Selaa lähdekoodia

Merge branch 'feature/mall_product' of https://gitee.com/puhui999/ruoyi-vue-pro into feature/mall_product

 Conflicts:
	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
YunaiV 1 vuosi sitten
vanhempi
commit
bdd81e4cbc
54 muutettua tiedostoa jossa 816 lisäystä ja 374 poistoa
  1. 2 4
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
  2. 2 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
  3. 2 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
  4. 4 4
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
  5. 2 2
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
  6. 19 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java
  7. 40 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java
  8. 8 49
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
  9. 14 24
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
  10. 12 10
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  11. 5 0
      yudao-module-mall/yudao-module-promotion-biz/pom.xml
  12. 2 19
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
  13. 23 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java
  14. 1 60
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
  15. 15 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
  16. 16 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
  17. 15 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
  18. 8 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
  19. 18 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
  20. 8 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  21. 38 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
  22. 26 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
  23. 7 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
  24. 34 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  25. 11 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
  26. 3 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
  27. 6 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
  28. 3 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
  29. 3 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
  30. 4 8
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java
  31. 3 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  32. 34 15
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  33. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java
  34. 2 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
  35. 9 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
  36. 7 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
  37. 69 78
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  38. 39 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java
  39. 57 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java
  40. 44 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java
  41. 49 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
  42. 32 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
  43. 44 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java
  44. 2 3
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
  45. 9 11
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  46. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
  47. 3 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
  48. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
  49. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
  50. 35 29
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
  51. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
  52. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
  53. 15 15
      yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
  54. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java

+ 2 - 4
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java

@@ -59,15 +59,13 @@ public class ProductSkuRespDTO {
      * 商品体积,单位:m^3 平米
      */
     private Double volume;
-
-    // TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致;
     /**
      * 一级分销的佣金,单位:分
      */
-    private Integer subCommissionFirstPrice;
+    private Integer firstBrokerageRecord;
     /**
      * 二级分销的佣金,单位:分
      */
-    private Integer subCommissionSecondPrice;
+    private Integer secondBrokerageRecord;
 
 }

+ 2 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java

@@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
     private Double volume;
 
     @Schema(description = "一级分销的佣金,单位:分", example = "199")
-    private Integer subCommissionFirstPrice;
+    private Integer firstBrokerageRecord;
 
     @Schema(description = "二级分销的佣金,单位:分", example = "19")
-    private Integer subCommissionSecondPrice;
+    private Integer secondBrokerageRecord;
 
     @Schema(description = "属性数组")
     private List<Property> properties;

+ 2 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java

@@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
     /**
      * 一级分销的佣金,单位:分
      */
-    private Integer subCommissionFirstPrice;
+    private Integer firstBrokerageRecord;
     /**
      * 二级分销的佣金,单位:分
      */
-    private Integer subCommissionSecondPrice;
+    private Integer secondBrokerageRecord;
 
     // ========== 营销相关字段 =========
 

+ 4 - 4
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java

@@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
             o.setMarketPrice(generaInt());
             o.setStock(generaInt());
             o.setWarnStock(10);
-            o.setSubCommissionFirstPrice(generaInt());
-            o.setSubCommissionSecondPrice(generaInt());
+            o.setFirstBrokerageRecord(generaInt());
+            o.setSecondBrokerageRecord(generaInt());
             // 限制分数为两位数
             o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
             o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
@@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
             o.setMarketPrice(generaInt());
             o.setStock(generaInt());
             o.setWarnStock(10);
-            o.setSubCommissionFirstPrice(generaInt());
-            o.setSubCommissionSecondPrice(generaInt());
+            o.setFirstBrokerageRecord(generaInt());
+            o.setSecondBrokerageRecord(generaInt());
             // 限制分数为两位数
             o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
             o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));

+ 2 - 2
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java

@@ -10,9 +10,9 @@ public interface BargainActivityApi {
     /**
      * 更新砍价活动库存
      *
-     * @param activityId 砍价活动编号
+     * @param id 砍价活动编号
      * @param count      购买数量
      */
-    void updateBargainActivityStock(Long activityId, Integer count);
+    void updateBargainActivityStock(Long id, Integer count);
 
 }

+ 19 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
+
+/**
+ * 拼团活动 Api 接口
+ *
+ * @author HUIHUI
+ */
+public interface CombinationApi {
+
+    /**
+     * 更新活动库存
+     *
+     * @param reqDTO 请求
+     */
+    void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
+
+}

