feat(googleplay): 新增购买成功记录服务并注入使用

This commit is contained in:
2026-03-19 08:53:22 +08:00
parent 0555f1d0df
commit 83cb65a31f
3 changed files with 139 additions and 2 deletions

View File

@@ -0,0 +1,137 @@
package com.yolo.keyborad.googleplay;
import com.yolo.keyborad.googleplay.model.GooglePlayPurchaseSnapshot;
import com.yolo.keyborad.model.entity.KeyboardProductItems;
import com.yolo.keyborad.model.entity.KeyboardUserPurchaseRecords;
import com.yolo.keyborad.model.entity.googleplay.GooglePlayOrder;
import com.yolo.keyborad.model.entity.googleplay.GooglePlayUserEntitlement;
import com.yolo.keyborad.service.KeyboardUserPurchaseRecordsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Objects;
@Component
@RequiredArgsConstructor
public class GooglePlayPurchaseRecordService {
private static final String PURCHASE_STATUS_PAID = "PAID";
private final KeyboardUserPurchaseRecordsService purchaseRecordsService;
public void recordSuccess(Long userId,
KeyboardProductItems product,
GooglePlayPurchaseSnapshot snapshot,
GooglePlayOrder order,
GooglePlayUserEntitlement entitlement) {
if (!shouldRecord(userId, order, entitlement)) {
return;
}
String transactionId = resolveTransactionId(order);
if (alreadyRecorded(transactionId)) {
return;
}
purchaseRecordsService.save(buildRecord(userId, product, snapshot, order, transactionId));
}
private boolean shouldRecord(Long userId,
GooglePlayOrder order,
GooglePlayUserEntitlement entitlement) {
return userId != null
&& order != null
&& entitlement != null
&& Boolean.TRUE.equals(entitlement.getActive())
&& !GooglePlayConstants.DELIVERY_REVOKED.equals(order.getDeliveryStatus())
&& !GooglePlayConstants.DELIVERY_MANUAL_REVIEW.equals(order.getDeliveryStatus());
}
private boolean alreadyRecorded(String transactionId) {
return purchaseRecordsService.lambdaQuery()
.eq(KeyboardUserPurchaseRecords::getTransactionId, transactionId)
.eq(KeyboardUserPurchaseRecords::getPaymentMethod, GooglePlayConstants.PAYMENT_METHOD_GOOGLE_PLAY)
.exists();
}
private KeyboardUserPurchaseRecords buildRecord(Long userId,
KeyboardProductItems product,
GooglePlayPurchaseSnapshot snapshot,
GooglePlayOrder order,
String transactionId) {
KeyboardUserPurchaseRecords record = new KeyboardUserPurchaseRecords();
record.setUserId(Math.toIntExact(userId));
record.setProductId(product.getProductId());
record.setPurchaseQuantity(resolvePurchaseQuantity(product, snapshot, order));
record.setPrice(product.getPrice());
record.setCurrency(product.getCurrency());
record.setPurchaseType(resolvePurchaseType(product, snapshot));
Date purchaseTime = resolvePurchaseTime(snapshot, order);
record.setPurchaseTime(purchaseTime);
record.setStatus(PURCHASE_STATUS_PAID);
record.setPaymentMethod(GooglePlayConstants.PAYMENT_METHOD_GOOGLE_PLAY);
record.setTransactionId(transactionId);
record.setOriginalTransactionId(order.getPurchaseToken());
record.setProductIds(new String[]{product.getProductId()});
record.setPurchaseDate(purchaseTime);
record.setExpiresDate(snapshot.getExpiryTime());
return record;
}
private Integer resolvePurchaseQuantity(KeyboardProductItems product,
GooglePlayPurchaseSnapshot snapshot,
GooglePlayOrder order) {
Integer configured = product.getDurationValue();
if (configured != null) {
return configured;
}
Integer parsed = parseInteger(product.getName());
if (parsed != null) {
return parsed;
}
if (snapshot.getQuantity() != null) {
return snapshot.getQuantity();
}
return Objects.requireNonNullElse(order.getQuantity(), 1);
}
private Integer parseInteger(String raw) {
if (raw == null || raw.isBlank()) {
return null;
}
String digits = raw.replaceAll("[^\\d]", "");
if (digits.isBlank()) {
return null;
}
return Integer.parseInt(digits);
}
private String resolvePurchaseType(KeyboardProductItems product, GooglePlayPurchaseSnapshot snapshot) {
if (product.getType() != null && !product.getType().isBlank()) {
return product.getType();
}
if (GooglePlayConstants.PRODUCT_TYPE_SUBSCRIPTION.equals(snapshot.getProductType())) {
return "subscription";
}
return "in-app-purchase";
}
private Date resolvePurchaseTime(GooglePlayPurchaseSnapshot snapshot, GooglePlayOrder order) {
if (snapshot.getStartTime() != null) {
return snapshot.getStartTime();
}
if (order.getLastEventTime() != null) {
return order.getLastEventTime();
}
if (snapshot.getLastSyncedAt() != null) {
return snapshot.getLastSyncedAt();
}
return new Date();
}
private String resolveTransactionId(GooglePlayOrder order) {
if (order.getGoogleOrderId() != null && !order.getGoogleOrderId().isBlank()) {
return order.getGoogleOrderId();
}
return order.getOrderKey();
}
}

View File

@@ -28,6 +28,7 @@ public class GooglePlayStateService {
private final GooglePlayPurchaseTokenMapper purchaseTokenMapper; private final GooglePlayPurchaseTokenMapper purchaseTokenMapper;
private final KeyboardProductItemsService productItemsService; private final KeyboardProductItemsService productItemsService;
private final GooglePlayEntitlementApplier entitlementApplier; private final GooglePlayEntitlementApplier entitlementApplier;
private final GooglePlayPurchaseRecordService purchaseRecordService;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public GooglePlaySyncResult sync(GooglePlaySyncCommand command, GooglePlayPurchaseSnapshot snapshot) { public GooglePlaySyncResult sync(GooglePlaySyncCommand command, GooglePlayPurchaseSnapshot snapshot) {
@@ -37,6 +38,7 @@ public class GooglePlayStateService {
GooglePlayUserEntitlement entitlement = null; GooglePlayUserEntitlement entitlement = null;
if (command.getUserId() != null) { if (command.getUserId() != null) {
entitlement = entitlementApplier.apply(command.getUserId(), product, snapshot, order); entitlement = entitlementApplier.apply(command.getUserId(), product, snapshot, order);
purchaseRecordService.recordSuccess(command.getUserId(), product, snapshot, order, entitlement);
} }
saveOrder(order); saveOrder(order);
token.setLatestOrderKey(order.getOrderKey()); token.setLatestOrderKey(order.getOrderKey());

View File

@@ -8,6 +8,4 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface KeyboardUserPurchaseRecordsService extends IService<KeyboardUserPurchaseRecords>{ public interface KeyboardUserPurchaseRecordsService extends IService<KeyboardUserPurchaseRecords>{
} }