فهرست منبع

feat(order): 增加订单退款防重提交机制并优化退款逻辑

- 在 OrderController 的 refundOrder 方法上添加 @,RepeatSubmit 注解设置防重类型为 SERVICE,锁定时间为 60 秒
- 修改 NoRepeatSubmitAspect 切面逻辑,支持 SERVICE 类型的防重控制,并针对 refundOrder服务 ID 抛出自定义提示信息- 更新 AppOrderProInfo 实体类,增加 Serial 版本号以支持序列化兼容性
-优化 OrderServiceImpl 中的退款校验逻辑,新增对 ORDER_PRO_INFO_TYPE_5 类型订单的课程开始时间判断- 调整查询订单商品信息时的过滤条件,排除 afterSaleStatus 为0 的记录- 修改分账接收方账号和描述信息,从“帝释天”改为“海南”
- 更新 WechatUrlConstants 配置,切换支付通知和退款通知回调地址到新的测试域名- 扩展 RepeatSubmit 注解中的 Type 枚举,新增 SERVICE 类型用于业务级别防重控制
wzq 1 روز پیش
والد
کامیت
0559d31cc0

+ 4 - 1
national-motion-base-core/src/main/java/org/jeecg/common/aspect/NoRepeatSubmitAspect.java

@@ -35,7 +35,7 @@ public class NoRepeatSubmitAspect {
         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
         String serviceId = repeatSubmit.serviceId();  // 获取RepeatSubmit注解中的serviceId
         String type = repeatSubmit.limitType().name();  // 获取防重提交的类型
-        if (type.equalsIgnoreCase(RepeatSubmit.Type.PARAM.name())) {
+        if (type.equalsIgnoreCase(RepeatSubmit.Type.PARAM.name()) || type.equalsIgnoreCase(RepeatSubmit.Type.SERVICE.name())) {
             long lockTime = repeatSubmit.lockTime();  // 获取锁的超时时间
             String ipAddr = request.getRemoteAddr();  // 获取客户端IP地址
             MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
@@ -46,6 +46,9 @@ public class NoRepeatSubmitAspect {
             boolean isLocked = redissonClient.getLock(key).tryLock(lockTime, TimeUnit.MILLISECONDS);  // 尝试获取锁
 
             if (!isLocked) {
+                if (repeatSubmit.serviceId().equals("refundOrder")) {
+                    throw new RuntimeException("多次部分退款,请间隔1分钟后再试");
+                 }
                 throw new RuntimeException("重复提交,请稍后再试");  // 如果获取锁失败,抛出异常
             }
 

+ 1 - 1
national-motion-base-core/src/main/java/org/jeecg/common/aspect/annotation/RepeatSubmit.java

@@ -22,6 +22,6 @@ public @interface RepeatSubmit {
     /**
      * 定义了两种防止重复提交的方式,PARAM 表示基于方法参数来防止重复,TOKEN 则可能涉及生成和验证token的机制
      */
-    enum Type {PARAM, TOKEN}
+    enum Type {PARAM, TOKEN, SERVICE}
 }
 

+ 3 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/OrderController.java

@@ -242,12 +242,12 @@ public class OrderController {
      * @return
      */
     @Operation(summary = "订单退款")
+    @RepeatSubmit(serviceId = "refundOrder", limitType = RepeatSubmit.Type.SERVICE, lockTime = 60)
     @PostMapping("/refundOrder")
     public Result<String> refundOrder(@Validated @RequestBody RefundOrderForm refundOrderForm) throws ParseException {
         return Result.OK(appOrderService.refundOrder(refundOrderForm));
     }
 
-
     /**
      * 赛事订单退款
      * @param orderCode
@@ -293,6 +293,7 @@ public class OrderController {
                 appOrderService.updateById(appOrder);
                 List<AppOrderProInfo> orderProInfoList = appOrderProInfoService.list(Wrappers.<AppOrderProInfo>lambdaQuery()
                         .eq(AppOrderProInfo::getOrderId, appOrder.getId())
+                        .ne(AppOrderProInfo::getAfterSaleStatus, CommonConstant.NUMBER_0)
                         .ne(AppOrderProInfo::getType, CommonConstant.ORDER_PRO_INFO_TYPE_6)
                 );
 
@@ -320,7 +321,7 @@ public class OrderController {
                         appOrder.getId()));
 
                 for (AppOrderProInfo appOrderProInfo : orderProInfoList) {
-                    appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_6).setAfterSaleStatus(CommonConstant.NUMBER_2);
+                    appOrderProInfo.setAfterSaleStatus(CommonConstant.NUMBER_3);
                     appOrderProInfoService.updateById(appOrderProInfo);
                 }
                 AppOrderRefundsInfo appOrderRefundsInfo =

+ 36 - 26
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -2223,38 +2223,48 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             if (appOrder.getProfitSharingStatus() > CommonConstant.NUMBER_0) {
                 throw new JeecgBootException("当前订单无法进行退款,请联系客服处理!");
             }
-            if (!Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_1) && !appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_2)) {
+            if (!Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_1) && !appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_2) && !appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_5)) {
                 throw new JeecgBootException("当前订单类型不支持退款!");
             }
             if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_2)) {
                 throw new JeecgBootException("订单商品已使用,无法进行退款!");
             }
-            //通过订单查询门店退款规则,判断是否可以进行退款
-            String s = appOrder.getProductIds().split(",")[0];
-            String priceRuleId = s.split("\\|")[0];
-            AppSitePriceRules appSitePriceRules =
-                    appSitePriceRulesMapper.selectOne(Wrappers.<AppSitePriceRules>lambdaQuery().eq(AppSitePriceRules::getId, priceRuleId).last("limit 1"));
-            String sitePlaceId = appSitePriceRules.getSitePlaceId();
-            AppSitePlace appSitePlace = appSitePlaceMapper.selectById(sitePlaceId);
-            if (Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_2) && Objects.equals(appSitePlace.getRefundType(),
-                    CommonConstant.NUMBER_2)) {
-                throw new JeecgBootException("当前门店不支持退款!");
+            if (Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_5)) {
+                AppCourses appCourses = appCoursesMapper.selectById(appOrder.getProductIds());
+                Date startTime = appCourses.getStartTime();
+                Date now = new Date();
+                if(startTime.before(now)){
+                    throw new JeecgBootException("当前课程已开始,无法进行退款!");
+                }
             }
-            if (Objects.equals(appSitePlace.getRefundType(), CommonConstant.NUMBER_1)) {
-
-                for (String refundOrderProInfoId : refundOrderProInfoIds) {
-                    AppOrderProInfo appOrderProInfo = appOrderProInfoMapper.selectById(refundOrderProInfoId);
-                    String productId = appOrderProInfo.getProductId();
-                    AppSitePriceRules sitePriceRules = appSitePriceRulesMapper.selectById(productId);
-                    if(ObjectUtil.isNotEmpty(sitePriceRules)){
-                        if(Objects.equals(sitePriceRules.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_1)){
-                            String timeStr = appOrderProInfo.getProductName().split("-")[0] + "-" + appOrderProInfo.getProductName().split("-")[1];
-                            int year = LocalDate.now().getYear();
-                            Instant originalInstant = DateUtils.parseDate(year+"-"+timeStr, "yyyy-MM-dd HH:mm").toInstant();
-                            Instant time = originalInstant.minusSeconds(appSitePlace.getEarlyRefundTime() * 60);
-                            Instant now = Instant.now();
-                            if (!now.isBefore(time)) {
-                                throw new JeecgBootException("商品:" + appOrderProInfo.getProductName() + " 已超过可退时间,无法进行退款!");
+            if (Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_1) || appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_2)){
+                //通过订单查询门店退款规则,判断是否可以进行退款
+                String s = appOrder.getProductIds().split(",")[0];
+                String priceRuleId = s.split("\\|")[0];
+                AppSitePriceRules appSitePriceRules =
+                        appSitePriceRulesMapper.selectOne(Wrappers.<AppSitePriceRules>lambdaQuery().eq(AppSitePriceRules::getId, priceRuleId).last("limit 1"));
+                String sitePlaceId = appSitePriceRules.getSitePlaceId();
+                AppSitePlace appSitePlace = appSitePlaceMapper.selectById(sitePlaceId);
+                if (Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_2) && Objects.equals(appSitePlace.getRefundType(),
+                        CommonConstant.NUMBER_2)) {
+                    throw new JeecgBootException("当前门店不支持退款!");
+                }
+                if (Objects.equals(appSitePlace.getRefundType(), CommonConstant.NUMBER_1)) {
+
+                    for (String refundOrderProInfoId : refundOrderProInfoIds) {
+                        AppOrderProInfo appOrderProInfo = appOrderProInfoMapper.selectById(refundOrderProInfoId);
+                        String productId = appOrderProInfo.getProductId();
+                        AppSitePriceRules sitePriceRules = appSitePriceRulesMapper.selectById(productId);
+                        if(ObjectUtil.isNotEmpty(sitePriceRules)){
+                            if(Objects.equals(sitePriceRules.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_1)){
+                                String timeStr = appOrderProInfo.getProductName().split("-")[0] + "-" + appOrderProInfo.getProductName().split("-")[1];
+                                int year = LocalDate.now().getYear();
+                                Instant originalInstant = DateUtils.parseDate(year+"-"+timeStr, "yyyy-MM-dd HH:mm").toInstant();
+                                Instant time = originalInstant.minusSeconds(appSitePlace.getEarlyRefundTime() * 60);
+                                Instant now = Instant.now();
+                                if (!now.isBefore(time)) {
+                                    throw new JeecgBootException("商品:" + appOrderProInfo.getProductName() + " 已超过可退时间,无法进行退款!");
+                                }
                             }
                         }
                     }

+ 2 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/paytest/payController.java

@@ -207,9 +207,9 @@ public class payController {
         for (int i = 0; i < 1; i++) {
             Receiver receiver = new Receiver();
             receiver.setType("MERCHANT_ID")
-                    .setAccount("1723757626")
+                    .setAccount("1726610149")
                     .setAmount(1)
-                    .setDescription("分给帝释天");
+                    .setDescription("分给海南");
             receivers.add(receiver);
         }
         ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest();

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppOrderProInfo.java

@@ -12,6 +12,7 @@ import lombok.experimental.Accessors;
 import org.jeecgframework.poi.excel.annotation.Excel;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import java.io.Serial;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
@@ -22,6 +23,7 @@ import java.util.Date;
 @EqualsAndHashCode(callSuper = false)
 @Schema(description="订单商品信息")
 public class AppOrderProInfo implements Serializable{
+    @Serial
     private static final long serialVersionUID = 1L;
 
     /**id*/