+ 40 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.promotion.api.combination.dto;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 拼团活动更新活动库存 Request DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationActivityUpdateStockReqDTO {
+
+    @NotNull(message = "活动编号不能为空")
+    private Long activityId;
+
+    @NotNull(message = "购买数量不能为空")
+    private Integer count;
+
+    @NotNull(message = "活动商品不能为空")
+    private Item item;
+
+    @Data
+    @Valid
+    public static class Item {
+
+        @NotNull(message = "SPU 编号不能为空")
+        private Long spuId;
+
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
+
+}

+ 8 - 49
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.combination.dto;
 
 import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
 // TODO @芋艿:这块要在看看
@@ -14,65 +13,25 @@ import javax.validation.constraints.NotNull;
 @Data
 public class CombinationRecordCreateReqDTO {
 
-    /**
-     * 拼团活动编号
-     */
     @NotNull(message = "拼团活动编号不能为空")
     private Long activityId;
-    /**
-     * spu 编号
-     */
+
     @NotNull(message = "spu 编号不能为空")
     private Long spuId;
-    /**
-     * sku 编号
-     */
+
     @NotNull(message = "sku 编号不能为空")
     private Long skuId;
-    /**
-     * 用户编号
-     */
-    @NotNull(message = "用户编号不能为空")
-    private Long userId;
-    /**
-     * 订单编号
-     */
+
     @NotNull(message = "订单编号不能为空")
     private Long orderId;
-    /**
-     * 团长编号
-     */
+
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
     @NotNull(message = "团长编号不能为空")
     private Long headId;
-    /**
-     * 商品名字
-     */
-    @NotEmpty(message = "商品名字不能为空")
-    private String spuName;
-    /**
-     * 商品图片
-     */
-    @NotEmpty(message = "商品图片不能为空")
-    private String picUrl;
-    /**
-     * 拼团商品单价
-     */
+
     @NotNull(message = "拼团商品单价不能为空")
     private Integer combinationPrice;
-    /**
-     * 用户昵称
-     */
-    @NotEmpty(message = "用户昵称不能为空")
-    private String nickname;
-    /**
-     * 用户头像
-     */
-    @NotEmpty(message = "用户头像不能为空")
-    private String avatar;
-    /**
-     * 开团状态:正在开团 拼团成功 拼团失败
-     */
-    @NotNull(message = "开团状态不能为空")
-    private Integer status;
 
 }

+ 14 - 24
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java

@@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.seckill.dto;
 
 import lombok.Data;
 
-import java.util.List;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
 
 /**
  * 更新秒杀库存 request DTO
@@ -12,37 +13,26 @@ import java.util.List;
 @Data
 public class SeckillActivityUpdateStockReqDTO {
 
-    // TODO @puhui999:参数校验
-
-    // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈;
-
-    /**
-     * 活动编号
-     */
+    @NotNull(message = "活动编号不能为空")
     private Long activityId;
-    /**
-     * 总购买数量
-     */
+
+    @NotNull(message = "购买数量不能为空")
     private Integer count;
-    /**
-     * 活动商品
-     */
-    private List<Item> items;
+
+    @NotNull(message = "活动商品不能为空")
+    private Item item;
 
     @Data
+    @Valid
     public static class Item {
 
-        /**
-         * SPU 编号
-         */
+        @NotNull(message = "SPU 编号不能为空")
         private Long spuId;
-        /**
-         * SKU 编号
-         */
+
+        @NotNull(message = "SKU 编号活动商品不能为空")
         private Long skuId;
-        /**
-         * 购买数量
-         */
+
+        @NotNull(message = "购买数量不能为空")
         private Integer count;
 
     }

+ 12 - 10
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -55,7 +55,7 @@ public interface ErrorCodeConstants {
     ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
     ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
     ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
-    ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
+    ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
 
     // ========== 秒杀时段 1013009000 ==========
     ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
@@ -65,24 +65,26 @@ public interface ErrorCodeConstants {
     // ========== 拼团活动 1013010000 ==========
     ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
     ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
-    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
+    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
     ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
-    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
+    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
 
     // ========== 拼团记录 1013011000 ==========
-    ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");
-    ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");
-    ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");
-    ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");
-    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");
-    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");
-    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出");
+    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
+    ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
+    ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
+    ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
+    ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
+    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束");
+    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
+    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
 
     // ========== 砍价活动 1013012000 ==========
     ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
     ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
     ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
     ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
+    ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足");
 
     // ========== 砍价记录 1013013000 ==========
     ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");

+ 5 - 0
yudao-module-mall/yudao-module-promotion-biz/pom.xml

@@ -29,6 +29,11 @@
             <artifactId>yudao-module-product-api</artifactId>
             <version>${revision}</version>
         </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-trade-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-module-member-api</artifactId>

+ 2 - 19
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java

@@ -1,15 +1,10 @@
 package cn.iocoder.yudao.module.promotion.api.bargain;
 
-import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
-
 /**
  * 砍价活动 Api 接口实现类
  *
@@ -22,20 +17,8 @@ public class BargainActivityApiImpl implements BargainActivityApi {
     private BargainActivityService bargainActivityService;
 
     @Override
-    public void updateBargainActivityStock(Long activityId, Integer count) {
-        // TODO @puhui999:可以整个实现到 bargainActivityService 中
-        // 查询砍价活动
-        BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
-        if (activity == null) {
-            throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
-        }
-
-        // 更新砍价库存
-        // TODO @puhui999:考虑下并发更新问题
-        BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
-        reqVO.setId(activityId);
-        reqVO.setStock(activity.getStock() - count);
-        bargainActivityService.updateBargainActivity(reqVO);
+    public void updateBargainActivityStock(Long id, Integer count) {
+        bargainActivityService.updateBargainActivityStock(id, count);
     }
 
 }

+ 23 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
+
+import javax.annotation.Resource;
+
+/**
+ * 拼团活动 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+public class CombinationApiImpl implements CombinationApi {
+
+    @Resource
+    private CombinationActivityService activityService;
+
+    @Override
+    public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
+        activityService.validateCombination(reqDTO);
+    }
+
+}

+ 1 - 60
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java

@@ -1,20 +1,10 @@
 package cn.iocoder.yudao.module.promotion.api.seckill;
 
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
 
 /**
  * 秒杀活动接口 Api 接口实现类
@@ -27,58 +17,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
     @Resource
     private SeckillActivityService activityService;
 
-    // TODO @puhui:建议这块弄到 activityService 实现哈;
-    // TODO @puhui:这个方法,要考虑事务性
     @Override
     public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
-        // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈;
-        SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
-        if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
-            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
-        }
-        // 获取活动商品
-        // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈;
-        List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
-        // TODO @puhui999:这个是不是搞成  CollectionUtils.convertMultiMap()
-        List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
-        Map<Long, List<Long>> map = new HashMap<>();
-        items.forEach(item -> {
-            if (map.containsKey(item.getSpuId())) {
-                List<Long> skuIds = map.get(item.getSpuId());
-                skuIds.add(item.getSkuId());
-                map.put(item.getSpuId(), skuIds);
-            } else {
-                List<Long> list = new ArrayList<>();
-                list.add(item.getSkuId());
-                map.put(item.getSpuId(), list);
-            }
-        });
-        // 过滤出购买的商品
-        // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里;
-        List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
-        Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
-        // 检查活动商品库存是否充足
-        // TODO @puhui999:避免 b 这种无业务含义的变量;
-        boolean b = CollectionUtils.anyMatch(productDOList, item -> {
-            SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
-            return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
-        });
-        if (b) {
-            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
-        }
-        // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起;
-        List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
-            item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
-            return item;
-        });
-
-        // 更新活动库存
-        // TODO @puhui999:考虑下并发更新
-        seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
-        seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
-        activityService.updateSeckillActivity(seckillActivity);
-        // 更新活动商品库存
-        activityService.updateSeckillActivityProductList(doList);
+        activityService.updateSeckillStock(updateStockReqDTO);
     }
 
 }

+ 15 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
@@ -28,4 +29,18 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
         return selectList(BargainActivityDO::getStatus, status);
     }
 
+    /**
+     * 更新活动库存
+     *
+     * @param id    活动编号
+     * @param count 扣减的库存数量
+     * @return 影响的行数
+     */
+    default int updateActivityStock(Long id, int count) {
+        return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
+                .eq(BargainActivityDO::getId, id)
+                .gt(BargainActivityDO::getStock, 0)
+                .setSql("stock = stock - " + count));
+    }
+
 }

+ 16 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
@@ -32,4 +33,19 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
                 .eqIfPresent(SeckillActivityDO::getStatus, status));
     }
 
