Przeglądaj źródła

支付模块:paypal paddle取消订阅时直接修改自动订阅状态 第三方回调时查询用户关于该产品最新订阅判断是否需要修改用户的自动订阅状态

tangxiangan 1 rok temu
rodzic
commit
2c21f4dc42
16 zmienionych plików z 493 dodań i 51 usunięć
  1. 5 1
      pdf-office-api/pdf-office-api-payment/pom.xml
  2. 10 1
      pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/constant/PaddleAPIConstant.java
  3. 49 0
      pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/LastPayment.java
  4. 47 24
      pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/NextPayment.java
  5. 61 0
      pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/PaymentInformation.java
  6. 182 0
      pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/SubscriptionWithUser.java
  7. 26 8
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/PaddleClient.java
  8. 9 0
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/mapper/SubscriptionsMapper.java
  9. 8 0
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/SubscriptionsService.java
  10. 4 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PaddleWebhookServiceImpl.java
  11. 13 10
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/SubscriptionsServiceImpl.java
  12. 29 3
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/WebhookServiceImpl.java
  13. 1 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/PaypalWebhookMonitor.java
  14. 43 1
      pdf-office-payment/src/main/resources/mapper/SubscriptionsMapper.xml
  15. 5 0
      pdf-office-payment/src/test/java/cn/kdan/cloud/pdf/office/payment/PaddleTest.java
  16. 1 1
      pdf-office-payment/src/test/java/cn/kdan/cloud/pdf/office/payment/PayPalTest.java

+ 5 - 1
pdf-office-api/pdf-office-api-payment/pom.xml

@@ -30,6 +30,10 @@
             <groupId>com.fasterxml.jackson.datatype</groupId>
             <artifactId>jackson-datatype-jsr310</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
     </dependencies>
 
-</project>
+</project>

+ 10 - 1
pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/constant/PaddleAPIConstant.java

