Browse Source

Merge branch 'develop/v1.0' into master-test

tangxiangan 3 months ago
parent
commit
b10b49b767
20 changed files with 73 additions and 59 deletions
  1. 1 0
      pdf-office-common/src/main/java/cn/kdan/cloud/pdf/office/common/enums/ExceptionEnum.java
  2. 2 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/GooglePayClient.java
  3. 1 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/controller/OrderController.java
  4. 2 2
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/AppStoreWebhookService.java
  5. 1 4
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/GooglePayService.java
  6. 2 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/WebhookService.java
  7. 2 2
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreServiceImpl.java
  8. 3 6
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreWebhookServiceImpl.java
  9. 9 13
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/GooglePayServiceImpl.java
  10. 6 6
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/OrderServiceImpl.java
  11. 1 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PaddleWebhookServiceImpl.java
  12. 3 2
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayCenterWebhookServiceImpl.java
  13. 1 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayPalWebhookServiceImpl.java
  14. 8 2
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/WebhookServiceImpl.java
  15. 2 3
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/utils/CommonUtils.java
  16. 1 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/AppStoreWebhookMonitor.java
  17. 8 7
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/GoogleWebhookMonitor.java
  18. 2 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/appstore/notification/NotificationType.java
  19. 9 1
      pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/controller/GoogleController.java
  20. 9 4
      pdf-office-product/src/main/java/cn/kdan/cloud/pdf/office/product/service/impl/ProductServiceImpl.java

+ 1 - 0
pdf-office-common/src/main/java/cn/kdan/cloud/pdf/office/common/enums/ExceptionEnum.java