+    /**
+     * 更新活动库存
+     *
+     * @param id    活动编号
+     * @param count 扣减的库存数量
+     * @return 影响的行数
+     */
+    default int updateActivityStock(Long id, int count) {
+        return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
+                .eq(SeckillActivityDO::getId, id)
+                .gt(SeckillActivityDO::getTotalStock, 0)
+                .setSql("stock = stock + " + count)
+                .setSql("totalStock = totalStock - " + count));
+    }
+
 }

+ 15 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
@@ -23,4 +24,18 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
         return selectList(SeckillProductDO::getActivityId, ids);
     }
 
+    /**
+     * 更新活动库存
+     *
+     * @param id    活动编号
+     * @param count 扣减的库存数量
+     * @return 影响的行数
+     */
+    default int updateActivityStock(Long id, int count) {
+        return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
+                .eq(SeckillProductDO::getId, id)
+                .gt(SeckillProductDO::getStock, 0)
+                .setSql("stock = stock - " + count));
+    }
+
 }

+ 8 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java

@@ -30,6 +30,14 @@ public interface BargainActivityService {
      */
     void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
 
+    /**
+     * 更新砍价活动库存
+     *
+     * @param id    砍价活动编号
+     * @param count 购买数量
+     */
+    void updateBargainActivityStock(Long id, Integer count);
+
     /**
      * 删除砍价活动
      *
@@ -53,5 +61,4 @@ public interface BargainActivityService {
      */
     PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
 
-
 }

+ 18 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java

@@ -39,6 +39,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
     private ProductSkuApi productSkuApi;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
         // 校验商品 SPU 是否存在是否参加的别的活动
         validateBargainConflict(createReqVO.getSpuId(), null);
@@ -53,6 +54,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
         // 校验存在
         BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
@@ -70,6 +72,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
         bargainActivityMapper.updateById(updateObj);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateBargainActivityStock(Long id, Integer count) {
+        // 查询砍价活动
+        BargainActivityDO activity = getBargainActivity(id);
+        if (activity == null) {
+            throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
+        }
+
+        // 更新砍价库存
+        int row = bargainActivityMapper.updateActivityStock(id, count);
+        if (row == 0) {
+            throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+    }
+
     private void validateBargainConflict(Long spuId, Long activityId) {
         // 查询所有开启的砍价活动
         List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());

+ 8 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -72,4 +73,11 @@ public interface CombinationActivityService {
      */
     List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
 
+    /**
+     * 更新拼图活动库存
+     *
+     * @param reqDTO 请求
+     */
+    void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
+
 }

+ 38 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -16,8 +17,11 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
+import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -28,8 +32,8 @@ import java.util.List;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@@ -48,11 +52,15 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
     private CombinationActivityMapper combinationActivityMapper;
     @Resource
     private CombinationProductMapper combinationProductMapper;
+    @Resource
+    private CombinationRecordService combinationRecordService;
 
     @Resource
     private ProductSpuApi productSpuApi;
     @Resource
     private ProductSkuApi productSkuApi;
+    @Resource
+    private TradeOrderApi tradeOrderApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -97,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
      * 校验拼团商品是否都存在
      *
      * @param spuId 商品 SPU 编号
-     * @param products 秒杀商品
+     * @param products 拼团商品
      */
     private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
         // 1. 校验商品 spu 是否存在
@@ -123,7 +131,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
         // 校验状态
         if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
-            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE);
         }
         // 校验商品冲突
         validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
@@ -205,4 +213,30 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         return combinationProductMapper.selectListByActivityIds(activityIds);
     }
 
+    @Override
+    public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
+        // 1、校验拼团活动是否存在
+        CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
+        // 1.1、校验活动是否开启
+        if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+        }
+        // 1.2、校验是否超出单次限购数量
+        if (activity.getSingleLimitCount() < reqDTO.getCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
+        }
+        // 1.3、校验是否超出总限购数量
+        List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(getLoginUserId(), reqDTO.getActivityId());
+        if (CollUtil.isNotEmpty(recordList)) {
+            // 过滤出拼团成功的
+            List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
+                    item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
+            Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList, CombinationRecordDO::getOrderId,
+                    item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
+            if (activity.getTotalLimitCount() < countSum) {
+                throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
+            }
+        }
+    }
+
 }

+ 26 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java

@@ -2,12 +2,19 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -32,10 +39,18 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
 
     @Resource
     private CombinationActivityService combinationActivityService;
-
     @Resource
     private CombinationRecordMapper recordMapper;
 
