前言
最近在开发 Google 订阅商品支付,也就是常见的包月VIP、包年VIP商品。之前写过一个 Google 支付一次性购买商品的设计方案,也就是单月VIP这种的,海外支付(GooglePay)服务端设计方案
前期工作
Google 订阅支付是依赖于实时开发者通知(Pub/Sub),需要开通 Pub/Sub功能:设置发布/订阅通知,需要注意的是,这个功能是收费的,需要绑定好银行卡。
使用Google订阅的场景里面应该主要就是处理消息产生的吞吐流量,这部分每月有10GiB的免费梯度,超出部分是40刀/TiB,所以当然一般免费梯度也够了。
还有一点需要注意,Google 内购商品需要在关联API-project之后创建,如果顺序反了,即使最后都配置好了,发送请求去Google验签也还是会报错:projectNotLinked
。如果你顺序搞反了,那你就再去创建一个内购商品就好了。
会员包月(周期扣款的续订商品)服务端表设计
对于这种支付会员包月的设计各有不同,我的设计就是两张表(苹果支付方案另外说)。
-
vip_order,会员订单表
CREATE TABLE `vip_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_sn` varchar(100) NOT NULL COMMENT '订单编号', `third_order_sn` varchar(100) DEFAULT NULL COMMENT '第三方订单编号', `origin_order_sn` varchar(100) DEFAULT NULL COMMENT '源订单号,发起退款时关联的订单', `type` tinyint(1) DEFAULT NULL COMMENT '订单类型 0 一次性购买 1 周期扣款订单', `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID', `goods_id` bigint(20) DEFAULT NULL COMMENT '商品id', `price` bigint(20) DEFAULT '0' COMMENT '订单金额', `distribution_channel` varchar(20) DEFAULT NULL COMMENT '分销渠道', `payment_method` varchar(50) DEFAULT NULL COMMENT '付款方式:0 Google pay ', `status` tinyint(1) DEFAULT NULL COMMENT '订单状态:0:初始化 1:已完成 2 已经取消 3 已退款', `deliver_status` tinyint(1) DEFAULT NULL COMMENT '发货状态:0:发货失败 1:发货成功', `complete_time` datetime DEFAULT NULL COMMENT '订单完成时间', `refund_time` datetime DEFAULT NULL COMMENT '退款时间', `pay_time` datetime DEFAULT NULL COMMENT '付款时间', `device_id` varchar(255) DEFAULT NULL COMMENT '设备ID', `ip` varchar(100) DEFAULT NULL COMMENT 'IP地址', `country` varchar(20) DEFAULT NULL COMMENT '国家', `origin_info` text COMMENT '第三方支付信息', `remark` varchar(200) DEFAULT NULL COMMENT '备注', `support_refund` tinyint(1) DEFAULT NULL COMMENT '是否支持退款', `refund_reason` varchar(200) DEFAULT NULL COMMENT '退款原因', `goods_info` text COMMENT '商品信息', `package_name` varchar(500) DEFAULT NULL COMMENT '包名', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), KEY `index_order_sn` (`order_sn`) USING BTREE, KEY `index_third_order_sn` (`third_order_sn`) USING BTREE, KEY `index_user_id` (`user_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='会员订单表';
-
vip_renewal_order,会员续订表
CREATE TABLE `vip_renewal_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_sn` varchar(100) NOT NULL COMMENT '订单编号', `latest_order_sn` varchar(100) NOT NULL COMMENT '上次订单号', `subscription_index` int(11) DEFAULT NULL COMMENT '扣款期数', `sign_no` varchar(255) DEFAULT NULL COMMENT '订阅号', `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID', `goods_id` bigint(20) DEFAULT NULL COMMENT '商品id', `goods_info` varchar(1000) DEFAULT NULL COMMENT '固化商品信息', `price` int(11) DEFAULT '0' COMMENT '订单金额,存储美分', `sign_channel` varchar(20) DEFAULT NULL COMMENT '签约渠道(支付渠道):google pay 、 paypal、payerMax', `sign_status` tinyint(1) DEFAULT NULL COMMENT '订阅状态,0-订阅处理中 1-订阅成功 2-订阅失败 3-订阅取消 4-订阅失效 5-订阅计划暂停', `sign_reason` varchar(100) DEFAULT NULL COMMENT '状态原因', `deduct_status` tinyint(1) DEFAULT NULL COMMENT '本期扣款状态: 0-待扣款 1-扣款成功 2-扣款失败 3-扣款取消 4-已忽略', `renewal_content` text COMMENT '第三方续订内容', `start_order_time` datetime DEFAULT NULL COMMENT '订单第一次订阅时间', `latest_order_time` datetime DEFAULT NULL COMMENT '上一次订单自动续约时间', `next_order_time` datetime DEFAULT NULL COMMENT '理论上下次扣款时间', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), KEY `index_order_sn` (`order_sn`) USING BTREE, KEY `index_latest_order_sn` (`latest_order_sn`) USING BTREE, KEY `index_user_id` (`user_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='会员自动续订表';
-
两张表关系,我现在的设计是,会员续订表只记录最新的续订情况,会员续订表可以关联到最新的订单,也就是说,一个用户一个签约号只有一条记录,只保存了最新的续订信息。
服务端验证签名流程
服务端流程主要分两块:创建订单验签流程、处理Google回调的续订流程
创建订单验签流程
流程很简单,就是首先本地签名验证,然后检查订单,根据订单是否续订商品分别调用Google的接口验证小票(使用Google SDK即可),然后就是续订商品创建两个订单(包括续订单子,续订单子可以看出目前用户的续订状态),最后发放会员。
Google 订阅相关API:developers.google.cn/android-pub…
- purchases.products 非订阅商品api
- purchases.subscriptions 订阅商品api
- purchases.voidedpurchases 退款api
代码
对于调用Google API 验证订单,可以直接调用 Google的API接口,但是需要自己获取 token 流程,如果嫌麻烦的话,也可以直接使用 Google 提供的SDK。
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v3-rev20211125-1.32.1</version>
</dependency>
主体业务逻辑代码:
@Transactional
public void verifyInapp(GooglePayVerifyRequest request) throws UserClientException {
// 渠道
String clientType = httpServletRequestHelper.getClientType();
Long userId = httpServletRequestHelper.getCurrentUserId();
String countryIsoCode = httpServletRequestHelper.getCountryIsoCode();
GooglePayVerifyRequest.SigntureData signtureData = request.getSigntureData();
// 本地签名验证
super.googleRSALocalVerifySignature(request, clientType, userId);
// 检查商品
MarketVipGoodsVo marketVipGoodsVo = commodityFeign.findMarketGoods2(signtureData.getProductId(), clientType, countryIsoCode).getData();
if(marketVipGoodsVo == null){
log.error("商品Code:{} ,ClientCodeType:{}, 国家码:{} 未能找到上架商品", signtureData.getProductId(), clientType, countryIsoCode);
throw new UserClientException(Constant.VipOrderExceptionConstant.GOODS_NOT_FOUND);
}
// 分布式锁
RLock lock = null;
try {
lock = redisUtils.lock(String.format(Constant.GOOGLE_PAY_VERIFY_LOCK, signtureData.getOrderId()));
// 检查 订单是否存在库里
VipOrder order = vipOrderRepository.findByThirdOrderSn(signtureData.getOrderId());
if (order == null) {
// 订单不存在 新事物 创建订单
order = vipOrderService.createOrderByGooglePay(request, marketVipGoodsVo);
} else if (order.checkHandleStatus()) {
// 检查订单状态
log.info("订单:{} 不是初始化状态,表示已经处理了" , JSON.toJSONString(order));
throw new OrderException(CommonErrorCode.create(OrderVerifyEnum.ORDER_HANDLED.getCode(),
OrderVerifyEnum.ORDER_HANDLED.getDesc()));
}
String originInfo;
// 续订商品,走 Google 订阅SDK获取订单
if(marketVipGoodsVo.isSubscribed()){
// 会员 订阅
SubscriptionPurchase subscriptionPurchase = subscriptionsGoodsCheck(signtureData.getPackageName(), signtureData.getProductId(), signtureData.getPurchaseToken());
log.info("Google API 校验结果:{}", subscriptionPurchase);
originInfo = subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase);
if (Constant.GooglePay.checkSubscriptionPurchase(subscriptionPurchase)) {
vipOrderService.updateOrderFail(order.getId(), originInfo);
// 订单未支付状态
log.info("Google API 校验订单:{} 不是支付完成状态,结果:{}" , order.getId(), originInfo);
throw new OrderException(CommonErrorCode.create(OrderVerifyEnum.ORDER_UN_PAID.getCode(),
OrderVerifyEnum.ORDER_UN_PAID.getDesc()));
}
// 获取到订单价格
order.setCountry(subscriptionPurchase.getCountryCode());
// 使用google 订阅的用户不会导致充值错了用户的BUG 修改用户ID
order.setUserId(Long.valueOf(subscriptionPurchase.getObfuscatedExternalAccountId()));
vipOrderRepository.save(order);
// 创建续订单
vipOrderService.createSubscribeOrder(order, subscriptionPurchase.getObfuscatedExternalProfileId(),
PayMethodEnum.generateVipOrderSn(PayMethodEnum.GOOGLE_PAY_PRIMORDIAL), RenewalSignStatusEnum.SUCCESS, RenewalSignChannelEnum.GOOGLE, JSON.toJSONString(subscriptionPurchase));
} else {
// 会员 一次性购买
Long orderId = order.getId();
originInfo = purchasesGoodsCheck(request, orderId, (info) -> vipOrderService.updateOrderFail(orderId, info));
}
// 更新订单数据
vipOrderService.updateOrderPaid(order.getId(), originInfo);
// 通知发放会员
boolean grantUserVipSuccess = vipOrderService.grantUserVip(order);
if(grantUserVipSuccess){
vipOrderService.updateOrderDeliverSuccess(order);
}
} finally {
if (lock != null) {
lock.unlock();
}
}
}
本地验证签名:
protected void googleRSALocalVerifySignature(GooglePayVerifyRequest request, String clientType, Long userId) {
GooglePayVerifyRequest.SigntureData signtureData = request.getSigntureData();
String publicKey = googlePublicKeyProperties.getPackageAndPublicKey().get(clientType);
log.info("clientType:{} ,userId:{}, 包名:{},公钥:{} 准备开始本地RSA校验",clientType,userId, signtureData.getPackageName(), publicKey);
if (!Constant.doCheck(request.getSigntureContent(), request.getSignture(), publicKey)) {
log.info("服务端RSA校验未通过,参数:{}" , request);
throw new OrderException(CommonErrorCode.create(OrderVerifyEnum.RSA_VERIFY_FAIL.getCode(),
OrderVerifyEnum.RSA_VERIFY_FAIL.getDesc()));
}
}
public static boolean doCheck(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.getDecoder().decode(publicKey);
PublicKey pubKey = keyFactory
.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(Base64.getDecoder().decode(sign));
} catch (Exception e) {
log.error("Google pay RSA 校验异常:{}", e);
}
return false;
}
会员订阅 Google SDK 验证订单:
private SubscriptionPurchase subscriptionsGoodsCheck(String packageName, String productId, String purchaseToken) {
SubscriptionPurchase purchaseSub;
try {
purchaseSub = androidPublisher.purchases()
.subscriptions().get(packageName, productId, purchaseToken).execute();
log.info("调用 GoogleSDK 获取订单数据,参数:{}, {}, {},返回结果:{}", packageName, productId, purchaseToken, JSON.toJSONString(purchaseSub));
} catch (Exception ex) {
log.error("调用GoogleSDK校验订单发生异常:{} ", ex);
throw new RuntimeException("调用GoogleSDK校验订单发生异常");
}
return purchaseSub;
}
一次性购买 Google SDK 校验订单:
protected String purchasesGoodsCheck(GooglePayVerifyRequest request, Long orderId, Consumer<String> consumer) {
String originInfo;
ProductPurchase productPurchase = null;
boolean googleServerError = false;
try {
GooglePayVerifyRequest.SigntureData signtureData = request.getSigntureData();
//校验订单 一次性商品
productPurchase = androidPublisher.purchases().products()
.get(signtureData.getPackageName(), signtureData.getProductId(), signtureData.getPurchaseToken()).execute();
originInfo = JSON.toJSONString(productPurchase);
log.info("调用 GoogleSDK 获取订单数据,参数:{},返回结果:{}", JSON.toJSONString(signtureData), originInfo);
} catch (Exception ex) {
log.error("调用GoogleSDK校验订单发生异常:{} , 忽略异常,因为Google本地RSA校验已经通过", ex);
originInfo = request.getSigntureContent();
googleServerError = true;
}
if (!googleServerError && (productPurchase == null || productPurchase.getPurchaseState() != 0)) {
consumer.accept(originInfo);
// 订单未支付状态
log.info("Google API 校验订单:{} 不是支付完成状态,结果:{}" , orderId, originInfo);
throw new OrderException(CommonErrorCode.create(OrderVerifyEnum.ORDER_UN_PAID.getCode(),
OrderVerifyEnum.ORDER_UN_PAID.getDesc()));
}
return originInfo;
}
上面代码是 Google 校验订单的业务逻辑,给个参考即可,具体还是要根据自己业务来处理。
处理Google回调的续订流程
回调数据大概长这样
{
"message": {
"data": "eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20uZGFybWl1LmRvcmFpbWkiLCJldmVudFRpbWVNaWxsaXMiOiIxNjczMTQ4Mjc0NDAyIiwic3Vic2NyaXB0aW9uTm90aWZpY2F0aW9uIjp7InZlcnNpb24iOiIxLjAiLCJub3RpZmljYXRpb25UeXBlIjoyLCJwdXJjaGFzZVRva2VuIjoiamxvbWNhamhkZWRrbGVoZGhpZm5naGRpLkFPLUoxT3gxcm5rVVBWMHJmZGI5QktYZ0ZnZlZFZFhjVmtLaElWc1RUMFEwQUpzUWhTR3hUQTl5YTl5dUNqc3VHRGdMQmYwbDNBaklYRUdITU5TdTd3OTN4R0N5V05tZ09RIiwic3Vic2NyaXB0aW9uSWQiOiJ2aXBfdGVzdF95ZWFyX3N1YnMifX0=",
"messageId": "6585558511031719",
"publishTime": "2023-01-08T03:24:34.623Z"
},
"subscription": "projects/pc-api-4971789543089929583-125/subscriptions/loklok-vip-subs-sub"
}
通过 Base64 解码后:
{
"eventTimeMillis": 1673148274402,
"packageName": "com.darmiu.doraimi",
"subscriptionNotification": {
"notificationType": 2,
"purchaseToken": "jlomcajhdedklehdhifnghdi.AO-J1Ox1rnkUPV0rfdb9BKXgFgfVEdXcVkKhIVsTT0Q0AJsQhSGxTA9ya9yuCjsuGDgLBf0l3AjIXEGHMNSu7w93xGCyWNmgOQ",
"subscriptionId": "vip_test_year_subs",
"version": "1.0"
},
"version": "1.0"
}
notificationType 表示通知类型,可以具有以下值:
(1) SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
(2) SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
(3) SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消,在用户取消时发送。
(4) SUBSCRIPTION_PURCHASED - 购买了新的订阅。
(5) SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态(如果已启用)。
(6) SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期(如果已启用)。
(7) SUBSCRIPTION_RESTARTED - 用户已通过 Play > 帐号 > 订阅恢复了订阅。订阅已取消,但在用户恢复时尚未到期。如需了解详情,请参阅 [恢复](/google/play/billing/subscriptions#restore)。
(8) SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
(9) SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
(10) SUBSCRIPTION_PAUSED - 订阅已暂停。
(11) SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
(12) SUBSCRIPTION_REVOKED - 用户在到期时间之前已撤消订阅。
(13) SUBSCRIPTION_EXPIRED - 订阅已到期。
很显然回调的数据可以看出续订的状态,但是不知道订单的状态,所以我们还需要通过回调的数据,packageName (包名), subscriptionId(订阅商品ID), purchaseToken(购买订阅时向用户设备提供的令牌)。通过 Google SDK 调用订阅相关API校验订单数据。
调用 Google SDK 获取数据大概长这样:
{
"acknowledgementState": 1,
"autoRenewing": true,
"countryCode": "ID",
"developerPayload": "",
"expiryTimeMillis": 1673150190345,
"kind": "androidpublisher#subscriptionPurchase",
"obfuscatedExternalAccountId": "6306074",
"obfuscatedExternalProfileId": "8e858fa068164b6583efc36ff44c4f1b",
"orderId": "GPA.3380-6685-4071-88443..0",
"paymentState": 1,
"priceAmountMicros": 299000000000,
"priceCurrencyCode": "IDR",
"purchaseType": 0,
"startTimeMillis": 1673146472411
}
具体字段解释的文档:developers.google.cn/android-pub… 通过上面的数据以及文档上的字段,我发现没有一个能表示续订号的字段,也就是说,我通过这个回调数据,没办法找到 vip_renewal_order 表里是哪条数据。
所以和客户端商量决定用 obfuscatedExternalProfileId 字段表示订阅号,客户端在发起创建订阅订单是创建。
具体代码参考:
处理Google回调:
public void subscribeCallback(GoogleSubscribeCallback callback) throws RequestParameterException {
GoogleSubscribeCallback.Message message = callback.getMessage();
Base64.Decoder decoder = Base64.getDecoder();
try {
// Base64 解码 data
String dataDecodeStr = new String(decoder.decode(message.getData()), "UTF-8");
GoogleSubscribeCallback.DataDecode dataDecode = JSON.parseObject(dataDecodeStr, GoogleSubscribeCallback.DataDecode.class);
log.info("google subscribe 解析回调数据:{}", JSON.toJSONString(dataDecode));
GoogleSubscribeCallback.SubscriptionNotification notification = dataDecode.getSubscriptionNotification();
// 调用 Google SDK 获取订阅结果
SubscriptionPurchase subscriptionPurchase = subscriptionsGoodsCheck(dataDecode.getPackageName(), notification.getSubscriptionId(), notification.getPurchaseToken());
if(dataDecode.getSubscriptionNotification().newSubscription()){
log.info("google 支付收到新的订阅,packageName :{}, productId:{}, purchaseToken:{},结果:{}",
dataDecode.getPackageName(), notification.getSubscriptionId(),
notification.getPurchaseToken(), subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase));
subscriptionDeductionSucceeded(subscriptionPurchase, dataDecode);
} else if(dataDecode.getSubscriptionNotification().subscriptionExpired()){
log.info("google 订阅过期,packageName :{}, productId:{}, purchaseToken:{},结果:{}",
dataDecode.getPackageName(), notification.getSubscriptionId(),
notification.getPurchaseToken(), subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase));
// 订阅到期
googleNoSubscription(subscriptionPurchase, RenewalSignStatusEnum.INVALID);
} else if(dataDecode.getSubscriptionNotification().subscriptionCanceled()){
log.info("google 取消订阅,packageName :{}, productId:{}, purchaseToken:{},结果:{}",
dataDecode.getPackageName(), notification.getSubscriptionId(),
notification.getPurchaseToken(), subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase));
// 取消订阅
googleNoSubscription(subscriptionPurchase, RenewalSignStatusEnum.CANCEL);
} else if(dataDecode.getSubscriptionNotification().subscriptionRevoked()){
log.info("google 用户在到期时间之前已撤消订阅,packageName :{}, productId:{}, purchaseToken:{},结果:{}",
dataDecode.getPackageName(), notification.getSubscriptionId(),
notification.getPurchaseToken(), subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase));
// 取消订阅
googleNoSubscription(subscriptionPurchase, RenewalSignStatusEnum.CANCEL);
} else if(dataDecode.getSubscriptionNotification().subscriptionPaused()){
log.info("google 订阅已暂停,packageName :{}, productId:{}, purchaseToken:{},结果:{}",
dataDecode.getPackageName(), notification.getSubscriptionId(),
notification.getPurchaseToken(), subscriptionPurchase == null ? null : JSON.toJSONString(subscriptionPurchase));
// 暂停订阅
subscriptionPurchase.setCancelReason(RenewalSignStatusEnum.SUSPEND.getCode());
googleNoSubscription(subscriptionPurchase, RenewalSignStatusEnum.SUSPEND);
}
} catch (UnsupportedEncodingException e) {
throw new RequestParameterException("订阅回调参数有问题");
}
}
处理订阅成功回调:
/**google 订阅回调通过订阅号
* 订阅自动扣款
* @param subscriptionPurchase
*/
private void subscriptionDeductionSucceeded(SubscriptionPurchase subscriptionPurchase, GoogleSubscribeCallback.DataDecode dataDecode ) {
if(Constant.GooglePay.checkSubscriptionPurchase(subscriptionPurchase)){
// 校验失败
log.info("Google 回调校验订单失败,结果:{}", subscriptionPurchase);
return;
}
VipOrder vipOrder = vipOrderRepository.findByThirdOrderSn(subscriptionPurchase.getOrderId());
if(vipOrder != null){
// 可能是第一次订阅 ,订单已经生成
log.info("google 订阅回调订单:{} 已经生成,不需要再次处理", vipOrder.getId());
return;
}
// 获取续订
VipRenewalOrder vipRenewalOrder = renewalOrderRepository.findBySignNoAndSignChannel(subscriptionPurchase.getObfuscatedExternalProfileId(), RenewalSignChannelEnum.GOOGLE.getCode());
if(vipRenewalOrder == null){
// 续订单不存在
log.info("google 订阅回调通过订阅号:{} 发现续订订单不存在", subscriptionPurchase.getObfuscatedExternalProfileId());
return;
}
// 找到自动续费上一个单子
VipOrder latestOrder = vipOrderRepository.findByOrderSn(vipRenewalOrder.getLatestOrderSn());
MarketVipGoodsVo marketVipGoodsVo = JSON.parseObject(vipRenewalOrder.getGoodsInfo(), MarketVipGoodsVo.class);
// 创建一个新的订单
VipOrder newOrder = vipOrderService.createOrderByGooglePayCallBack(dataDecode.getPackageName(), PayMethodEnum.GOOGLE_PAY_PRIMORDIAL.getCode(),
marketVipGoodsVo, latestOrder, subscriptionPurchase);
// 修改续订
if(!RenewalSignStatusEnum.SUCCESS.getCode().equals(vipRenewalOrder.getSignStatus())){
vipRenewalOrder.setSignStatus(RenewalSignStatusEnum.SUCCESS.getCode());
vipRenewalOrder.setStatusReason(null);
}
vipRenewalOrder.setLatestOrderSn(newOrder.getOrderSn());
vipRenewalOrder.setLatestOrderTime(newOrder.getCreateTime());
vipRenewalOrder.setDeductStatus(DeductStatusEnum.DEDUCTED_SUCCESS.getCode());
vipRenewalOrder.setRenewalContent(JSON.toJSONString(subscriptionPurchase));
vipRenewalOrder.setSubscriptionIndex(Optional.ofNullable(vipRenewalOrder.getSubscriptionIndex()).orElse(0) + 1);
renewalOrderRepository.save(vipRenewalOrder);
// 消耗订单
acknowledgeGoogleOrder(subscriptionPurchase, dataDecode);
// 通知发放会员
boolean grantUserVipSuccess = vipOrderService.grantUserVip(newOrder);
if(grantUserVipSuccess){
vipOrderService.updateOrderDeliverSuccess(newOrder);
}
}
处理用户不再订阅的逻辑:
private void googleNoSubscription(SubscriptionPurchase subscriptionPurchase, RenewalSignStatusEnum signStatusEnum) {
if(subscriptionPurchase != null){
VipRenewalOrder vipRenewalOrder = renewalOrderRepository.findBySignNoAndSignChannel(subscriptionPurchase.getObfuscatedExternalProfileId(), RenewalSignChannelEnum.GOOGLE.getCode());
if(vipRenewalOrder == null){
// 续订单不存在
log.error("google 订阅回调通过订阅号:{} 发现续订订单不存在", subscriptionPurchase.getObfuscatedExternalProfileId());
return;
}
vipRenewalOrder.setSignStatus(signStatusEnum.getCode());
vipRenewalOrder.setStatusReason(GoogleSubscribeCancelReasonEnum.getCancelReason(subscriptionPurchase.getCancelReason()));
vipRenewalOrder.setRenewalContent(JSON.toJSONString(subscriptionPurchase));
renewalOrderRepository.save(vipRenewalOrder);
}
}