@@ -99,6 +99,7 @@ public enum ExceptionEnum {
     EXCEPTION_USER_ALREADY_LOTTERY(364, "用户已经抽过奖啦!"),
     EXCEPTION_PRODUCT_TYPE_ERROR(365, "产品类型错误"),
     EXCEPTION_USER_ALREADY_SUBSCRIBED(366, "您已经是订阅会员,无需重复订阅"),
+    EXCEPTION_TEST_BUY(367, "测试订单"),
     ;
     private final Integer value;
     private final String msg;

+ 2 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/GooglePayClient.java

@@ -145,7 +145,8 @@ public class GooglePayClient {
 //        testID();
         RestTemplate restTemplate = new RestTemplate();
         String url = "https://backend.pdfreaderpro.com/system/google/getSubscriptionGoogleOrderV2" +
-                "?packageName=" + "com.pdftechnologies.pdfreaderpro" + "&purchaseToken=" + "addcgghjnngggjcmcciogdmc.AO-J1OwbnlU9brbdzMiRUTGYOyDJbdmPl1AaJWaIjqyYhTFQXkMlw2qdwTUsvNRNSf45PANqkhVghwYUdT8viJ8wfbMeILsj6S6BHLEtU4WKKH0GossQJrc";
+                "?packageName=" + "com.pdftechnologies.pdfreaderpro" + "&purchaseToken="
+                + "opajmgohldedlcaneafhjibe.AO-J1OxaTTocxdvDeUROv4lNFQXdw7hz9S2EfVkeQZBed4D6IUBmX9elKLQ04_2BbBE0vgaZulHWa2ZtTswBN-UDsFZVrL2EMJknSJUnraA_mPsGrD3Y8sQ";
 
         // 设置请求头
         HttpHeaders headers = new HttpHeaders();

+ 1 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/controller/OrderController.java

@@ -133,7 +133,7 @@ public class OrderController {
                     // 上锁
                     boolean resultLock = rLock.tryLock(30, 10, TimeUnit.SECONDS);
                     if (resultLock) {
-                        googlePayService.subscriptionPaymentSucceeded(false, subscriptionGoogleOrderV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId(), subscriptionGoogleOrderV2.getLatestOrderId(), 2);
+                        googlePayService.subscriptionPaymentSucceeded(false, subscriptionGoogleOrderV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId(), subscriptionGoogleOrderV2.getLatestOrderId(), 2, subscriptionGoogleOrderV2);
                     }
                 } catch (InterruptedException e) {
 

+ 2 - 2
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/AppStoreWebhookService.java

@@ -1,6 +1,6 @@
 package cn.kdan.cloud.pdf.office.payment.service;
 
-import cn.kdan.cloud.pdf.office.api.payment.dto.PaddleWebhookDTO;
+import cn.kdan.cloud.pdf.office.payment.webhook.appstore.notification.JWSTransactionDecodedPayload;
 
 /**
  * @author ComPDFKit-WPH 2023/1/30
@@ -13,7 +13,7 @@ public interface AppStoreWebhookService {
      * 订阅已自动续期
      *
      */
-    void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo,String thirdOrderId,Integer payTime);
+    void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime, JWSTransactionDecodedPayload jwsTransactionDecodedPayload);
 
     /**
      * 订阅取消

+ 1 - 4
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/GooglePayService.java

@@ -1,11 +1,8 @@
 package cn.kdan.cloud.pdf.office.payment.service;
 
-import cn.kdan.cloud.pdf.office.api.payment.dto.AppStoreOrderSucceedDTO;
-import cn.kdan.cloud.pdf.office.api.payment.dto.EquityVerificationDTO;
 import cn.kdan.cloud.pdf.office.api.payment.dto.GooglePayDTO;
 import cn.kdan.cloud.pdf.office.common.vo.UserInfoVO;
 import cn.kdan.cloud.pdf.office.payment.webhook.google.SubscriptionPurchaseV3;
-import com.google.api.services.androidpublisher.model.SubscriptionPurchaseV2;
 
 /**
  * @author ComPDFKit-WPH 2023/6/29
@@ -23,7 +20,7 @@ public interface GooglePayService {
 
     SubscriptionPurchaseV3 verify(String purchaseToken, String packageName);
 
-    void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime);
+    void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime, SubscriptionPurchaseV3 subscriptionGoogleOrderV2);
 
     void subscriptionCancel(String thirdSubscriptionId);
 }

+ 2 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/WebhookService.java

@@ -16,8 +16,9 @@ public interface WebhookService {
      * @param thirdOrderId   第三方订单id
      * @param orderByTradeNo 订阅的前一笔订单对象(用于设置新订单的一些相同参数)
      * @param payTime
+     * @param result
      */
-    void handleSubsequentAutomaticDeduction(BigDecimal price, String thirdTradeNo, String thirdOrderId, OrdersVO orderByTradeNo, Integer payTime);
+    void handleSubsequentAutomaticDeduction(BigDecimal price, String thirdTradeNo, String thirdOrderId, OrdersVO orderByTradeNo, Integer payTime, String result);
 
     /**
      * 查询订单详情(用于判断订阅是否已经支付完成)

+ 2 - 2
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreServiceImpl.java

@@ -104,7 +104,7 @@ public class AppStoreServiceImpl implements AppStoreService {
             CreateSubscriptionDTO createSubscription = new CreateSubscriptionDTO();
             ProductVO product = productApi.getProductByCode(equityVerificationDTO.getProductCode()).getResult();
             String subscriptionId = CommonUtils.generateId();
-            String orderId = CommonUtils.generateId();
+            String orderId = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
             String appId = product.getAppId();
             createSubscription.setId(subscriptionId);
             createSubscription.setUserId(equityVerificationDTO.getUserId());
@@ -127,7 +127,7 @@ public class AppStoreServiceImpl implements AppStoreService {
             CreateOrderManualDTO orderManualDTO = CreateOrderManualDTO.builder()
                     .thirdTradeNo(originalTransactionId)
                     .thirdOrderNo(transactionId)
-                    .price(currency.equals("cny")?product.getCnyPrice():product.getPrice())
+                    .price(price)
                     .reducedPrice(price)
                     .subscriptionId(subscriptionId)
                     .userId(equityVerificationDTO.getUserId())

+ 3 - 6
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreWebhookServiceImpl.java

@@ -1,13 +1,10 @@
 package cn.kdan.cloud.pdf.office.payment.service.impl;
 
-import cn.kdan.cloud.pdf.office.api.account.feign.UserApi;
 import cn.kdan.cloud.pdf.office.api.payment.constant.OrderConstant;
-import cn.kdan.cloud.pdf.office.api.payment.dto.PaddleWebhookDTO;
 import cn.kdan.cloud.pdf.office.api.payment.vo.OrdersVO;
 import cn.kdan.cloud.pdf.office.api.product.vo.ProductVO;
-import cn.kdan.cloud.pdf.office.payment.entity.RestorePurchaseLogs;
-import cn.kdan.cloud.pdf.office.payment.properties.AppStoreProperties;
 import cn.kdan.cloud.pdf.office.payment.service.*;
+import cn.kdan.cloud.pdf.office.payment.webhook.appstore.notification.JWSTransactionDecodedPayload;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
@@ -30,7 +27,7 @@ public class AppStoreWebhookServiceImpl implements AppStoreWebhookService {
     private final WebhookService webhookService;
 
     @Override
-    public void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo,String thirdOrderId,Integer payTime) {
+    public void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime, JWSTransactionDecodedPayload jwsTransactionDecodedPayload) {
         log.info("appstore 订阅的支付订单已成功 appstore订单id:{}", thirdOrderId);
         OrdersVO ordersVO = ordersService.getOrderByThirdOrderNo(thirdOrderId);
         //如果处理过
@@ -51,7 +48,7 @@ public class AppStoreWebhookServiceImpl implements AppStoreWebhookService {
         }else{
             price = productVO.getCnyPrice();
         }
-        webhookService.handleSubsequentAutomaticDeduction(price, thirdTradeNo, thirdOrderId,ordersVONew,payTime);
+        webhookService.handleSubsequentAutomaticDeduction(price, thirdTradeNo, thirdOrderId,ordersVONew,payTime, jwsTransactionDecodedPayload.toString());
     }
 
     @Override

+ 9 - 13
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/GooglePayServiceImpl.java

@@ -20,9 +20,9 @@ import cn.kdan.cloud.pdf.office.common.utils.MyDateUtils;
 import cn.kdan.cloud.pdf.office.common.vo.UserInfoVO;
 import cn.kdan.cloud.pdf.office.common.vo.UserVO;
 import cn.kdan.cloud.pdf.office.payment.client.GooglePayClient;
+import cn.kdan.cloud.pdf.office.payment.properties.GooglePayConfig;
 import cn.kdan.cloud.pdf.office.payment.service.GooglePayService;
 import cn.kdan.cloud.pdf.office.payment.service.OrderService;
-import cn.kdan.cloud.pdf.office.payment.service.RestorePurchaseLogsService;
 import cn.kdan.cloud.pdf.office.payment.service.SubscriptionsService;
 import cn.kdan.cloud.pdf.office.payment.utils.TemplatesUtil;
 import cn.kdan.cloud.pdf.office.payment.webhook.google.SubscriptionPurchaseLineItemMS;
@@ -30,14 +30,10 @@ import cn.kdan.cloud.pdf.office.payment.webhook.google.SubscriptionPurchaseV3;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
-import com.google.api.services.androidpublisher.model.SubscriptionPurchaseLineItem;
-import com.google.api.services.androidpublisher.model.SubscriptionPurchaseV2;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
+import org.springframework.http.*;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.LinkedMultiValueMap;
@@ -49,9 +45,6 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -81,6 +74,7 @@ public class GooglePayServiceImpl implements GooglePayService {
 
     private final EmailApi emailApi;
     private static final RestTemplate restTemplate = new RestTemplate();
+    private final GooglePayConfig googlePayConfig;
     @Value("${htmlToPdfUrl:http://139.196.160.101:3060/api/get-invoice}")
     private String htmlToPdfUrl;
 
@@ -96,6 +90,9 @@ public class GooglePayServiceImpl implements GooglePayService {
         }
         log.info("谷歌权益校验,用户id:{}", googlePayDTO.getUserId());
         SubscriptionPurchaseV3 subscriptionPurchaseV2 = this.verify(googlePayDTO.getPurchaseToken(),googlePayDTO.getPackageName());
+        if (subscriptionPurchaseV2.getTestPurchase() != null) {
+            throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
+        }
         // 获取票据订单信息
         if(ObjectUtils.isEmpty(subscriptionPurchaseV2.getExternalAccountIdentifiers())){
             throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_MSG_GOOGLE_STORE_TRANSACTION_ID_VALIDATION_FAILED);
@@ -123,7 +120,7 @@ public class GooglePayServiceImpl implements GooglePayService {
 
         CreateSubscriptionDTO createSubscription = new CreateSubscriptionDTO();
         String subscriptionId = CommonUtils.generateId();
-        String orderId = CommonUtils.generateId();
+        String orderId = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
         String appId = product.getAppId().toString();
         createSubscription.setId(subscriptionId);
         createSubscription.setUserId(googlePayDTO.getUserId());
@@ -170,7 +167,6 @@ public class GooglePayServiceImpl implements GooglePayService {
         result.setDigestPassword(null);
         return result;
     }
-
     private void sendBuyEmail(ProductVO product, UserVO userVO,CreateOrderManualDTO orderManualDTO) {
         if(product.getCode().contains("upgrade")){
             EmailSendBO bo = new EmailSendBO();
@@ -289,7 +285,7 @@ public class GooglePayServiceImpl implements GooglePayService {
     }
 
     @Override
-    public void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime) {
+    public void subscriptionPaymentSucceeded(Boolean isDiscount, String thirdTradeNo, String thirdOrderId, Integer payTime, SubscriptionPurchaseV3 subscriptionGoogleOrderV2) {
         log.info("谷歌 订阅的续费订单已成功 谷歌订单id:{},订阅id{}", thirdOrderId,thirdTradeNo);
         OrdersVO ordersVO = orderService.getOrderByThirdOrderNo(thirdOrderId);
         //如果订单处理过直接返回
@@ -304,7 +300,7 @@ public class GooglePayServiceImpl implements GooglePayService {
         OrdersVO ordersVONew = orderByTradeNo.get(0);
         ProductVO productVO = orderService.getProduct(ordersVONew.getProductId());
 
-        webhookService.handleSubsequentAutomaticDeduction(productVO.getPrice(), thirdTradeNo, thirdOrderId,ordersVONew, 1);
+        webhookService.handleSubsequentAutomaticDeduction(productVO.getPrice(), thirdTradeNo, thirdOrderId,ordersVONew, 1, subscriptionGoogleOrderV2.toString());
     }
 
     @Override

+ 6 - 6
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/OrderServiceImpl.java

@@ -197,7 +197,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
 
     @Override
     @Transactional
-    @Cacheable(value = RedisKeyConstant.CACHE_PAYMENT_CREAT_ORDER + "#24#h",
+    @Cacheable(value = RedisKeyConstant.CACHE_PAYMENT_CREAT_ORDER + "#2#h",
             key = "T(String).valueOf(#createUserOrderDTO.userId)" +
                     ".concat('-').concat(#createUserOrderDTO.productId)" +
                     ".concat('-').concat(#createUserOrderDTO.paymentMethod)" +
@@ -220,7 +220,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         }
         // 创建order
         Order order = new Order();
-        String readeNo = CommonUtils.generateRightsId((long) ((Math.random() * 9 + 1) * 1000));
+        String readeNo = CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
         order.setTradeNo(readeNo);
         // 记录原价和实际付款价
         if (createUserOrderDTO.getPaymentMethod().equals(PaymentMethodEnum.PAYPAL.getValue()) || createUserOrderDTO.getPaymentMethod().equals(PaymentMethodEnum.PADDLE.getValue())) {
@@ -319,7 +319,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
                         RabbitMqConstant.PAYMENT_ORDER_ROUTING_KEY,
                         order.getId(),
                         (msg -> {
-                            msg.getMessageProperties().setHeader("x-delay", (24 * 60 * 60 * 1000) + "");
+                            msg.getMessageProperties().setHeader("x-delay", (2 * 60 * 60 * 1000) + "");
                             return msg;
                         }));
                 Map<String, String> result = new HashMap<>();
@@ -337,7 +337,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
 
     @Override
     @Transactional
-    @Cacheable(value = RedisKeyConstant.CACHE_PAYMENT_CREAT_ORDER + "#24#h",
+    @Cacheable(value = RedisKeyConstant.CACHE_PAYMENT_CREAT_ORDER + "#2#h",
             key = "T(String).valueOf(#createUserOrderDTO.userId)" +
                     ".concat('-').concat(#createUserOrderDTO.productId)" +
                     ".concat('-').concat(#createUserOrderDTO.paymentMethod)" +
@@ -360,7 +360,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         }
         // 创建order
         Order order = new Order();
-        String readeNo = CommonUtils.generateRightsId((long) ((Math.random() * 9 + 1) * 1000));
+        String readeNo = CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
         order.setTradeNo(readeNo);
         // 订阅目前只支持美元
         order.setPrice(productVO.getPrice());
@@ -477,7 +477,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
                         RabbitMqConstant.PAYMENT_ORDER_ROUTING_KEY,
                         order.getId(),
                         (msg -> {
-                            msg.getMessageProperties().setHeader("x-delay", (24 * 60 * 60 * 1000) + "");
+                            msg.getMessageProperties().setHeader("x-delay", (2 * 60 * 60 * 1000) + "");
                             return msg;
                         }));
                 Map<String, String> result = new HashMap<>();

+ 1 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PaddleWebhookServiceImpl.java

@@ -47,7 +47,7 @@ public class PaddleWebhookServiceImpl implements PaddleWebhookService {
             }
             //paddle第一次使用get Passthrough paddleWebhookDTO.getSubscriptionId()
             webhookService.handleSubsequentAutomaticDeduction(paddleWebhookDTO.getBalanceGross(),
-                    paddleWebhookDTO.getSubscriptionId(), paddleWebhookDTO.getOrderId(), ordersVOS.get(0), 1);
+                    paddleWebhookDTO.getSubscriptionId(), paddleWebhookDTO.getOrderId(), ordersVOS.get(0), 1, null);
         }
     }
 

+ 3 - 2
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayCenterWebhookServiceImpl.java

@@ -312,17 +312,18 @@ public class PayCenterWebhookServiceImpl implements PayCenterWebhookService {
                                 userSubscriptionInfo.setPoint(Integer.valueOf(productVO.getPoints()));
                                 if(productVO.getCode().contains("trail")){
                                     userVO.setCanAccessAi("0");
+                                    userApi.updateUser(userVO);
                                 }
                             } else {
                                 userVO.setAccountType(AccountTypeEnum.PAID_ACCOUNT.value());
+                                userApi.updateUser(userVO);
                             }
-                            userApi.updateUser(userVO);
                             userSubscriptionInfoApi.insert(userSubscriptionInfo);
                             emailFlag = true;
                         }
                     }
                     //删除缓存中的订单
-                    ordersService.deleteTheCacheInTheCacheManager(ordersVO.getUserId() + "-" + ordersVO.getProductId() + "-" + ordersVO.getPayment());
+                    ordersService.deleteTheCacheInTheCacheManager(ordersVO.getUserId() + "-" + ordersVO.getProductId() + "-" + ordersVO.getPayment() + "-" + ordersVO.getPayNumber());
                     // 关闭用户同类型订单
                     ordersService.closeOrderByUser(ordersVO.getUserId(), productVO.getPlatform());
                     if (emailFlag) {

+ 1 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayPalWebhookServiceImpl.java

@@ -55,7 +55,7 @@ public class PayPalWebhookServiceImpl implements PayPalWebhookService {
             }
             OrdersVO orderByTradeNo = ordersVOS.get(0);
             webhookService.handleSubsequentAutomaticDeduction(price, thirdTradeNo,
-                    thirdOrderId, orderByTradeNo, null);
+                    thirdOrderId, orderByTradeNo, null, null);
         }
     }
 

+ 8 - 2
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/WebhookServiceImpl.java

@@ -99,16 +99,22 @@ public class WebhookServiceImpl implements WebhookService {
     private final PaddleClient paddleClient;
 
     @Override
-    public void handleSubsequentAutomaticDeduction(BigDecimal price, String thirdTradeNo, String thirdOrderId, OrdersVO orderByTradeNo, Integer payTime) {
+    public void handleSubsequentAutomaticDeduction(BigDecimal price, String thirdTradeNo, String thirdOrderId, OrdersVO orderByTradeNo, Integer payTime, String result) {
         log.info("自动订阅业务处理开始(非首期)订单id:{}", thirdOrderId);
         String subId = CommonUtils.generateId();
-        String orderId = CommonUtils.generateId();
+        String orderId = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));;
         // 创建新订单
         CreateOrderManualDTO createOrderManual = new CreateOrderManualDTO();
         BeanUtils.copyProperties(orderByTradeNo, createOrderManual);
         createOrderManual.setPaymentMethod(PaymentMethodEnum.fromValue(orderByTradeNo.getPayment()));
         // 设置实际扣费价格
         createOrderManual.setPrice(price);
+        if(!StringUtils.isEmpty(orderByTradeNo.getCurrency())){
+            createOrderManual.setCurrency(orderByTradeNo.getCurrency());
+        }
+        if(!StringUtils.isEmpty(result)){
+            createOrderManual.setResult(result);
+        }
         // 设置第三方passthrough
         createOrderManual.setThirdTradeNo(orderByTradeNo.getThirdTradeNo());
         // 设置第三方回调id

+ 2 - 3
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/utils/CommonUtils.java

@@ -92,10 +92,9 @@ public class CommonUtils {
 
 
     public static String generateRightsId(long incrementalNumber) {
-        int i = (int) incrementalNumber;
         String datePart = getDateTime("yyyyMMdd"); // 获取日期部分
-        String numberPart = String.format("%05d", incrementalNumber); // 格式化数字为5位
-        return "D" + datePart + numberPart;
+        String numberPart = String.format("%08d", incrementalNumber); // 格式化数字为5位
+        return datePart + numberPart;
     }
 
     public static String generatePrefixId(long incrementalNumber, String prefix) {

+ 1 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/AppStoreWebhookMonitor.java

@@ -92,7 +92,7 @@ public class AppStoreWebhookMonitor {
                         // 订阅已成功续订
                         case DID_RENEW:
                             if (decodedPayload.getData().getStatus().equals(1)){
-                                appStoreWebhookService.subscriptionPaymentSucceeded(false,jwsRenewalInfoDecodedPayload.getOriginalTransactionId(),jwsTransactionDecodedPayload.getTransactionId(),1);
+                                appStoreWebhookService.subscriptionPaymentSucceeded(false,jwsRenewalInfoDecodedPayload.getOriginalTransactionId(),jwsTransactionDecodedPayload.getTransactionId(),1,jwsTransactionDecodedPayload);
                             }
                             break;
                         // 订阅已过期

+ 8 - 7
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/GoogleWebhookMonitor.java

@@ -72,17 +72,18 @@ public class GoogleWebhookMonitor {
             // 获取订阅订单信息
             SubscriptionPurchaseV3 subscriptionGoogleOrderV2 = googlePayClient.getSubscription(developerNotification.getPackageName(), purchaseToken);
             //测试订单
-            if (subscriptionGoogleOrderV2.getTestPurchase() != null) {
+            log.info("谷歌 订阅:{}", subscriptionGoogleOrderV2.toString());
+            if(ObjectUtils.isEmpty(subscriptionGoogleOrderV2.getExternalAccountIdentifiers())){
+                log.info("没有订阅id,旧产品订阅回调不处理,谷歌订阅回调:{}", notificationType);
+                return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
+            }
+            if(subscriptionGoogleOrderV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId().contains("test")){
                 if (googlePayConfig.getIsSandbox().equals("false")) {
                     log.info("正式环境转发测试回调", purchaseToken);
                     sandboxCallBack(body);
                     return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
                 }
             }
-            if(ObjectUtils.isEmpty(subscriptionGoogleOrderV2.getExternalAccountIdentifiers())){
-                log.info("没有订阅id,旧产品订阅回调不处理,谷歌订阅回调:{}", notificationType);
-                return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
-            }
             //判断订单状态
             if (!googlePayClient.checkSubscriptionSuccess(subscriptionGoogleOrderV2)) {
                 log.error("谷歌订单验证状态异常:{}", subscriptionGoogleOrderV2);
@@ -103,7 +104,7 @@ public class GoogleWebhookMonitor {
                         return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
                     } else if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_RENEWED.getType() == notificationType) {
                         // 续订处理
-                        googlePayService.subscriptionPaymentSucceeded(false, subscriptionGoogleOrderV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId(), subscriptionGoogleOrderV2.getLatestOrderId(), 2);
+                        googlePayService.subscriptionPaymentSucceeded(false, subscriptionGoogleOrderV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId(), subscriptionGoogleOrderV2.getLatestOrderId(), 2,subscriptionGoogleOrderV2);
                         return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
                     }
                 }
@@ -118,7 +119,7 @@ public class GoogleWebhookMonitor {
             return ResponseEntity.status(HttpStatus.OK).build(); // 返回 200 OK
 
         } catch (Exception e) {
-            log.error("谷歌 回调失败:" + e.getMessage() + "purchaseToken:{}", body);
+            log.error("谷歌 回调失败:" + e.getMessage() + "purchaseToken:{}");
             return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // 返回 500 错误
         }
     }

+ 2 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/appstore/notification/NotificationType.java

@@ -28,5 +28,6 @@ public enum NotificationType {
 
   REVOKE,
 
-  SUBSCRIBED
+  SUBSCRIBED,
+  ONE_TIME_CHARGE
 }

+ 9 - 1
pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/controller/GoogleController.java

@@ -8,6 +8,7 @@ import cn.kdan.cloud.pdf.office.common.vo.UserInfoVO;
 import cn.kdan.cloud.pdf.office.website.service.PaymentService;
 import cn.kdan.cloud.pdf.office.website.utils.SecurityUtils;
 import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 
 
@@ -21,6 +22,8 @@ public class GoogleController {
 
     private final PaymentService paymentService;
 
+    @Value("${isSandbox}")
+    private String isSandbox;
 
     /**
      * 谷歌 权益校验
@@ -38,7 +41,12 @@ public class GoogleController {
      */
     @GetMapping("/generateSubscriptionId")
     public ResultMap<String> generateSubscriptionId() {
+        if (isSandbox.equals("false")) {
+            return ResultMap.success(MyDateUtils.getTimeStamp() + "-" + "google" + "-" + (int) ((Math.random() * 9 + 1) * 1000)+"-pro"); // 返回生成的订阅 ID
+        }else{
+            return ResultMap.success(MyDateUtils.getTimeStamp() + "-" + "google" + "-" + (int) ((Math.random() * 9 + 1) * 1000)+"-test"); // 返回生成的订阅 ID
+
+        }
         // 生成一个唯一的订阅 ID
-        return ResultMap.success(MyDateUtils.getTimeStamp() + "-" + "google" + "-" + (int) ((Math.random() * 9 + 1) * 1000)); // 返回生成的订阅 ID
     }
 }