+    @Resource
+    private MemberUserApi memberUserApi;
+    @Resource
+    @Lazy
+    private ProductSpuApi productSpuApi;
+    @Resource
+    @Lazy
+    private ProductSkuApi productSkuApi;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
@@ -102,12 +117,12 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         // 1.5 父拼团是否存在,是否已经满了
         if (reqDTO.getHeadId() != null) {
             // 查询进行中的父拼团
-            CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
-            if (recordDO1 == null) {
+            CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+            if (record == null) {
                 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
             }
             // 校验拼团是否满足要求
-            if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
+            if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
                 throw exception(COMBINATION_RECORD_USER_FULL);
             }
         }
@@ -117,6 +132,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         record.setVirtualGroup(false);
         record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
         record.setUserSize(activity.getUserSize());
+        MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
+        record.setNickname(user.getNickname());
+        record.setAvatar(user.getAvatar());
+        ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
+        record.setSpuName(spu.getName());
+        ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
+        record.setPicUrl(sku.getPicUrl());
         recordMapper.insert(record);
     }
 

+ 7 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.service.seckill;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@@ -40,6 +41,12 @@ public interface SeckillActivityService {
      */
     void updateSeckillActivity(SeckillActivityDO activityDO);
 
+    /**
+     * 更新秒杀库存
+     *
+     * @param updateStockReqDTO 更新信息
+     */
+    void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
     /**
      * 更新秒杀活动商品
      *

+ 34 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java

@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@@ -149,6 +150,39 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         seckillActivityMapper.updateById(activityDO);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
+        // 1、校验秒杀活动是否存在
+        SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
+        // 1.1、校验库存是否充足
+        if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+
+        // 2、获取活动商品
+        List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
+        // 2.1、过滤出购买的商品
+        SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId()));
+        // 2.2、检查活动商品库存是否充足
+        boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0);
+        if (isSufficient) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+
+        // 3、更新活动商品库存
+        int itemRow = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
+        if (itemRow == 0) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+
+        // 4、更新活动库存
+        int row = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
+        if (row == 0) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+    }
+
     @Override
     public void updateSeckillActivityProductList(List<SeckillProductDO> productList) {
         seckillProductMapper.updateBatch(productList);

+ 11 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.trade.api.order;
 
+import java.util.Collection;
+
 /**
  * 订单 API 接口
  *
@@ -16,4 +18,13 @@ public interface TradeOrderApi {
      */
     Long validateOrder(Long userId, Long orderItemId);
 
+    /**
+     * 获取订单项商品购买数量总和
+     *
+     * @param orderIds 订单编号
+     * @param skuIds   sku 编号
+     * @return 订单项商品购买数量总和
+     */
+    Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
+
 }

+ 3 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java

@@ -34,6 +34,9 @@ public interface ErrorCodeConstants {
     ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
     ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
     ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1011000026, "支付订单调价失败,原因:支付订单已付款,不能调价");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1011000027, "支付订单调价失败,原因:价格没有变化");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_NOT_ITEM = new ErrorCode(1011000028, "支付订单调价失败,原因:订单项不存在");
 
     // ========== After Sale 模块 1011000100 ==========
     ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");

+ 6 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java

@@ -6,6 +6,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.util.Collection;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
@@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi {
         return item.getOrderId();
     }
 
+    @Override
+    public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
+        return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
+    }
+
 }

+ 3 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java

@@ -76,10 +76,9 @@ public class TradeAfterSaleController {
     public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
         // 查询订单
         TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
-        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
-//        if (afterSale == null) {
-//            return success(null, AFTER_SALE_NOT_FOUND.getMsg());
-//        }
+        if (afterSale == null) {
+            return success(null);
+        }
 
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());

+ 3 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java

@@ -67,10 +67,9 @@ public class TradeOrderController {
     public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(id);
-        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
-//        if (order == null) {
-//            return success(null, ORDER_NOT_FOUND.getMsg());
-//        }
+        if (order == null) {
+            return success(null);
+        }
 
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);

+ 4 - 8
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java

@@ -31,19 +31,15 @@ public class TradeOrderPageReqVO extends PageParam {
     @Mobile
     private String userMobile;
 
+    @Schema(description = "配送方式", example = "1")
+    private Integer deliveryType;
+
     @Schema(description = "发货物流公司编号", example = "1")
     private Long logisticsId;
 
     @Schema(description = "自提门店编号", example = "[1,2]")
     private List<Long> pickUpStoreIds;
 
-    @Schema(description = "收件人名称", example = "小红")
-    private String receiverName;
-
-    @Schema(description = "收件人手机", example = "1560")
-    @Mobile
-    private String receiverMobile;
-
     @Schema(description = "订单类型", example = "1")
     private Integer type;
 
@@ -61,5 +57,5 @@ public class TradeOrderPageReqVO extends PageParam {
     @Schema(description = "订单来源", example = "10")
     @InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
     private Integer terminal;
-//    TODO 添加配送方式筛选
+
 }

+ 3 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java

@@ -81,10 +81,9 @@ public class AppTradeOrderController {
     public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
-        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
-//        if (order == null) {
-//            return success(null, ORDER_NOT_FOUND.getMsg());
-//        }
+        if (order == null) {
+            return success(null);
+        }
 
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());

+ 34 - 15
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -14,7 +14,9 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@@ -32,6 +34,9 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
+import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import org.mapstruct.Mapper;
@@ -254,21 +259,15 @@ public interface TradeOrderConvert {
     AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
 
     @Mappings({
-            @Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
-            @Mapping(target = "spuId", source = "orderItem.spuId"),
-            @Mapping(target = "skuId", source = "orderItem.skuId"),
-            @Mapping(target = "userId", source = "order.userId"),
-            @Mapping(target = "orderId", source = "order.id"),
-            @Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
-            @Mapping(target = "spuName", source = "orderItem.spuName"),
-            @Mapping(target = "picUrl", source = "orderItem.picUrl"),
-            @Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
-            @Mapping(target = "nickname", source = "user.nickname"),
-            @Mapping(target = "avatar", source = "user.avatar"),
-            @Mapping(target = "status", ignore = true)
+            @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
+            @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
+            @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
+            @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
+            @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
+            @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
+            @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
     })
-    CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
-                                          AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
+    CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
 
     List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
 
@@ -282,6 +281,26 @@ public interface TradeOrderConvert {
         return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
                 .setBasePrice(item.getPayPrice() * item.getCount())
                 .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:标题类似:木晴冰雪成功购买云时代的JVM原理与实战;茫农成功购买深入拆解消息队列47讲
-                .setFirstFixedPrice(sku.getSubCommissionFirstPrice()).setSecondFixedPrice(sku.getSubCommissionSecondPrice());
+                .setFirstFixedPrice(sku.getFirstBrokerageRecord()).getSecondBrokerageRecord(sku.getSecondBrokerageRecord());
     }
+
+    @Mapping(target = "activityId", source = "reqBO.seckillActivityId")
+    SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
+
+    @Mapping(target = "activityId", source = "reqBO.combinationActivityId")
+    CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
+
+    TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
+
+    @Mappings({
+            @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
+            @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
+            @Mapping(target = "spuId", source = "orderItem.spuId"),
+            @Mapping(target = "skuId", source = "orderItem.skuId"),
+            @Mapping(target = "orderId", source = "tradeOrderDO.id"),
+            @Mapping(target = "userId", source = "userId"),
+            @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
+    })
+    TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
+
 }

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java

@@ -29,7 +29,7 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
     default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
         return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
                 .in(TradeOrderItemDO::getOrderId, orderIds)
-                .eq(TradeOrderItemDO::getSkuId, skuIds));
+                .in(TradeOrderItemDO::getSkuId, skuIds));
     }
 
     default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {

+ 2 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java

@@ -27,13 +27,12 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>()
                 .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo())
                 .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId())