@@ -6,9 +6,18 @@ package cn.kdan.cloud.pdf.office.api.payment.constant;
  * PaypalAPIConstant
  */
 public interface PaddleAPIConstant {
-
+    /**
+     * 生成支付链接
+     */
     String CREAT_PAY_LINK = "/product/generate_pay_link";
+    /**
+     * 取消用户订阅
+     */
     String CANCEL_SUBSCRIPTION = "/subscription/users_cancel";
+    /**
+     * 查询某个订阅用户的订阅状态
+     */
+    String USER_SUBSCRIPTION = "/subscription/users";
     String UPDATE_SUBSCRIPTION = "/subscription/users/update";
 
     String VENDORID = "vendor_id";

+ 49 - 0
pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/LastPayment.java

@@ -0,0 +1,49 @@
+package cn.kdan.cloud.pdf.office.api.payment.paddle;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class LastPayment{
+
+	@JSONField(name="date")
+	private String date;
+
+	@JSONField(name="amount")
+	private double amount;
+
+	@JSONField(name="currency")
+	private String currency;
+
+	public void setDate(String date){
+		this.date = date;
+	}
+
+	public String getDate(){
+		return date;
+	}
+
+	public void setAmount(double amount){
+		this.amount = amount;
+	}
+
+	public double getAmount(){
+		return amount;
+	}
+
+	public void setCurrency(String currency){
+		this.currency = currency;
+	}
+
+	public String getCurrency(){
+		return currency;
+	}
+
+	@Override
+ 	public String toString(){
+		return 
+			"LastPayment{" + 
+			"date = '" + date + '\'' + 
+			",amount = '" + amount + '\'' + 
+			",currency = '" + currency + '\'' + 
+			"}";
+		}
+}

+ 47 - 24
pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/NextPayment.java

@@ -1,26 +1,49 @@
 package cn.kdan.cloud.pdf.office.api.payment.paddle;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import lombok.Data;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * @author ComPDFKit-WPH 2023/2/2
- */
-@Data
-@ToString
-public class NextPayment implements Serializable {
-    private BigDecimal amount;
-    private String currency;
-
-    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
-    @JsonSerialize(using = LocalDateTimeSerializer.class)
-    private LocalDateTime date;
-}
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class NextPayment{
+
+	@JSONField(name="date")
+	private String date;
+
+	@JSONField(name="amount")
+	private double amount;
+
+	@JSONField(name="currency")
+	private String currency;
+
+	public void setDate(String date){
+		this.date = date;
+	}
+
+	public String getDate(){
+		return date;
+	}
+
+	public void setAmount(double amount){
+		this.amount = amount;
+	}
+
+	public double getAmount(){
+		return amount;
+	}
+
+	public void setCurrency(String currency){
+		this.currency = currency;
+	}
+
+	public String getCurrency(){
+		return currency;
+	}
+
+	@Override
+ 	public String toString(){
+		return 
+			"NextPayment{" + 
+			"date = '" + date + '\'' + 
+			",amount = '" + amount + '\'' + 
+			",currency = '" + currency + '\'' + 
+			"}";
+		}
+}

+ 61 - 0
pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/PaymentInformation.java

@@ -0,0 +1,61 @@
+package cn.kdan.cloud.pdf.office.api.payment.paddle;
+import com.alibaba.fastjson.annotation.JSONField;
+
+
+public class PaymentInformation{
+
+	@JSONField(name="expiry_date")
+	private String expiryDate;
+
+	@JSONField(name="card_type")
+	private String cardType;
+
+	@JSONField(name="last_four_digits")
+	private String lastFourDigits;
+
+	@JSONField(name="payment_method")
+	private String paymentMethod;
+
+	public void setExpiryDate(String expiryDate){
+		this.expiryDate = expiryDate;
+	}
+
+	public String getExpiryDate(){
+		return expiryDate;
+	}
+
+	public void setCardType(String cardType){
+		this.cardType = cardType;
+	}
+
+	public String getCardType(){
+		return cardType;
+	}
+
+	public void setLastFourDigits(String lastFourDigits){
+		this.lastFourDigits = lastFourDigits;
+	}
+
+	public String getLastFourDigits(){
+		return lastFourDigits;
+	}
+
+	public void setPaymentMethod(String paymentMethod){
+		this.paymentMethod = paymentMethod;
+	}
+
+	public String getPaymentMethod(){
+		return paymentMethod;
+	}
+
+	@Override
+ 	public String toString(){
+		return
+			"PaymentInformation{" +
+			"expiry_date = '" + expiryDate + '\'' +
+			",card_type = '" + cardType + '\'' +
+			",last_four_digits = '" + lastFourDigits + '\'' +
+			",payment_method = '" + paymentMethod + '\'' +
+			"}";
+		}
+}

+ 182 - 0
pdf-office-api/pdf-office-api-payment/src/main/java/cn/kdan/cloud/pdf/office/api/payment/paddle/SubscriptionWithUser.java

@@ -0,0 +1,182 @@
+package cn.kdan.cloud.pdf.office.api.payment.paddle;
+
+import java.util.List;
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class SubscriptionWithUser {
+
+	@JSONField(name="user_email")
+	private String userEmail;
+
+	@JSONField(name="payment_information")
+	private PaymentInformation paymentInformation;
+
+	@JSONField(name="linked_subscriptions")
+	private List<Object> linkedSubscriptions;
+
+	@JSONField(name="subscription_id")
+	private int subscriptionId;
+
+	@JSONField(name="next_payment")
+	private NextPayment nextPayment;
+
+	@JSONField(name="signup_date")
+	private String signupDate;
+
+	@JSONField(name="user_id")
+	private int userId;
+
+	@JSONField(name="update_url")
+	private String updateUrl;
+
+	@JSONField(name="last_payment")
+	private LastPayment lastPayment;
+
+	@JSONField(name="state")
+	private String state;
+
+	@JSONField(name="marketing_consent")
+	private boolean marketingConsent;
+
+	@JSONField(name="cancel_url")
+	private String cancelUrl;
+
+	@JSONField(name="custom_data")
+	private Object customData;
+
+	@JSONField(name="plan_id")
+	private int planId;
+
+	public void setUserEmail(String userEmail){
+		this.userEmail = userEmail;
+	}
+
+	public String getUserEmail(){
+		return userEmail;
+	}
+
+	public void setPaymentInformation(PaymentInformation paymentInformation){
+		this.paymentInformation = paymentInformation;
+	}
+
+	public PaymentInformation getPaymentInformation(){
+		return paymentInformation;
+	}
+
+	public void setLinkedSubscriptions(List<Object> linkedSubscriptions){
+		this.linkedSubscriptions = linkedSubscriptions;
+	}
+
+	public List<Object> getLinkedSubscriptions(){
+		return linkedSubscriptions;
+	}
+
+	public void setSubscriptionId(int subscriptionId){
+		this.subscriptionId = subscriptionId;
+	}
+
+	public int getSubscriptionId(){
+		return subscriptionId;
+	}
+
+	public void setNextPayment(NextPayment nextPayment){
+		this.nextPayment = nextPayment;
+	}
+
+	public NextPayment getNextPayment(){
+		return nextPayment;
+	}
+
+	public void setSignupDate(String signupDate){
+		this.signupDate = signupDate;
+	}
+
+	public String getSignupDate(){
+		return signupDate;
+	}
+
+	public void setUserId(int userId){
+		this.userId = userId;
+	}
+
+	public int getUserId(){
+		return userId;
+	}
+
+	public void setUpdateUrl(String updateUrl){
+		this.updateUrl = updateUrl;
+	}
+
+	public String getUpdateUrl(){
+		return updateUrl;
+	}
+
+	public void setLastPayment(LastPayment lastPayment){
+		this.lastPayment = lastPayment;
+	}
+
+	public LastPayment getLastPayment(){
+		return lastPayment;
+	}
+
+	public void setState(String state){
+		this.state = state;
+	}
+
+	public String getState(){
+		return state;
+	}
+
+	public void setMarketingConsent(boolean marketingConsent){
+		this.marketingConsent = marketingConsent;
+	}
+
+	public boolean isMarketingConsent(){
+		return marketingConsent;
+	}
+
+	public void setCancelUrl(String cancelUrl){
+		this.cancelUrl = cancelUrl;
+	}
+
+	public String getCancelUrl(){
+		return cancelUrl;
+	}
+
+	public void setCustomData(Object customData){
+		this.customData = customData;
+	}
+
+	public Object getCustomData(){
+		return customData;
+	}
+
+	public void setPlanId(int planId){
+		this.planId = planId;
+	}
+
+	public int getPlanId(){
+		return planId;
+	}
+
+	@Override
+ 	public String toString(){
+		return
+			"ResponseItem{" +
+			"user_email = '" + userEmail + '\'' +
+			",payment_information = '" + paymentInformation + '\'' +
+			",linked_subscriptions = '" + linkedSubscriptions + '\'' +
+			",subscription_id = '" + subscriptionId + '\'' +
+			",next_payment = '" + nextPayment + '\'' +
+			",signup_date = '" + signupDate + '\'' +
+			",user_id = '" + userId + '\'' +
+			",update_url = '" + updateUrl + '\'' +
+			",last_payment = '" + lastPayment + '\'' +
+			",state = '" + state + '\'' +
+			",marketing_consent = '" + marketingConsent + '\'' +
+			",cancel_url = '" + cancelUrl + '\'' +
+			",custom_data = '" + customData + '\'' +
+			",plan_id = '" + planId + '\'' +
+			"}";
+		}
+}

+ 26 - 8
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/PaddleClient.java

@@ -5,6 +5,7 @@ import cn.kdan.cloud.pdf.office.api.payment.bo.GeneratePayLinkPaddleBO;
 import cn.kdan.cloud.pdf.office.api.payment.bo.GeneratePayLinkResultPaddleBO;
 import cn.kdan.cloud.pdf.office.api.payment.constant.PaddleAPIConstant;
 import cn.kdan.cloud.pdf.office.api.payment.paddle.PaddleResult;
+import cn.kdan.cloud.pdf.office.api.payment.paddle.SubscriptionWithUser;
 import cn.kdan.cloud.pdf.office.api.payment.paddle.UpdateSubscription;
 import cn.kdan.cloud.pdf.office.api.payment.paddle.UpdateSubscriptionResult;
 import cn.kdan.cloud.pdf.office.common.exception.BackendRuntimeException;
@@ -30,7 +31,10 @@ import org.springframework.web.client.DefaultResponseErrorHandler;
 import org.springframework.web.client.RestTemplate;
 
 import java.io.IOException;
-import java.util.*;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * @author ComPDFKit-WPH 2023/1/16
@@ -177,13 +181,27 @@ public class PaddleClient {
      * @param subscriptionId subscriptionId
      * @return CreateSubscriptionsResultBO
      */
-    public CreateSubscriptionsResultPaypalBO getSubscriptionInfo(@NotNull String subscriptionId) {
-//        String resultJson = restTemplate.exchange(PADDLE_HOST + PaypalAPIConstant.GET_SUBSCRIPTIONS_INFO + subscriptionId,
-//                HttpMethod.GET,
-//                new HttpEntity<>(getJsonHttpHeaders()),
-//                String.class).getBody();
-//        return JsonUtils.jsonStringToBean(resultJson, CreateSubscriptionsResultPaypalBO.class);
-        return null;
+    public List<SubscriptionWithUser> getSubscriptionInfo(@NotNull String subscriptionId) {
+        log.info("paddle 查询订阅:{}", subscriptionId);
+        MultiValueMap<String, Object> requestParamMap = getValueMap(null);
+        requestParamMap.set("subscription_id", subscriptionId);
+        requestParamMap.set("page", 1);
+        requestParamMap.set("results_per_page", 1);
+        requestParamMap.set("state", "active");
+        String resultJson = restTemplate.exchange(
+                PADDLE_VENDORS_HOST + PaddleAPIConstant.USER_SUBSCRIPTION,
+                HttpMethod.POST,
+                new HttpEntity<>(requestParamMap, getWwwFormHttpHeaders()),
+                String.class).getBody();
+        PaddleResult<List<SubscriptionWithUser>> paddleResult = JSON.parseObject(resultJson,
+                new TypeReference<PaddleResult<List<SubscriptionWithUser>>>() {
+                });
+
+        if (!paddleResult.isSuccess()) {
+            log.error("paddle 取消续订调用失败\n:{},\n参数:{}", paddleResult.getError(), subscriptionId);
+            throw new BackendRuntimeException(paddleResult.getError().getMessage());
+        }
+        return paddleResult.getResponse();
     }
 
 

+ 9 - 0
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/mapper/SubscriptionsMapper.java

@@ -30,6 +30,15 @@ public interface SubscriptionsMapper extends BaseMapper<Subscription> {
     SubscriptionsVO selectNewestSubscriptionByProductId(@Param("userId") String userId,
                                                         @Param("productId") String productId);
 
+    /**
+     * 查询最新一条实际支付的订阅信息(排除赠送的订阅)
+     * @param userId 用户id
+     * @param productId 产品id
+     * @return SubscriptionsVO
+     */
+    SubscriptionsVO selectLatestSubscriptionForActualPayment(@Param("userId") String userId,
+                                                        @Param("productId") String productId);
+
     /**
      * 查询订阅信息 通过userId
      *

+ 8 - 0
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/SubscriptionsService.java

@@ -55,6 +55,14 @@ public interface SubscriptionsService extends IService<Subscription> {
      */
     SubscriptionsVO getSubscriptionsByProductId(String userId, String productId);
 
+    /**
+     * 查询最新一条实际支付的订阅信息(排除赠送的订阅)
+     * @param userId 用户id
+     * @param productId 产品id
+     * @return SubscriptionsVO
+     */
+    SubscriptionsVO getLatestSubscriptionForActualPayment(String userId, String productId);
+
     /**
      * 创建订阅信息 自动续订
      *

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

@@ -2,9 +2,12 @@ package cn.kdan.cloud.pdf.office.payment.service.impl;
 
 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.paddle.SubscriptionWithUser;
 import cn.kdan.cloud.pdf.office.api.payment.vo.OrdersVO;
+import cn.kdan.cloud.pdf.office.payment.client.PaddleClient;
 import cn.kdan.cloud.pdf.office.payment.service.OrderService;
 import cn.kdan.cloud.pdf.office.payment.service.PaddleWebhookService;
+import cn.kdan.cloud.pdf.office.payment.service.SubscriptionsService;
 import cn.kdan.cloud.pdf.office.payment.service.WebhookService;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
@@ -29,6 +32,7 @@ public class PaddleWebhookServiceImpl implements PaddleWebhookService {
 
 
 
+
     @Override
     public void subscriptionPaymentSucceeded(PaddleWebhookDTO paddleWebhookDTO) {
         log.info("paddle 订阅的支付订单已成功 paddle订单id:{}", paddleWebhookDTO.getCheckoutId());
@@ -54,7 +58,6 @@ public class PaddleWebhookServiceImpl implements PaddleWebhookService {
     public void subscriptionCancel(PaddleWebhookDTO paddleWebhookDTO) {
         String thirdSubscriptionId = paddleWebhookDTO.getSubscriptionId();
         log.info("订阅取消续订,paddle订阅id:{}", thirdSubscriptionId);
-        // 根据第三放订阅id查询对应的用户id和产品id
         webhookService.handleUnsubscribeFollowUpActions(thirdSubscriptionId);
     }
 }

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

@@ -13,7 +13,6 @@ import cn.kdan.cloud.pdf.office.api.product.feign.ProductApi;
 import cn.kdan.cloud.pdf.office.api.product.vo.ProductVO;
 import cn.kdan.cloud.pdf.office.common.enums.account.PDFOfficeUserSubscriptionPayTypeEnum;
 import cn.kdan.cloud.pdf.office.common.enums.account.PDFOfficeUserSubscriptionStatusEnum;
-import cn.kdan.cloud.pdf.office.common.enums.account.PaidTypeEnum;
 import cn.kdan.cloud.pdf.office.common.enums.account.PayTypeEnum;
 import cn.kdan.cloud.pdf.office.common.exception.BackendRuntimeException;
 import cn.kdan.cloud.pdf.office.common.utils.CommonUtils;
@@ -33,7 +32,6 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import freemarker.template.utility.DateUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -143,6 +141,11 @@ public class SubscriptionsServiceImpl extends ServiceImpl<SubscriptionsMapper, S
         return this.baseMapper.selectNewestSubscriptionByProductId(userId, productId);
     }
 
+    @Override
+    public SubscriptionsVO getLatestSubscriptionForActualPayment(String userId, String productId) {
+        return this.baseMapper.selectLatestSubscriptionForActualPayment(userId, productId);
+    }
+
     @Override
     public String createSubscriptionManual(CreateSubscriptionManualDTO subscriptionManual) {
         CreateSubscriptionDTO createSubscriptionDTO = new CreateSubscriptionDTO();
@@ -166,14 +169,6 @@ public class SubscriptionsServiceImpl extends ServiceImpl<SubscriptionsMapper, S
             case PAYPAL:
                 // 取消续订 webhook实际处理状态字段
                 paypalClient.cancelSubscription(thirdSubscriptionId,"Not satisfied with the service");
-                UserSubscriptionInfo userSubscriptionInfo = userSubscriptionInfoApi.getByUserIdAndProductId(subscription.getUserId(), subscription.getProductId()).getResult();
-                log.info("userSubscriptionInfo id: {} ",userSubscriptionInfo.getId());
-                UserSubscriptionInfo info = new UserSubscriptionInfo();
-                info.setUserId(userSubscriptionInfo.getUserId());
-                info.setProductId(userSubscriptionInfo.getProductId());
-                info.setPayType(PDFOfficeUserSubscriptionPayTypeEnum.NON_AUTO_SUBSCRIPTION.value());
-                info.setId(userSubscriptionInfo.getId());
-                userSubscriptionInfoApi.update(info);
                 break;
             case PADDLE:
                 // 更新paddle的订阅信息
@@ -186,6 +181,14 @@ public class SubscriptionsServiceImpl extends ServiceImpl<SubscriptionsMapper, S
             default:
                 throw new BackendRuntimeException(ErrorMessage.PAYMENT_METHOD_INVALID);
         }
+        UserSubscriptionInfo userSubscriptionInfo = userSubscriptionInfoApi.getByUserIdAndProductId(subscription.getUserId(), subscription.getProductId()).getResult();
+        log.info("userSubscriptionInfo id: {} ",userSubscriptionInfo.getId());
+        UserSubscriptionInfo info = new UserSubscriptionInfo();
+        info.setUserId(userSubscriptionInfo.getUserId());
+        info.setProductId(userSubscriptionInfo.getProductId());
+        info.setPayType(PDFOfficeUserSubscriptionPayTypeEnum.NON_AUTO_SUBSCRIPTION.value());
+        info.setId(userSubscriptionInfo.getId());
+        userSubscriptionInfoApi.update(info);
     }
 
     @Override

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

@@ -5,11 +5,13 @@ import cn.kdan.cloud.pdf.office.api.account.feign.UserSubscriptionInfoApi;
 import cn.kdan.cloud.pdf.office.api.account.vo.UserSubscriptionInfo;
 import cn.kdan.cloud.pdf.office.api.email.bo.EmailSendBO;
 import cn.kdan.cloud.pdf.office.api.email.feign.EmailApi;
+import cn.kdan.cloud.pdf.office.api.payment.bo.CreateSubscriptionsResultPaypalBO;
 import cn.kdan.cloud.pdf.office.api.payment.bo.OrderSucceededBO;
 import cn.kdan.cloud.pdf.office.api.payment.constant.OrderConstant;
 import cn.kdan.cloud.pdf.office.api.payment.dto.CreateOrderManualDTO;
 import cn.kdan.cloud.pdf.office.api.payment.dto.CreateSubscriptionDTO;
 import cn.kdan.cloud.pdf.office.api.payment.enums.PaymentMethodEnum;
+import cn.kdan.cloud.pdf.office.api.payment.paddle.SubscriptionWithUser;
 import cn.kdan.cloud.pdf.office.api.payment.paypal.transaction.PaypalTransaction;
 import cn.kdan.cloud.pdf.office.api.payment.paypal.transaction.TransactionsItem;
 import cn.kdan.cloud.pdf.office.api.payment.vo.OrderUpdateVO;
@@ -27,6 +29,7 @@ import cn.kdan.cloud.pdf.office.common.pojo.ResultMap;
 import cn.kdan.cloud.pdf.office.common.utils.CommonUtils;
 import cn.kdan.cloud.pdf.office.common.utils.MyDateUtils;
 import cn.kdan.cloud.pdf.office.common.vo.UserVO;
+import cn.kdan.cloud.pdf.office.payment.client.PaddleClient;
 import cn.kdan.cloud.pdf.office.payment.client.PaypalClient;
 import cn.kdan.cloud.pdf.office.payment.enums.PaypalTransactionStatusEnum;
 import cn.kdan.cloud.pdf.office.payment.enums.PaypalWebhookEventEnum;
@@ -92,6 +95,8 @@ public class WebhookServiceImpl implements WebhookService {
 
     private final PaypalClient paypalClient;
 
+    private final PaddleClient paddleClient;
+
     @Override
     public void handleSubsequentAutomaticDeduction(BigDecimal price, String thirdTradeNo, String thirdOrderId, OrdersVO orderByTradeNo) {
         log.info("自动订阅业务处理开始(非首期)订单id:{}", thirdOrderId);
@@ -275,7 +280,6 @@ public class WebhookServiceImpl implements WebhookService {
         // 生成发票,  C端发票操作
         // 设置请求header
         log.info("发票html内容填充map: {}",map.toString());
-//        log.info("发票html内容填充后: {}",invoiceHtml);
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
         // 封装表单数据
@@ -336,9 +340,31 @@ public class WebhookServiceImpl implements WebhookService {
         String userId = subscription.getUserId();
         String productId = subscription.getProductId();
         // 根据用户id和产品id修改用户订阅状态 不是自动订阅
-        log.info("userId: {} productId:{}",userId,productId);
+        log.info("userId: {} productId:{}", userId, productId);
         UserSubscriptionInfo userSubscriptionInfo = userSubscriptionInfoApi.getByUserIdAndProductId(userId, productId).getResult();
-        log.info("userSubscriptionInfo id: {} ",userSubscriptionInfo.getId());
+        log.info("userSubscriptionInfo id: {} ", userSubscriptionInfo.getId());
+        SubscriptionsVO latestSubscription = subscriptionsService.getLatestSubscriptionForActualPayment(userId, productId);
+        //用户最新的实际订阅
+        log.info("LatestSubscriptionForActualPayment id: {} ", latestSubscription.getId());
+        PaymentMethodEnum paymentMethodEnum = PaymentMethodEnum.fromValue(latestSubscription.getPayment());
+        switch (paymentMethodEnum) {
+            case PADDLE:
+                List<SubscriptionWithUser> list = paddleClient.getSubscriptionInfo(latestSubscription.getThirdSubscriptionId());
+                //如果查出来有记录说明处于订阅状态,则不需要修改状态
+                if (!CollectionUtils.isEmpty(list)) {
+                    return;
+                }
+                break;
+            case PAYPAL:
+                CreateSubscriptionsResultPaypalBO subscriptionsResultPaypalBO = paypalClient.getSubscriptionInfo(latestSubscription.getThirdSubscriptionId());
+                //如果订阅状态是活跃的,则不需要修改状态
+                if ("ACTIVE".equals(subscriptionsResultPaypalBO.getStatus())) {
+                    return;
+                }
+                break;
+            default:
+                return;
+        }
         UserSubscriptionInfo info = new UserSubscriptionInfo();
         info.setUserId(userId);
         info.setProductId(productId);

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

@@ -89,7 +89,7 @@ public class PaypalWebhookMonitor {
                             break;
                         case BILLING_SUBSCRIPTION_CANCELLED:
                             // 订阅取消成功回调
-                            // payPalWebhookService.subscriptionCancel(paypalWebhookMonitorDTO);
+                             payPalWebhookService.subscriptionCancel(paypalWebhookMonitorDTO);
                             break;
                         default:
                             throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_MSG_EVENT_IS_CURRENTLY_NOT_SUPPORTED);

+ 43 - 1
pdf-office-payment/src/main/resources/mapper/SubscriptionsMapper.xml

@@ -157,6 +157,48 @@
         ORDER BY s.end_date desc
         LIMIT 1
     </select>
+    <select id="selectLatestSubscriptionForActualPayment"
+            resultType="cn.kdan.cloud.pdf.office.api.payment.vo.SubscriptionsVO">
+        SELECT s.id,
+               s.product_id,
+               s.status,
+               s.price,
+               s.buyer_type,
+               s.cdkey,
+               s.email,
+               s.phone,
+               s.contact_name,
+               s.company_name,
+               s.start_date,
+               s.end_date,
+               s.max_device_amount,
+               s.cny_price,
+               s.coupon_id,
+               s.cdkey_type,
+               s.upgrade_cdkey,
+               s.for_reason,
+               s.last_sub_id,
+               s.payment,
+               s.original_price,
+               s.cny_original_price,
+               s.is_vpp,
+               s.vpp_member_id,
+               s.company_id,
+               s.user_id,
+               s.subscription_type,
+               s.third_subscription_id,
+               s.order_id,
+               s.app_id,
+               p.platform
+        FROM subscription s
+                 left join product p on s.product_id = p.id
+        where p.id = #{productId}
+          and s.user_id = #{userId}
+          AND s.`status` = 3
+          AND s.payment != 4
+        ORDER BY s.end_date desc
+        LIMIT 1
+    </select>
 
 
     <select id="selectByUserId" resultType="cn.kdan.cloud.pdf.office.api.payment.vo.SubscriptionsVO">
@@ -209,4 +251,4 @@
     </select>
 
 
-</mapper>
+</mapper>

+ 5 - 0
pdf-office-payment/src/test/java/cn/kdan/cloud/pdf/office/payment/PaddleTest.java

@@ -57,6 +57,11 @@ public class PaddleTest {
         UpdateSubscriptionResult updateSubscriptionResult = paddleClient.updateSubscription(updateSubscription);
     }
 
+    @Test
+    public void testActiveSub() {
+       paddleClient.getSubscriptionInfo("533832");
+    }
+
     @Autowired
     private RabbitTemplate rabbitTemplate;
 

+ 1 - 1
pdf-office-payment/src/test/java/cn/kdan/cloud/pdf/office/payment/PayPalTest.java

@@ -58,7 +58,7 @@ public class PayPalTest {
 
     @Test
     public void getSInfo(){
-        CreateSubscriptionsResultPaypalBO subscriptionInfo = paypalClient.getSubscriptionInfo("I-S8EXDUY8BYLF");
+        CreateSubscriptionsResultPaypalBO subscriptionInfo = paypalClient.getSubscriptionInfo("I-9JFFHM65F58R");
         System.out.println(JsonUtils.getJsonString(subscriptionInfo));
     }