+ 9 - 4
pdf-office-product/src/main/java/cn/kdan/cloud/pdf/office/product/service/impl/ProductServiceImpl.java

@@ -393,7 +393,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
     @Override
     public ListingProductVO checkCoupon(String productId, String userId, String code) {
         Prize prize = prizeService.getOne(new LambdaQueryWrapper<Prize>()
-                .eq(Prize::getCode, code).eq(Prize::getUserId, userId).eq(Prize::getValidFlag, 1));
+                .eq(Prize::getCode, code).eq(Prize::getValidFlag, 1));
         if (prize == null) {
             log.error("优惠券不存在:{}", code);
             throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_NOT_EXISTS);
@@ -420,14 +420,19 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
             throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
         }
         if(ObjectUtils.isNotEmpty(listingProductVO.getDisplayPrice())){
-            if (prize.getActivityType().equals("1")&&listingProductVO.getDisplayPrice().compareTo(BigDecimal.valueOf(79.99))<0){
+            if (prize.getActivityType().equals("1")){
                 throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
             }
             listingProductVO.setDisplayPrice(listingProductVO.getDisplayPrice().subtract(prize.getUsdPrice()));
             listingProductVO.setCnyDisplayPrice(listingProductVO.getCnyDisplayPrice().subtract(prize.getCnyPrice()));
         }else{
-            if (prize.getActivityType().equals("1")&&listingProductVO.getPrice().compareTo(BigDecimal.valueOf(79.99))<0){
-                throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
+            if ("1".equals(prize.getActivityType())) {
+                if (listingProductVO.getDiscountType()==1) {
+                    throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
+                }
+                if (listingProductVO.getPrice().compareTo(BigDecimal.valueOf(79.99)) < 0) {
+                    throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_INVALID);
+                }
             }
             listingProductVO.setDisplayPrice(listingProductVO.getPrice().subtract(prize.getUsdPrice()));
             listingProductVO.setCnyDisplayPrice(listingProductVO.getCnyPrice().subtract(prize.getCnyPrice()));