+                .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType())
                 .inIfPresent(TradeOrderDO::getUserId, userIds)
-                .likeIfPresent(TradeOrderDO::getReceiverName, reqVO.getReceiverName())
-                .likeIfPresent(TradeOrderDO::getReceiverMobile, reqVO.getReceiverMobile())
                 .eqIfPresent(TradeOrderDO::getType, reqVO.getType())
                 .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus())
                 .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode())
-                .eqIfPresent(TradeOrderDO::getTerminal,reqVO.getTerminal())
+                .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal())
                 .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId())
                 .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds())
                 .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()));

+ 9 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java

@@ -119,4 +119,13 @@ public interface TradeOrderQueryService {
      */
     List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
 
+    /**
+     * 获取订单项商品购买数量总和
+     *
+     * @param orderIds 订单编号
+     * @param skuIds   sku 编号
+     * @return 订单项商品购买数量总和
+     */
+    Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
+
 }

+ 7 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
@@ -167,4 +168,10 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
         return tradeOrderItemMapper.selectListByOrderId(orderIds);
     }
 
+    @Override
+    public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
+        List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
+        return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
+    }
+
 }

+ 69 - 78
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.member.api.address.AddressApi;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
 import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
-import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
-import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@@ -24,15 +22,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
-import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
-import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
-import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
-import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
@@ -53,12 +46,14 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.*;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
-import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
+import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
 import cn.iocoder.yudao.module.trade.service.cart.CartService;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -70,14 +65,13 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
 /**
@@ -96,6 +90,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private TradeOrderItemMapper tradeOrderItemMapper;
     @Resource
     private TradeOrderNoRedisDAO orderNoRedisDAO;
+    @Resource
+    private List<TradeOrderHandler> orderHandlers;
 
     @Resource
     private CartService cartService;
@@ -119,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Resource
     private BargainRecordApi bargainRecordApi;
     @Resource
-    private SeckillActivityApi seckillActivityApi;
-    @Resource
-    private BargainActivityApi bargainActivityApi;
-    @Resource
-    private MemberUserApi memberUserApi;
-    @Resource
     private MemberLevelApi memberLevelApi;
     @Resource
     private MemberPointApi memberPointApi;
@@ -189,7 +179,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
-        // 1. 价格计算
+        // 1、执行订单创建前置处理器
+        TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
+        beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
+        beforeOrderCreateReqBO.setCount(CollectionUtils.getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
+        orderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
+
+        // 2. 价格计算
         TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
 
         // 2.1 插入 TradeOrderDO 订单
@@ -199,37 +195,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
         // 3. 订单创建完后的逻辑
         afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
-        // 3.1 拼团的特殊逻辑
-        // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
-        // 拼团
-        if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
-            createCombinationRecord(userId, createReqVO, orderItems, order);
-        }
-        // 3.2 秒杀的特殊逻辑
-        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
-
-        }
-        // 3.3 砍价的特殊逻辑
 
         // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
         return order;
     }
 
-    private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
-        MemberUserRespDTO user = memberUserApi.getUser(userId);
-        List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
-        // TODO 拼团一次应该只能选择一种规格的商品
-        TradeOrderItemDO orderItemDO = orderItems.get(0);
-        if (CollUtil.isNotEmpty(recordRespDTOS)) {
-            List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
-            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
-                    CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
-            combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
-                    CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
-        }
-
-        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
-    }
 
     // TODO @puhui999:订单超时,自动取消;
 
@@ -311,23 +281,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
                                        TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
                                        TradePriceCalculateRespBO calculateRespBO) {
-        Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
-        // 1)如果是秒杀商品:额外扣减秒杀的库存;
-        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
-            SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
-            updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
-            updateStockReqDTO.setCount(count);
-            updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
-                SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
-                item1.setSpuId(item.getSpuId());
-                item1.setSkuId(item.getSkuId());
-                item1.setCount(item.getCount());
-                return item1;
-            }));
-            seckillActivityApi.updateSeckillStock(updateStockReqDTO);
-        }
-        // 2)如果是砍价活动:额外扣减砍价的库存;
-        bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
+        // 执行订单创建后置处理器
+        orderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
         // 扣减积分 TODO 芋艿:待实现,需要前置;
         // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
 
@@ -352,6 +307,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 增加订单日志 TODO 芋艿:待实现
     }
 
+
     private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
         // 创建支付单,用于后续的支付
         PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
@@ -562,35 +518,67 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     }
 
     @Override
-    // TODO @puhui999:考虑事务性
+    @Transactional(rollbackFor = Exception.class)
     public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
-        // 校验交易订单
+        // 1、校验交易订单
         TradeOrderDO order = validateOrderExists(reqVO.getId());
         if (order.getPayStatus()) {
             throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
         }
+        // 2、校验订单项
+        List<TradeOrderItemDO> items = tradeOrderItemMapper.selectListByOrderId(order.getId());
+        if (CollUtil.isEmpty(items)) {
+            throw exception(ORDER_UPDATE_PRICE_FAIL_NOT_ITEM);
+        }
+        // 3、校验调价金额是否变化
         if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
             throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
         }
 
-        // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
-        List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        // TradeOrderItemDO 需要做 adjustPrice 的分摊
-        int price = reqVO.getAdjustPrice() / itemDOs.size();
-        itemDOs.forEach(item -> {
-            item.setAdjustPrice(price);
-        });
-        // 更新 TradeOrderItem
-        // TODO @puhui999:不要整个对象去更新哈;应该 new 一下;
-        tradeOrderItemMapper.updateBatch(itemDOs);
-        // 更新订单
-        // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格;
-        TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
-        update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
+        // 4、更新订单
+        TradeOrderDO update = new TradeOrderDO();
+        update.setId(order.getId());
+        update.setAdjustPrice(reqVO.getAdjustPrice());
+        int orderPayPrice = order.getAdjustPrice() != null ? (order.getPayPrice() - order.getAdjustPrice())
+                + reqVO.getAdjustPrice() : order.getPayPrice() + reqVO.getAdjustPrice();
+        update.setPayPrice(orderPayPrice);
         // TODO @芋艿:改价时,赠送的积分,要不要做改动???
         tradeOrderMapper.updateById(update);
-        // 更新支付订单
-        payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
+
+        // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
+        // TODO:先按 adjustPrice 实现,没明白 payPrice 怎么搞哈哈哈
+        // 5、更新 TradeOrderItem
+        if (items.size() > 1) {
+            // TradeOrderItemDO 需要做 adjustPrice 的分摊
+            int price = reqVO.getAdjustPrice() / items.size();
+            int remainderPrice = reqVO.getAdjustPrice() % items.size();
+            List<TradeOrderItemDO> orders = new ArrayList<>();
+            for (int i = 0; i < items.size(); i++) {
+                // 把平摊后剩余的金额加到第一个订单项
+                if (remainderPrice != 0 && i == 0) {
+                    orders.add(convertOrderItemPrice(items.get(i), price + remainderPrice));
+                }
+                orders.add(convertOrderItemPrice(items.get(i), price));
+            }
+            tradeOrderItemMapper.updateBatch(orders);
+        } else {
+            TradeOrderItemDO orderItem = items.get(0);
+            TradeOrderItemDO updateItem = convertOrderItemPrice(orderItem, reqVO.getAdjustPrice());
+            tradeOrderItemMapper.updateById(updateItem);
+        }
+
+        // 6、更新支付订单
+        payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice());
+    }
+
+    private TradeOrderItemDO convertOrderItemPrice(TradeOrderItemDO orderItem, Integer price) {
+        TradeOrderItemDO newOrderItem = new TradeOrderItemDO();
+        newOrderItem.setId(orderItem.getId());
+        newOrderItem.setAdjustPrice(price);
+        int payPrice = orderItem.getAdjustPrice() != null ? (orderItem.getPayPrice() - orderItem.getAdjustPrice())
+                + price : orderItem.getPayPrice() + price;
+        newOrderItem.setPayPrice(payPrice);
+        return newOrderItem;
     }
 
     @Override
@@ -733,6 +721,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
         }
 
+        // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
+        orderHandlers.forEach(handler -> handler.rollbackStock());
+
         // 2.回滚库存
         List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
         productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));

+ 39 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.trade.service.order.bo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 订单创建之后 Request BO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeAfterOrderCreateReqBO {
+
+    // ========== 拼团活动相关字段 ==========
+
+    @Schema(description = "拼团活动编号", example = "1024")
+    private Long combinationActivityId;
+
+    @Schema(description = "拼团团长编号", example = "2048")
+    private Long combinationHeadId;
+
+    @NotNull(message = "SPU 编号不能为空")
+    private Long spuId;
+
+    @NotNull(message = "SKU 编号活动商品不能为空")
+    private Long skuId;
+
+    @NotNull(message = "订单编号不能为空")
+    private Long orderId;
+
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
+    @NotNull(message = "支付金额不能为空")
+    private Integer payPrice;
+
+}

+ 57 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java

@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.trade.service.order.bo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 订单创建之前 Request BO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeBeforeOrderCreateReqBO {
+
+    @NotNull(message = "订单类型不能为空")
+    private Integer orderType;
+
+    // ========== 秒杀活动相关字段 ==========
+
+    @Schema(description = "秒杀活动编号", example = "1024")
+    private Long seckillActivityId;
+
+    // ========== 拼团活动相关字段 ==========
+
+    @Schema(description = "拼团活动编号", example = "1024")
+    private Long combinationActivityId;
+
+    @Schema(description = "拼团团长编号", example = "2048")
+    private Long combinationHeadId;
+
+    @Schema(description = "砍价活动编号", example = "123")
+    private Long bargainActivityId;
+
+    @NotNull(message = "购买数量不能为空")
+    private Integer count;
+
+    @NotNull(message = "活动商品不能为空")
+    private Item item;
+
+    @Data
+    @Valid
+    public static class Item {
+
+        @NotNull(message = "SPU 编号不能为空")
+        private Long spuId;
+
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
+
+}

+ 44 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 砍价订单 handler 实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeBargainHandler implements TradeOrderHandler {
+
+    @Resource
+    private BargainActivityApi bargainActivityApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是秒杀订单
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        // 额外扣减砍价的库存
+        bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}

+ 49 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
+import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 拼团订单 handler 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeCombinationHandler implements TradeOrderHandler {
+
+    @Resource
+    private CombinationApi combinationApi;
+    @Resource
+    private CombinationRecordApi combinationRecordApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是拼团订单;
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        // 校验是否满足拼团活动相关限制
+        combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+        // 创建砍价记录
+        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}

+ 32 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+
+/**
+ * 订单活动特殊逻辑处理器 handler 接口
+ *
+ * @author HUIHUI
+ */
+public interface TradeOrderHandler {
+
+    /**
+     * 订单创建前
+     *
+     * @param reqBO 请求
+     */
+    void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO);
+
+    /**
+     * 订单创建后
+     *
+     * @param reqBO 请求
+     */
+    void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
+
+    /**
+     * 回滚活动相关库存
+     */
+    void rollbackStock();
+
+}

+ 44 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 秒杀订单 handler 实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeSeckillHandler implements TradeOrderHandler {
+
+    @Resource
+    private SeckillActivityApi seckillActivityApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是秒杀订单:额外扣减秒杀的库存;
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}

+ 2 - 3
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java

@@ -29,13 +29,12 @@ public interface PayOrderApi {
      */
     PayOrderRespDTO getOrder(Long id);
 
-    // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id;
     /**
      * 更新支付订单价格
      *
-     * @param payOrderId 支付单编号
+     * @param id 支付单编号
      * @param payPrice   支付单价格
      */
-    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
+    void updatePayOrderPrice(Long id, Integer payPrice);
 
 }

+ 9 - 11
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java

@@ -21,19 +21,17 @@ public interface ErrorCodeConstants {
     ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
 
     // ========== ORDER 模块 1007002000 ==========
-    ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
-    ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
-    ErrorCode ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
-    ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
-    ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
-    ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
-    ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
-    ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
+    ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
+    ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
+    ErrorCode PAY_ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
+    ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
+    ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
+    ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
 
     // ========== ORDER 模块(拓展单) 1007003000 ==========
-    ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
-    ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
-    ErrorCode ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
+    ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
+    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
+    ErrorCode PAY_ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
 
     // ========== 支付模块(退款) 1007006000 ==========
     ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java

@@ -32,8 +32,8 @@ public class PayOrderApiImpl implements PayOrderApi {
     }
 
     @Override
-    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
-        payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
+    public void updatePayOrderPrice(Long id, Integer payPrice) {
+        payOrderService.updatePayOrderPrice(id, payPrice);
     }
 
 }

+ 3 - 3
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java

@@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
 
 /**
@@ -98,8 +98,8 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
         PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         // 支付交易拓展单不存在, 返回关闭状态
         if (orderExtension == null) {
-            return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
-                    ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
+            return PayOrderRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()),
+                    PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
         }
         // 关闭状态
         if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java

@@ -25,7 +25,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
-import static cn.hutool.core.util.ObjectUtil.*;
+import static cn.hutool.core.util.ObjectUtil.notEqual;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
@@ -156,7 +156,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
         if (payOrder == null) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
         }
         // 2.2 校验支付单已支付
         if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java

@@ -101,10 +101,10 @@ public interface PayOrderService {
     /**
      * 更新支付订单价格
      *
-     * @param payOrderId 支付单编号
+     * @param id 支付单编号
      * @param payPrice   支付单价格
      */
-    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
+    void updatePayOrderPrice(Long id, Integer payPrice);
 
     /**
      * 获得支付订单

+ 35 - 29
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -160,7 +160,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             getSelf().notifyOrder(channel, unifiedOrderResp);
             // 如有渠道错误码,则抛出业务异常,提示用户
             if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
-                throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
+                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
                         unifiedOrderResp.getChannelErrorMsg());
             }
             // 此处需要读取最新的状态
@@ -172,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService {
     private PayOrderDO validateOrderCanSubmit(Long id) {
         PayOrderDO order = orderMapper.selectById(id);
         if (order == null) { // 是否存在
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付
-            throw exception(ORDER_STATUS_IS_SUCCESS);
+            throw exception(PAY_ORDER_STATUS_IS_SUCCESS);
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw exception(ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
-            throw exception(ORDER_IS_EXPIRED);
+            throw exception(PAY_ORDER_IS_EXPIRED);
         }
 
         // 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常
@@ -202,7 +202,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
                 log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]",
                         id, orderExtension.getId());
-                throw exception(ORDER_EXTENSION_IS_PAID);
+                throw exception(PAY_ORDER_EXTENSION_IS_PAID);
             }
             // 情况二:调用三方接口,查询支付单状态,是不是已支付
             PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId());
@@ -214,7 +214,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) {
                 log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]",
                         id, toJsonString(respDTO));
-                throw exception(ORDER_EXTENSION_IS_PAID);
+                throw exception(PAY_ORDER_EXTENSION_IS_PAID);
             }
         });
     }
@@ -254,9 +254,10 @@ public class PayOrderServiceImpl implements PayOrderService {
      * 通知并更新订单的支付结果
      *
      * @param channel 支付渠道
-     * @param notify 通知
+     * @param notify  通知
      */
-    @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
+    @Transactional(rollbackFor = Exception.class)
+    // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
     public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
         // 情况一:支付成功的回调
         if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
@@ -295,21 +296,21 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 1. 查询 PayOrderExtensionDO
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
         if (orderExtension == null) {
-            throw exception(ORDER_EXTENSION_NOT_FOUND);
+            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
             log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId());
             return orderExtension;
         }
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
-            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderExtensionDO
         int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
                 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId());
         return orderExtension;
@@ -318,17 +319,17 @@ public class PayOrderServiceImpl implements PayOrderService {
     /**
      * 更新 PayOrderDO 支付成功
      *
-     * @param channel 支付渠道
+     * @param channel        支付渠道
      * @param orderExtension 支付拓展单
-     * @param notify 通知回调
+     * @param notify         通知回调
      * @return 是否之前已经成功回调
      */
     private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
-                                                         PayOrderRespDTO notify) {
+                                       PayOrderRespDTO notify) {
         // 1. 判断 PayOrderDO 是否处于待支付
         PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
         if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
                 && Objects.equals(order.getExtensionId(), orderExtension.getId())) {
@@ -336,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             return true;
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw exception(ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderDO
@@ -346,10 +347,10 @@ public class PayOrderServiceImpl implements PayOrderService {
                         .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
                         .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
                         .channelFeeRate(channel.getFeeRate())
-		                .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
+                        .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
                         .build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
         return false;
@@ -363,7 +364,7 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 1. 查询 PayOrderExtensionDO
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
         if (orderExtension == null) {
-            throw exception(ORDER_EXTENSION_NOT_FOUND);
+            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
             log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId());
@@ -375,7 +376,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             return;
         }
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
-            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderExtensionDO
@@ -383,7 +384,7 @@ public class PayOrderServiceImpl implements PayOrderService {
                 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
                         .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId());
     }
@@ -392,10 +393,10 @@ public class PayOrderServiceImpl implements PayOrderService {
     public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
         PayOrderDO order = orderMapper.selectById(id);
         if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
         }
         if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
-            throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
+            throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
         }
         if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
             throw exception(REFUND_PRICE_EXCEED);
@@ -407,16 +408,21 @@ public class PayOrderServiceImpl implements PayOrderService {
                 .setStatus(PayOrderStatusEnum.REFUND.getStatus());
         int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
         if (updateCount == 0) {
-            throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
+            throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
         }
     }
 
     @Override
-    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
-        // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈;
-        PayOrderDO order = orderMapper.selectById(payOrderId);
+    public void updatePayOrderPrice(Long id, Integer payPrice) {
+        PayOrderDO order = orderMapper.selectById(id);
         if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
+        }
+        if (ObjectUtil.notEqual(PayOrderStatusEnum.WAITING.getStatus(), order.getStatus())) {
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+        }
+        if (ObjectUtil.equal(order.getPrice(), payPrice)) {
+            return;
         }
 
         order.setPrice(payPrice);

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java

@@ -160,11 +160,11 @@ public class PayRefundServiceImpl implements PayRefundService {
     private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
         PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
         if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
+            throw exception(PAY_ORDER_NOT_FOUND);
         }
         // 校验状态,必须是已支付、或者已退款
         if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
-            throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
+            throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
         }
 
         // 校验金额,退款金额不能大于原定的金额

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java

@@ -61,7 +61,7 @@ public class PayWalletServiceImpl implements  PayWalletService {
         // 1. 判断支付交易拓展单是否存
         PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         if (orderExtension == null) {
-            throw exception(ORDER_EXTENSION_NOT_FOUND);
+            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
         }
         // 2. 扣减余额
         return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);

+ 15 - 15
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java

@@ -261,7 +261,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
         String userIp = randomString();
 
         // 调用, 并断言异常
-        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_NOT_FOUND);
     }
 
     @Test
@@ -274,7 +274,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
         String userIp = randomString();
 
         // 调用, 并断言异常
-        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_NOT_WAITING);
     }
 
     @Test
@@ -287,7 +287,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
         String userIp = randomString();
 
         // 调用, 并断言异常
-        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_SUCCESS);
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_SUCCESS);
     }
 
     @Test
@@ -301,7 +301,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
         String userIp = randomString();
 
         // 调用, 并断言异常
-        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_IS_EXPIRED);
     }
 
     @Test
@@ -366,7 +366,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
             // 调用,并断言异常
             assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
-                    ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
+                    PAY_ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
             // 断言,数据记录(PayOrderExtensionDO)
             PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
             assertNotNull(orderExtension);
@@ -450,7 +450,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
-                ORDER_EXTENSION_IS_PAID);
+                PAY_ORDER_EXTENSION_IS_PAID);
     }
 
     @Test
@@ -469,7 +469,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
-                ORDER_EXTENSION_IS_PAID);
+                PAY_ORDER_EXTENSION_IS_PAID);
     }
 
     @Test
@@ -519,7 +519,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_EXTENSION_NOT_FOUND);
+                PAY_ORDER_EXTENSION_NOT_FOUND);
     }
 
     @Test
@@ -537,7 +537,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+                PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
     }
 
     @Test
@@ -555,7 +555,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_NOT_FOUND);
+                PAY_ORDER_NOT_FOUND);
         // 断言 PayOrderExtensionDO :数据更新被回滚
         assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
     }
@@ -588,7 +588,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_STATUS_IS_NOT_WAITING);
+                PAY_ORDER_STATUS_IS_NOT_WAITING);
         // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
         assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
     }
@@ -673,7 +673,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_EXTENSION_NOT_FOUND);
+                PAY_ORDER_EXTENSION_NOT_FOUND);
     }
 
     @Test
@@ -729,7 +729,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.notifyOrder(channel, notify),
-                ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+                PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
     }
 
     @Test
@@ -762,7 +762,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
-                ORDER_NOT_FOUND);
+                PAY_ORDER_NOT_FOUND);
     }
 
     @Test
@@ -786,7 +786,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
-                ORDER_REFUND_FAIL_STATUS_ERROR);
+                PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
     }
 
     @Test

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java

@@ -219,7 +219,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> refundService.createPayRefund(reqDTO),
-                ORDER_NOT_FOUND);
+                PAY_ORDER_NOT_FOUND);
     }
 
     @Test
@@ -245,7 +245,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 
         // 调用,并断言异常
         assertServiceException(() -> refundService.createPayRefund(reqDTO),
-                ORDER_REFUND_FAIL_STATUS_ERROR);
+                PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
     }
 
     @Test