Commit 73e4976ae4fd81dc277bfd1725bf2c89b8003d36

Authored by owen
2 parents 2c821d2b ebd4ea54

Merge remote-tracking branch 'origin/feature/mall_product' into brokerate

Showing 84 changed files with 1631 additions and 446 deletions
sql/mysql/pay_wallet.sql
@@ -4,18 +4,18 @@ @@ -4,18 +4,18 @@
4 DROP TABLE IF EXISTS `pay_wallet`; 4 DROP TABLE IF EXISTS `pay_wallet`;
5 CREATE TABLE `pay_wallet` 5 CREATE TABLE `pay_wallet`
6 ( 6 (
7 - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',  
8 - `user_id` bigint NOT NULL COMMENT '用户编号',  
9 - `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型',  
10 - `balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分',  
11 - `total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',  
12 - `total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',  
13 - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',  
14 - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',  
15 - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',  
16 - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',  
17 - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',  
18 - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 7 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  8 + `user_id` bigint NOT NULL COMMENT '用户编号',
  9 + `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型',
  10 + `balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分',
  11 + `total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',
  12 + `total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',
  13 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  14 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  15 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  16 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  17 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  18 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
19 PRIMARY KEY (`id`) USING BTREE 19 PRIMARY KEY (`id`) USING BTREE
20 ) ENGINE=InnoDB COMMENT='会员钱包表'; 20 ) ENGINE=InnoDB COMMENT='会员钱包表';
21 21
@@ -41,3 +41,33 @@ CREATE TABLE `pay_wallet_transaction` @@ -41,3 +41,33 @@ CREATE TABLE `pay_wallet_transaction`
41 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 41 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
42 PRIMARY KEY (`id`) USING BTREE 42 PRIMARY KEY (`id`) USING BTREE
43 ) ENGINE=InnoDB COMMENT='会员钱包流水表'; 43 ) ENGINE=InnoDB COMMENT='会员钱包流水表';
  44 +
  45 +-- ----------------------------
  46 +-- 会员钱包充值
  47 +-- ----------------------------
  48 +DROP TABLE IF EXISTS `pay_wallet_recharge`;
  49 +CREATE TABLE `pay_wallet_recharge`
  50 +(
  51 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  52 + `wallet_id` bigint NOT NULL COMMENT '会员钱包 id',
  53 + `price` int NOT NULL COMMENT '用户实际到账余额,例如充 100 送 20,则该值是 120',
  54 + `pay_price` int NOT NULL COMMENT '实际支付金额',
  55 + `wallet_bonus` int NOT NULL COMMENT '钱包赠送金额',
  56 + `pay_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]',
  57 + `pay_order_id` bigint NULL COMMENT '支付订单编号',
  58 + `pay_channel_code` varchar(16) NULL COMMENT '支付成功的支付渠道',
  59 + `pay_time` datetime NULL COMMENT '订单支付时间',
  60 + `pay_refund_id` bigint NULL COMMENT '支付退款单编号',
  61 + `refund_price` int NOT NULL DEFAULT 0 COMMENT '退款金额,包含赠送金额',
  62 + `refund_pay_price` int NOT NULL DEFAULT 0 COMMENT '退款支付金额',
  63 + `refund_wallet_bonus` int NOT NULL DEFAULT 0 COMMENT '退款钱包赠送金额',
  64 + `refund_time` datetime NULL COMMENT '退款时间',
  65 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  66 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  67 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  68 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  69 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  70 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  71 + PRIMARY KEY (`id`) USING BTREE
  72 +) ENGINE=InnoDB COMMENT='会员钱包充值';
  73 +
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
@@ -59,15 +59,14 @@ public class ProductSkuRespDTO { @@ -59,15 +59,14 @@ public class ProductSkuRespDTO {
59 * 商品体积,单位:m^3 平米 59 * 商品体积,单位:m^3 平米
60 */ 60 */
61 private Double volume; 61 private Double volume;
62 -  
63 - // TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致; 62 + // TODO @puhui999:firstBrokeragePrice ;尴尬,我当时打错了;secondBrokeragePrice
64 /** 63 /**
65 * 一级分销的佣金,单位:分 64 * 一级分销的佣金,单位:分
66 */ 65 */
67 - private Integer subCommissionFirstPrice; 66 + private Integer firstBrokerageRecord;
68 /** 67 /**
69 * 二级分销的佣金,单位:分 68 * 二级分销的佣金,单位:分
70 */ 69 */
71 - private Integer subCommissionSecondPrice; 70 + private Integer secondBrokerageRecord;
72 71
73 } 72 }
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 { @@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
51 private Double volume; 51 private Double volume;
52 52
53 @Schema(description = "一级分销的佣金,单位:分", example = "199") 53 @Schema(description = "一级分销的佣金,单位:分", example = "199")
54 - private Integer subCommissionFirstPrice; 54 + private Integer firstBrokerageRecord;
55 55
56 @Schema(description = "二级分销的佣金,单位:分", example = "19") 56 @Schema(description = "二级分销的佣金,单位:分", example = "19")
57 - private Integer subCommissionSecondPrice; 57 + private Integer secondBrokerageRecord;
58 58
59 @Schema(description = "属性数组") 59 @Schema(description = "属性数组")
60 private List<Property> properties; 60 private List<Property> properties;
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 { @@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
81 /** 81 /**
82 * 一级分销的佣金,单位:分 82 * 一级分销的佣金,单位:分
83 */ 83 */
84 - private Integer subCommissionFirstPrice; 84 + private Integer firstBrokerageRecord;
85 /** 85 /**
86 * 二级分销的佣金,单位:分 86 * 二级分销的佣金,单位:分
87 */ 87 */
88 - private Integer subCommissionSecondPrice; 88 + private Integer secondBrokerageRecord;
89 89
90 // ========== 营销相关字段 ========= 90 // ========== 营销相关字段 =========
91 91
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 { @@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
92 o.setMarketPrice(generaInt()); 92 o.setMarketPrice(generaInt());
93 o.setStock(generaInt()); 93 o.setStock(generaInt());
94 o.setWarnStock(10); 94 o.setWarnStock(10);
95 - o.setSubCommissionFirstPrice(generaInt());  
96 - o.setSubCommissionSecondPrice(generaInt()); 95 + o.setFirstBrokerageRecord(generaInt());
  96 + o.setSecondBrokerageRecord(generaInt());
97 // 限制分数为两位数 97 // 限制分数为两位数
98 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); 98 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
99 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); 99 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
@@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { @@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
143 o.setMarketPrice(generaInt()); 143 o.setMarketPrice(generaInt());
144 o.setStock(generaInt()); 144 o.setStock(generaInt());
145 o.setWarnStock(10); 145 o.setWarnStock(10);
146 - o.setSubCommissionFirstPrice(generaInt());  
147 - o.setSubCommissionSecondPrice(generaInt()); 146 + o.setFirstBrokerageRecord(generaInt());
  147 + o.setSecondBrokerageRecord(generaInt());
148 // 限制分数为两位数 148 // 限制分数为两位数
149 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); 149 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
150 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); 150 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
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 { @@ -10,9 +10,9 @@ public interface BargainActivityApi {
10 /** 10 /**
11 * 更新砍价活动库存 11 * 更新砍价活动库存
12 * 12 *
13 - * @param activityId 砍价活动编号 13 + * @param id 砍价活动编号
14 * @param count 购买数量 14 * @param count 购买数量
15 */ 15 */
16 - void updateBargainActivityStock(Long activityId, Integer count); 16 + void updateBargainActivityStock(Long id, Integer count);
17 17
18 } 18 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
  4 +
  5 +// TODO @puhui999:是不是改成 CombinationActivityApi
  6 +/**
  7 + * 拼团活动 Api 接口
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +public interface CombinationApi {
  12 +
  13 + /**
  14 + * 更新活动库存
  15 + *
  16 + * @param reqDTO 请求
  17 + */
  18 + // TODO @puhui999:应该是更新哇?还是校验哈;
  19 + void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
  20 +
  21 +}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.Valid;
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * 拼团活动更新活动库存 Request DTO
  10 + *
  11 + * @author HUIHUI
  12 + */
  13 +@Data
  14 +public class CombinationActivityUpdateStockReqDTO {
  15 +
  16 + // TODO @puhui999:是不是一个 activityId、count、skuId 参数就完事啦。
  17 +
  18 + @NotNull(message = "活动编号不能为空")
  19 + private Long activityId;
  20 +
  21 + @NotNull(message = "购买数量不能为空")
  22 + private Integer count;
  23 +
  24 + @NotNull(message = "活动商品不能为空")
  25 + private Item item;
  26 +
  27 + @Data
  28 + @Valid
  29 + public static class Item {
  30 +
  31 + @NotNull(message = "SPU 编号不能为空")
  32 + private Long spuId;
  33 +
  34 + @NotNull(message = "SKU 编号活动商品不能为空")
  35 + private Long skuId;
  36 +
  37 + @NotNull(message = "购买数量不能为空")
  38 + private Integer count;
  39 +
  40 + }
  41 +
  42 +}
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; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.combination.dto;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
5 -import javax.validation.constraints.NotEmpty;  
6 import javax.validation.constraints.NotNull; 5 import javax.validation.constraints.NotNull;
7 6
8 // TODO @芋艿:这块要在看看 7 // TODO @芋艿:这块要在看看
@@ -14,65 +13,27 @@ import javax.validation.constraints.NotNull; @@ -14,65 +13,27 @@ import javax.validation.constraints.NotNull;
14 @Data 13 @Data
15 public class CombinationRecordCreateReqDTO { 14 public class CombinationRecordCreateReqDTO {
16 15
17 - /**  
18 - * 拼团活动编号  
19 - */ 16 + // TODO @puhui999:注释还是要的哈
  17 +
20 @NotNull(message = "拼团活动编号不能为空") 18 @NotNull(message = "拼团活动编号不能为空")
21 private Long activityId; 19 private Long activityId;
22 - /**  
23 - * spu 编号  
24 - */ 20 +
25 @NotNull(message = "spu 编号不能为空") 21 @NotNull(message = "spu 编号不能为空")
26 private Long spuId; 22 private Long spuId;
27 - /**  
28 - * sku 编号  
29 - */ 23 +
30 @NotNull(message = "sku 编号不能为空") 24 @NotNull(message = "sku 编号不能为空")
31 private Long skuId; 25 private Long skuId;
32 - /**  
33 - * 用户编号  
34 - */  
35 - @NotNull(message = "用户编号不能为空")  
36 - private Long userId;  
37 - /**  
38 - * 订单编号  
39 - */ 26 +
40 @NotNull(message = "订单编号不能为空") 27 @NotNull(message = "订单编号不能为空")
41 private Long orderId; 28 private Long orderId;
42 - /**  
43 - * 团长编号  
44 - */ 29 +
  30 + @NotNull(message = "用户编号不能为空")
  31 + private Long userId;
  32 +
45 @NotNull(message = "团长编号不能为空") 33 @NotNull(message = "团长编号不能为空")
46 private Long headId; 34 private Long headId;
47 - /**  
48 - * 商品名字  
49 - */  
50 - @NotEmpty(message = "商品名字不能为空")  
51 - private String spuName;  
52 - /**  
53 - * 商品图片  
54 - */  
55 - @NotEmpty(message = "商品图片不能为空")  
56 - private String picUrl;  
57 - /**  
58 - * 拼团商品单价  
59 - */ 35 +
60 @NotNull(message = "拼团商品单价不能为空") 36 @NotNull(message = "拼团商品单价不能为空")
61 private Integer combinationPrice; 37 private Integer combinationPrice;
62 - /**  
63 - * 用户昵称  
64 - */  
65 - @NotEmpty(message = "用户昵称不能为空")  
66 - private String nickname;  
67 - /**  
68 - * 用户头像  
69 - */  
70 - @NotEmpty(message = "用户头像不能为空")  
71 - private String avatar;  
72 - /**  
73 - * 开团状态:正在开团 拼团成功 拼团失败  
74 - */  
75 - @NotNull(message = "开团状态不能为空")  
76 - private Integer status;  
77 38
78 } 39 }
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; @@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.seckill.dto;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
5 -import java.util.List; 5 +import javax.validation.Valid;
  6 +import javax.validation.constraints.NotNull;
6 7
7 /** 8 /**
8 * 更新秒杀库存 request DTO 9 * 更新秒杀库存 request DTO
@@ -12,37 +13,28 @@ import java.util.List; @@ -12,37 +13,28 @@ import java.util.List;
12 @Data 13 @Data
13 public class SeckillActivityUpdateStockReqDTO { 14 public class SeckillActivityUpdateStockReqDTO {
14 15
15 - // TODO @puhui999:参数校验 16 + // TODO @puhui999:可以不用 dto,直接 activityId、skuId、count 即可
16 17
17 - // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈;  
18 -  
19 - /**  
20 - * 活动编号  
21 - */ 18 + @NotNull(message = "活动编号不能为空")
22 private Long activityId; 19 private Long activityId;
23 - /**  
24 - * 总购买数量  
25 - */ 20 +
  21 + @NotNull(message = "购买数量不能为空")
26 private Integer count; 22 private Integer count;
27 - /**  
28 - * 活动商品  
29 - */  
30 - private List<Item> items; 23 +
  24 + @NotNull(message = "活动商品不能为空")
  25 + private Item item;
31 26
32 @Data 27 @Data
  28 + @Valid
33 public static class Item { 29 public static class Item {
34 30
35 - /**  
36 - * SPU 编号  
37 - */ 31 + @NotNull(message = "SPU 编号不能为空")
38 private Long spuId; 32 private Long spuId;
39 - /**  
40 - * SKU 编号  
41 - */ 33 +
  34 + @NotNull(message = "SKU 编号活动商品不能为空")
42 private Long skuId; 35 private Long skuId;
43 - /**  
44 - * 购买数量  
45 - */ 36 +
  37 + @NotNull(message = "购买数量不能为空")
46 private Integer count; 38 private Integer count;
47 39
48 } 40 }
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 { @@ -55,7 +55,7 @@ public interface ErrorCodeConstants {
55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除"); 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
58 - ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足"); 58 + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
59 59
60 // ========== 秒杀时段 1013009000 ========== 60 // ========== 秒杀时段 1013009000 ==========
61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); 61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
@@ -65,24 +65,26 @@ public interface ErrorCodeConstants { @@ -65,24 +65,26 @@ public interface ErrorCodeConstants {
65 // ========== 拼团活动 1013010000 ========== 65 // ========== 拼团活动 1013010000 ==========
66 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); 66 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
67 ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动"); 67 ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
68 - ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改"); 68 + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
69 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除"); 69 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
70 - ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在"); 70 + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
71 71
72 // ========== 拼团记录 1013011000 ========== 72 // ========== 拼团记录 1013011000 ==========
73 - ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");  
74 - ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");  
75 - ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");  
76 - ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");  
77 - ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");  
78 - ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");  
79 - ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出"); 73 + ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
  74 + ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
  75 + ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
  76 + ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
  77 + ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
  78 + ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束");
  79 + ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
  80 + ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
80 81
81 // ========== 砍价活动 1013012000 ========== 82 // ========== 砍价活动 1013012000 ==========
82 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在"); 83 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
83 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动"); 84 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
84 ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改"); 85 ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
85 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除"); 86 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
  87 + ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足");
86 88
87 // ========== 砍价记录 1013013000 ========== 89 // ========== 砍价记录 1013013000 ==========
88 ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在"); 90 ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");
yudao-module-mall/yudao-module-promotion-biz/pom.xml
@@ -31,6 +31,11 @@ @@ -31,6 +31,11 @@
31 </dependency> 31 </dependency>
32 <dependency> 32 <dependency>
33 <groupId>cn.iocoder.boot</groupId> 33 <groupId>cn.iocoder.boot</groupId>
  34 + <artifactId>yudao-module-trade-api</artifactId>
  35 + <version>${revision}</version>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>cn.iocoder.boot</groupId>
34 <artifactId>yudao-module-member-api</artifactId> 39 <artifactId>yudao-module-member-api</artifactId>
35 <version>${revision}</version> 40 <version>${revision}</version>
36 </dependency> 41 </dependency>
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.bargain; 1 package cn.iocoder.yudao.module.promotion.api.bargain;
2 2
3 -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;  
4 -import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;  
5 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; 3 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
6 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
7 5
8 import javax.annotation.Resource; 6 import javax.annotation.Resource;
9 7
10 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
11 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;  
12 -  
13 /** 8 /**
14 * 砍价活动 Api 接口实现类 9 * 砍价活动 Api 接口实现类
15 * 10 *
@@ -22,20 +17,8 @@ public class BargainActivityApiImpl implements BargainActivityApi { @@ -22,20 +17,8 @@ public class BargainActivityApiImpl implements BargainActivityApi {
22 private BargainActivityService bargainActivityService; 17 private BargainActivityService bargainActivityService;
23 18
24 @Override 19 @Override
25 - public void updateBargainActivityStock(Long activityId, Integer count) {  
26 - // TODO @puhui999:可以整个实现到 bargainActivityService 中  
27 - // 查询砍价活动  
28 - BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);  
29 - if (activity == null) {  
30 - throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);  
31 - }  
32 -  
33 - // 更新砍价库存  
34 - // TODO @puhui999:考虑下并发更新问题  
35 - BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();  
36 - reqVO.setId(activityId);  
37 - reqVO.setStock(activity.getStock() - count);  
38 - bargainActivityService.updateBargainActivity(reqVO); 20 + public void updateBargainActivityStock(Long id, Integer count) {
  21 + bargainActivityService.updateBargainActivityStock(id, count);
39 } 22 }
40 23
41 } 24 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
  5 +import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +/**
  11 + * 拼团活动 Api 接口实现类
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@Service
  16 +@Validated
  17 +public class CombinationApiImpl implements CombinationApi {
  18 +
  19 + @Resource
  20 + private CombinationActivityService activityService;
  21 +
  22 + @Override
  23 + public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
  24 + activityService.validateCombination(reqDTO);
  25 + }
  26 +
  27 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.seckill; 1 package cn.iocoder.yudao.module.promotion.api.seckill;
2 2
3 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
4 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; 3 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
5 -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;  
6 -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;  
7 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; 4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
8 import org.springframework.stereotype.Service; 5 import org.springframework.stereotype.Service;
9 6
10 import javax.annotation.Resource; 7 import javax.annotation.Resource;
11 -import java.util.ArrayList;  
12 -import java.util.HashMap;  
13 -import java.util.List;  
14 -import java.util.Map;  
15 -  
16 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
17 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;  
18 8
19 /** 9 /**
20 * 秒杀活动接口 Api 接口实现类 10 * 秒杀活动接口 Api 接口实现类
@@ -27,58 +17,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi { @@ -27,58 +17,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
27 @Resource 17 @Resource
28 private SeckillActivityService activityService; 18 private SeckillActivityService activityService;
29 19
30 - // TODO @puhui:建议这块弄到 activityService 实现哈;  
31 - // TODO @puhui:这个方法,要考虑事务性  
32 @Override 20 @Override
33 public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { 21 public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
34 - // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈;  
35 - SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());  
36 - if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {  
37 - throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);  
38 - }  
39 - // 获取活动商品  
40 - // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈;  
41 - List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());  
42 - // TODO @puhui999:这个是不是搞成 CollectionUtils.convertMultiMap()  
43 - List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();  
44 - Map<Long, List<Long>> map = new HashMap<>();  
45 - items.forEach(item -> {  
46 - if (map.containsKey(item.getSpuId())) {  
47 - List<Long> skuIds = map.get(item.getSpuId());  
48 - skuIds.add(item.getSkuId());  
49 - map.put(item.getSpuId(), skuIds);  
50 - } else {  
51 - List<Long> list = new ArrayList<>();  
52 - list.add(item.getSkuId());  
53 - map.put(item.getSpuId(), list);  
54 - }  
55 - });  
56 - // 过滤出购买的商品  
57 - // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里;  
58 - List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));  
59 - Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);  
60 - // 检查活动商品库存是否充足  
61 - // TODO @puhui999:避免 b 这种无业务含义的变量;  
62 - boolean b = CollectionUtils.anyMatch(productDOList, item -> {  
63 - SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());  
64 - return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;  
65 - });  
66 - if (b) {  
67 - throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);  
68 - }  
69 - // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起;  
70 - List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {  
71 - item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());  
72 - return item;  
73 - });  
74 -  
75 - // 更新活动库存  
76 - // TODO @puhui999:考虑下并发更新  
77 - seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());  
78 - seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());  
79 - activityService.updateSeckillActivity(seckillActivity);  
80 - // 更新活动商品库存  
81 - activityService.updateSeckillActivityProductList(doList); 22 + activityService.updateSeckillStock(updateStockReqDTO);
82 } 23 }
83 24
84 } 25 }
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; @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
8 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
9 10
10 import java.util.List; 11 import java.util.List;
@@ -28,4 +29,18 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; { @@ -28,4 +29,18 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; {
28 return selectList(BargainActivityDO::getStatus, status); 29 return selectList(BargainActivityDO::getStatus, status);
29 } 30 }
30 31
  32 + /**
  33 + * 更新活动库存
  34 + *
  35 + * @param id 活动编号
  36 + * @param count 扣减的库存数量
  37 + * @return 影响的行数
  38 + */
  39 + default int updateActivityStock(Long id, int count) {
  40 + return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
  41 + .eq(BargainActivityDO::getId, id)
  42 + .gt(BargainActivityDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
  43 + .setSql("stock = stock - " + count));
  44 + }
  45 +
31 } 46 }
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; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
9 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
10 11
11 import java.util.List; 12 import java.util.List;
@@ -32,4 +33,19 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -32,4 +33,19 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
32 .eqIfPresent(SeckillActivityDO::getStatus, status)); 33 .eqIfPresent(SeckillActivityDO::getStatus, status));
33 } 34 }
34 35
  36 + /**
  37 + * 更新活动库存
  38 + *
  39 + * @param id 活动编号
  40 + * @param count 扣减的库存数量
  41 + * @return 影响的行数
  42 + */
  43 + default int updateActivityStock(Long id, int count) {
  44 + return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
  45 + .eq(SeckillActivityDO::getId, id)
  46 + .gt(SeckillActivityDO::getTotalStock, 0)
  47 + .setSql("stock = stock + " + count)
  48 + .setSql("totalStock = totalStock - " + count));
  49 + }
  50 +
35 } 51 }
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; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  5 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
5 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
6 7
7 import java.util.Collection; 8 import java.util.Collection;
@@ -23,4 +24,18 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; { @@ -23,4 +24,18 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; {
23 return selectList(SeckillProductDO::getActivityId, ids); 24 return selectList(SeckillProductDO::getActivityId, ids);
24 } 25 }
25 26
  27 + /**
  28 + * 更新活动库存
  29 + *
  30 + * @param id 活动编号
  31 + * @param count 扣减的库存数量
  32 + * @return 影响的行数
  33 + */
  34 + default int updateActivityStock(Long id, int count) {
  35 + return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
  36 + .eq(SeckillProductDO::getId, id)
  37 + .gt(SeckillProductDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
  38 + .setSql("stock = stock - " + count));
  39 + }
  40 +
26 } 41 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
@@ -31,6 +31,14 @@ public interface BargainActivityService { @@ -31,6 +31,14 @@ public interface BargainActivityService {
31 void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO); 31 void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
32 32
33 /** 33 /**
  34 + * 更新砍价活动库存
  35 + *
  36 + * @param id 砍价活动编号
  37 + * @param count 购买数量
  38 + */
  39 + void updateBargainActivityStock(Long id, Integer count);
  40 +
  41 + /**
34 * 删除砍价活动 42 * 删除砍价活动
35 * 43 *
36 * @param id 编号 44 * @param id 编号
@@ -53,5 +61,4 @@ public interface BargainActivityService { @@ -53,5 +61,4 @@ public interface BargainActivityService {
53 */ 61 */
54 PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO); 62 PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
55 63
56 -  
57 } 64 }
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 { @@ -39,6 +39,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
39 private ProductSkuApi productSkuApi; 39 private ProductSkuApi productSkuApi;
40 40
41 @Override 41 @Override
  42 + @Transactional(rollbackFor = Exception.class)
42 public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) { 43 public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
43 // 校验商品 SPU 是否存在是否参加的别的活动 44 // 校验商品 SPU 是否存在是否参加的别的活动
44 validateBargainConflict(createReqVO.getSpuId(), null); 45 validateBargainConflict(createReqVO.getSpuId(), null);
@@ -53,6 +54,7 @@ public class BargainActivityServiceImpl implements BargainActivityService { @@ -53,6 +54,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
53 } 54 }
54 55
55 @Override 56 @Override
  57 + @Transactional(rollbackFor = Exception.class)
56 public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) { 58 public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
57 // 校验存在 59 // 校验存在
58 BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId()); 60 BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
@@ -70,6 +72,22 @@ public class BargainActivityServiceImpl implements BargainActivityService { @@ -70,6 +72,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
70 bargainActivityMapper.updateById(updateObj); 72 bargainActivityMapper.updateById(updateObj);
71 } 73 }
72 74
  75 + @Override
  76 + @Transactional(rollbackFor = Exception.class)
  77 + public void updateBargainActivityStock(Long id, Integer count) {
  78 + // 查询砍价活动
  79 + BargainActivityDO activity = getBargainActivity(id);
  80 + if (activity == null) {
  81 + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
  82 + }
  83 +
  84 + // 更新砍价库存
  85 + int updateCount = bargainActivityMapper.updateActivityStock(id, count);
  86 + if (updateCount == 0) {
  87 + throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
  88 + }
  89 + }
  90 +
73 private void validateBargainConflict(Long spuId, Long activityId) { 91 private void validateBargainConflict(Long spuId, Long activityId) {
74 // 查询所有开启的砍价活动 92 // 查询所有开启的砍价活动
75 List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); 93 List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
1 package cn.iocoder.yudao.module.promotion.service.combination; 1 package cn.iocoder.yudao.module.promotion.service.combination;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
4 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -72,4 +73,11 @@ public interface CombinationActivityService { @@ -72,4 +73,11 @@ public interface CombinationActivityService {
72 */ 73 */
73 List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds); 74 List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
74 75
  76 + /**
  77 + * 更新拼图活动库存
  78 + *
  79 + * @param reqDTO 请求
  80 + */
  81 + void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
  82 +
75 } 83 }
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; @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
11 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 11 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  12 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 15 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -16,8 +17,12 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product @@ -16,8 +17,12 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
16 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; 17 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
17 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
  20 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
19 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper; 21 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
20 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper; 22 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
  23 +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
  24 +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
  25 +import org.springframework.context.annotation.Lazy;
21 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
22 import org.springframework.transaction.annotation.Transactional; 27 import org.springframework.transaction.annotation.Transactional;
23 import org.springframework.validation.annotation.Validated; 28 import org.springframework.validation.annotation.Validated;
@@ -28,8 +33,8 @@ import java.util.List; @@ -28,8 +33,8 @@ import java.util.List;
28 import java.util.Map; 33 import java.util.Map;
29 34
30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;  
32 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  37 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
33 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; 38 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; 39 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 40 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@@ -50,9 +55,15 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -50,9 +55,15 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
50 private CombinationProductMapper combinationProductMapper; 55 private CombinationProductMapper combinationProductMapper;
51 56
52 @Resource 57 @Resource
  58 + @Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录;
  59 + private CombinationRecordService combinationRecordService;
  60 +
  61 + @Resource
53 private ProductSpuApi productSpuApi; 62 private ProductSpuApi productSpuApi;
54 @Resource 63 @Resource
55 private ProductSkuApi productSkuApi; 64 private ProductSkuApi productSkuApi;
  65 + @Resource
  66 + private TradeOrderApi tradeOrderApi;
56 67
57 @Override 68 @Override
58 @Transactional(rollbackFor = Exception.class) 69 @Transactional(rollbackFor = Exception.class)
@@ -97,7 +108,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -97,7 +108,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
97 * 校验拼团商品是否都存在 108 * 校验拼团商品是否都存在
98 * 109 *
99 * @param spuId 商品 SPU 编号 110 * @param spuId 商品 SPU 编号
100 - * @param products 秒杀商品 111 + * @param products 拼团商品
101 */ 112 */
102 private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) { 113 private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
103 // 1. 校验商品 spu 是否存在 114 // 1. 校验商品 spu 是否存在
@@ -123,7 +134,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -123,7 +134,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
123 CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId()); 134 CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
124 // 校验状态 135 // 校验状态
125 if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { 136 if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
126 - throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); 137 + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE);
127 } 138 }
128 // 校验商品冲突 139 // 校验商品冲突
129 validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId()); 140 validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
@@ -205,4 +216,36 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -205,4 +216,36 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
205 return combinationProductMapper.selectListByActivityIds(activityIds); 216 return combinationProductMapper.selectListByActivityIds(activityIds);
206 } 217 }
207 218
  219 + @Override
  220 + public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
  221 + // 1.1 校验拼团活动是否存在
  222 + CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
  223 + // 1.2 校验活动是否开启
  224 + if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  225 + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
  226 + }
  227 + // 1.3 校验是否超出单次限购数量
  228 + if (activity.getSingleLimitCount() < reqDTO.getCount()) {
  229 + throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
  230 + }
  231 +
  232 + // 2. 校验是否超出总限购数量
  233 + // TODO @puhui999:userId 应该接口传递哈;要保证 service 无状态
  234 + List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(
  235 + getLoginUserId(), reqDTO.getActivityId());
  236 + // TODO @puhui999:最好 if true return;减少括号层数
  237 + if (CollUtil.isNotEmpty(recordList)) {
  238 + // 过滤出拼团成功的
  239 + // TODO @puhui999:count 要不存一个在 record 里?
  240 + List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
  241 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
  242 + Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
  243 + CombinationRecordDO::getOrderId,
  244 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
  245 + if (activity.getTotalLimitCount() < countSum) {
  246 + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
  247 + }
  248 + }
  249 + }
  250 +
208 } 251 }
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; @@ -2,12 +2,19 @@ package cn.iocoder.yudao.module.promotion.service.combination;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
  6 +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  7 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  8 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  9 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  10 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 11 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
6 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; 12 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 14 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
9 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper; 15 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
10 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 16 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
  17 +import org.springframework.context.annotation.Lazy;
11 import org.springframework.stereotype.Service; 18 import org.springframework.stereotype.Service;
12 import org.springframework.transaction.annotation.Transactional; 19 import org.springframework.transaction.annotation.Transactional;
13 import org.springframework.validation.annotation.Validated; 20 import org.springframework.validation.annotation.Validated;
@@ -31,11 +38,20 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; @@ -31,11 +38,20 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
31 public class CombinationRecordServiceImpl implements CombinationRecordService { 38 public class CombinationRecordServiceImpl implements CombinationRecordService {
32 39
33 @Resource 40 @Resource
  41 + @Lazy
34 private CombinationActivityService combinationActivityService; 42 private CombinationActivityService combinationActivityService;
35 -  
36 @Resource 43 @Resource
37 private CombinationRecordMapper recordMapper; 44 private CombinationRecordMapper recordMapper;
38 45
  46 + @Resource
  47 + private MemberUserApi memberUserApi;
  48 + @Resource
  49 + @Lazy
  50 + private ProductSpuApi productSpuApi;
  51 + @Resource
  52 + @Lazy
  53 + private ProductSkuApi productSkuApi;
  54 +
39 @Override 55 @Override
40 @Transactional(rollbackFor = Exception.class) 56 @Transactional(rollbackFor = Exception.class)
41 public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) { 57 public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
@@ -102,21 +118,29 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -102,21 +118,29 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
102 // 1.5 父拼团是否存在,是否已经满了 118 // 1.5 父拼团是否存在,是否已经满了
103 if (reqDTO.getHeadId() != null) { 119 if (reqDTO.getHeadId() != null) {
104 // 查询进行中的父拼团 120 // 查询进行中的父拼团
105 - CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());  
106 - if (recordDO1 == null) { 121 + CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
  122 + if (record == null) {
107 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS); 123 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
108 } 124 }
109 // 校验拼团是否满足要求 125 // 校验拼团是否满足要求
110 - if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) { 126 + if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
111 throw exception(COMBINATION_RECORD_USER_FULL); 127 throw exception(COMBINATION_RECORD_USER_FULL);
112 } 128 }
113 } 129 }
114 130
115 // 2. 创建拼团记录 131 // 2. 创建拼团记录
  132 + // TODO @puhui999:可以把 user、spu、sku 一起放 convert 里哈;
116 CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); 133 CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
117 record.setVirtualGroup(false); 134 record.setVirtualGroup(false);
118 record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration())); 135 record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
119 record.setUserSize(activity.getUserSize()); 136 record.setUserSize(activity.getUserSize());
  137 + MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
  138 + record.setNickname(user.getNickname());
  139 + record.setAvatar(user.getAvatar());
  140 + ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
  141 + record.setSpuName(spu.getName());
  142 + ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
  143 + record.setPicUrl(sku.getPicUrl());
120 recordMapper.insert(record); 144 recordMapper.insert(record);
121 } 145 }
122 146
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
1 package cn.iocoder.yudao.module.promotion.service.seckill; 1 package cn.iocoder.yudao.module.promotion.service.seckill;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@@ -34,18 +35,11 @@ public interface SeckillActivityService { @@ -34,18 +35,11 @@ public interface SeckillActivityService {
34 void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); 35 void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
35 36
36 /** 37 /**
37 - * 更新秒杀活动  
38 - *  
39 - * @param activityDO 秒杀活动  
40 - */  
41 - void updateSeckillActivity(SeckillActivityDO activityDO);  
42 -  
43 - /**  
44 - * 更新秒杀活动商品 38 + * 更新秒杀库存
45 * 39 *
46 - * @param productList 活动商品列表 40 + * @param updateStockReqDTO 更新信息
47 */ 41 */
48 - void updateSeckillActivityProductList(List<SeckillProductDO> productList); 42 + void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
49 43
50 /** 44 /**
51 * 关闭秒杀活动 45 * 关闭秒杀活动
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; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 8 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
9 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 9 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  10 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@@ -145,13 +146,36 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -145,13 +146,36 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
145 } 146 }
146 147
147 @Override 148 @Override
148 - public void updateSeckillActivity(SeckillActivityDO activityDO) {  
149 - seckillActivityMapper.updateById(activityDO);  
150 - } 149 + @Transactional(rollbackFor = Exception.class)
  150 + public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
  151 + // 1、校验秒杀活动是否存在
  152 + SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
  153 + // 1.1、校验库存是否充足
  154 + if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
  155 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  156 + }
151 157
152 - @Override  
153 - public void updateSeckillActivityProductList(List<SeckillProductDO> productList) {  
154 - seckillProductMapper.updateBatch(productList); 158 + // 2、获取活动商品
  159 + List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
  160 + // 2.1、过滤出购买的商品
  161 + SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId()));
  162 + // 2.2、检查活动商品库存是否充足
  163 + boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0);
  164 + if (isSufficient) {
  165 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  166 + }
  167 +
  168 + // 3、更新活动商品库存
  169 + int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
  170 + if (updateCount == 0) {
  171 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  172 + }
  173 +
  174 + // 4、更新活动库存
  175 + updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
  176 + if (updateCount == 0) {
  177 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  178 + }
155 } 179 }
156 180
157 /** 181 /**
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
6 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
7 import java.time.LocalDateTime; 7 import java.time.LocalDateTime;
8 8
  9 +// TODO @疯狂:是不是不需要这个啦?
9 /** 10 /**
10 * 分销 API 接口 11 * 分销 API 接口
11 * 12 *
@@ -31,6 +32,7 @@ public interface BrokerageApi { @@ -31,6 +32,7 @@ public interface BrokerageApi {
31 */ 32 */
32 default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) { 33 default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
33 // 注册时间在30秒内的,都算新用户 34 // 注册时间在30秒内的,都算新用户
  35 + // TODO @疯狂:这个要不抽到 service 里哈?
34 boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30)); 36 boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
35 return bindUser(userId, bindUserId, isNewUser); 37 return bindUser(userId, bindUserId, isNewUser);
36 } 38 }
@@ -43,5 +45,8 @@ public interface BrokerageApi { @@ -43,5 +45,8 @@ public interface BrokerageApi {
43 * @param isNewUser 是否为新用户 45 * @param isNewUser 是否为新用户
44 * @return 是否绑定 46 * @return 是否绑定
45 */ 47 */
46 - boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull Boolean isNewUser); 48 + boolean bindUser(@NotNull(message = "用户编号不能为空") Long userId,
  49 + @NotNull(message = "推广员编号不能为空") Long bindUserId,
  50 + @NotNull Boolean isNewUser);
  51 +
47 } 52 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
1 package cn.iocoder.yudao.module.trade.api.order; 1 package cn.iocoder.yudao.module.trade.api.order;
2 2
  3 +import java.util.Collection;
  4 +
3 /** 5 /**
4 * 订单 API 接口 6 * 订单 API 接口
5 * 7 *
@@ -16,4 +18,13 @@ public interface TradeOrderApi { @@ -16,4 +18,13 @@ public interface TradeOrderApi {
16 */ 18 */
17 Long validateOrder(Long userId, Long orderItemId); 19 Long validateOrder(Long userId, Long orderItemId);
18 20
  21 + /**
  22 + * 获取订单项商品购买数量总和
  23 + *
  24 + * @param orderIds 订单编号
  25 + * @param skuIds sku 编号
  26 + * @return 订单项商品购买数量总和
  27 + */
  28 + Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
  29 +
19 } 30 }
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 { @@ -34,6 +34,9 @@ public interface ErrorCodeConstants {
34 ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功"); 34 ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
35 ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递"); 35 ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
36 ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态"); 36 ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
  37 + ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1011000026, "支付订单调价失败,原因:支付订单已付款,不能调价");
  38 + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1011000027, "支付订单调价失败,原因:价格没有变化");
  39 + ErrorCode ORDER_UPDATE_PRICE_FAIL_NOT_ITEM = new ErrorCode(1011000028, "支付订单调价失败,原因:订单项不存在");
37 40
38 // ========== After Sale 模块 1011000100 ========== 41 // ========== After Sale 模块 1011000100 ==========
39 ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); 42 ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java
@@ -6,6 +6,7 @@ import lombok.Getter; @@ -6,6 +6,7 @@ import lombok.Getter;
6 6
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
  9 +// TODO @疯狂:是不是搞成层级,类似 level 这样?因为本质上,它是 1 级、2 级、3 级这样的关系哈
9 /** 10 /**
10 * 分销用户类型枚举 11 * 分销用户类型枚举
11 * 12 *
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.order;
  2 +
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +/**
  7 + * 订单操作类型的枚举
  8 + *
  9 + * @author 陈賝
  10 + * @since 2023/7/6 15:31
  11 + */
  12 +@RequiredArgsConstructor
  13 +@Getter
  14 +public enum TradeOrderOperateTypeEnum {
  15 +
  16 + MEMBER_CREATE(1, "用户下单"),
  17 + TEST(2, "用户({nickname})做了({thing})"),
  18 + ;
  19 +
  20 + /**
  21 + * 类型
  22 + */
  23 + private final Integer type;
  24 + /**
  25 + * 类型
  26 + */
  27 + private final String content;
  28 +
  29 +}
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; @@ -6,6 +6,7 @@ import org.springframework.stereotype.Service;
6 import org.springframework.validation.annotation.Validated; 6 import org.springframework.validation.annotation.Validated;
7 7
8 import javax.annotation.Resource; 8 import javax.annotation.Resource;
  9 +import java.util.Collection;
9 10
10 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 11 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
11 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND; 12 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
@@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi { @@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi {
32 return item.getOrderId(); 33 return item.getOrderId();
33 } 34 }
34 35
  36 + @Override
  37 + public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
  38 + return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
  39 + }
  40 +
35 } 41 }
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 { @@ -76,10 +76,9 @@ public class TradeAfterSaleController {
76 public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { 76 public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
77 // 查询订单 77 // 查询订单
78 TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); 78 TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
79 - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;  
80 -// if (afterSale == null) {  
81 -// return success(null, AFTER_SALE_NOT_FOUND.getMsg());  
82 -// } 79 + if (afterSale == null) {
  80 + return success(null);
  81 + }
83 82
84 // 查询订单 83 // 查询订单
85 TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); 84 TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java
@@ -55,10 +55,11 @@ public class BrokerageRecordController { @@ -55,10 +55,11 @@ public class BrokerageRecordController {
55 public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) { 55 public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
56 PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO); 56 PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
57 57
  58 + // 查询用户信息
58 Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId); 59 Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
59 userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId)); 60 userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
60 Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds); 61 Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
61 - 62 + // 拼接数据
62 return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap)); 63 return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
63 } 64 }
64 65
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 { @@ -67,10 +67,9 @@ public class TradeOrderController {
67 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { 67 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
68 // 查询订单 68 // 查询订单
69 TradeOrderDO order = tradeOrderQueryService.getOrder(id); 69 TradeOrderDO order = tradeOrderQueryService.getOrder(id);
70 - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;  
71 -// if (order == null) {  
72 -// return success(null, ORDER_NOT_FOUND.getMsg());  
73 -// } 70 + if (order == null) {
  71 + return success(null);
  72 + }
74 73
75 // 查询订单项 74 // 查询订单项
76 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); 75 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
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 { @@ -31,19 +31,15 @@ public class TradeOrderPageReqVO extends PageParam {
31 @Mobile 31 @Mobile
32 private String userMobile; 32 private String userMobile;
33 33
  34 + @Schema(description = "配送方式", example = "1")
  35 + private Integer deliveryType;
  36 +
34 @Schema(description = "发货物流公司编号", example = "1") 37 @Schema(description = "发货物流公司编号", example = "1")
35 private Long logisticsId; 38 private Long logisticsId;
36 39
37 @Schema(description = "自提门店编号", example = "[1,2]") 40 @Schema(description = "自提门店编号", example = "[1,2]")
38 private List<Long> pickUpStoreIds; 41 private List<Long> pickUpStoreIds;
39 42
40 - @Schema(description = "收件人名称", example = "小红")  
41 - private String receiverName;  
42 -  
43 - @Schema(description = "收件人手机", example = "1560")  
44 - @Mobile  
45 - private String receiverMobile;  
46 -  
47 @Schema(description = "订单类型", example = "1") 43 @Schema(description = "订单类型", example = "1")
48 private Integer type; 44 private Integer type;
49 45
@@ -61,5 +57,5 @@ public class TradeOrderPageReqVO extends PageParam { @@ -61,5 +57,5 @@ public class TradeOrderPageReqVO extends PageParam {
61 @Schema(description = "订单来源", example = "10") 57 @Schema(description = "订单来源", example = "10")
62 @InEnum(value = TerminalEnum.class, message = "订单来源 {value}") 58 @InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
63 private Integer terminal; 59 private Integer terminal;
64 -// TODO 添加配送方式筛选 60 +
65 } 61 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java
@@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO { @@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO {
19 @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") 19 @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
20 private Integer frozenPrice; 20 private Integer frozenPrice;
21 21
22 - @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 22 + @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
23 private Integer firstBrokerageUserCount; 23 private Integer firstBrokerageUserCount;
24 24
25 @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 25 @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
1 package cn.iocoder.yudao.module.trade.controller.app.order; 1 package cn.iocoder.yudao.module.trade.controller.app.order;
2 2
  3 +import cn.hutool.core.map.MapUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 6 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
@@ -11,8 +12,11 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; @@ -11,8 +12,11 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
11 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; 12 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
12 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 14 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  15 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
14 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
15 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 17 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  18 +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
  19 +import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
16 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; 20 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
17 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; 21 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
18 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; 22 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
@@ -61,7 +65,10 @@ public class AppTradeOrderController { @@ -61,7 +65,10 @@ public class AppTradeOrderController {
61 @PostMapping("/create") 65 @PostMapping("/create")
62 @Operation(summary = "创建订单") 66 @Operation(summary = "创建订单")
63 @PreAuthenticated 67 @PreAuthenticated
  68 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST)
64 public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) { 69 public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
  70 + TradeOrderLogUtils.setOrderInfo(10L, 1, 2,
  71 + MapUtil.<String, Object>builder().put("nickname", "小明").put("thing", "种土豆").build());
65 TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO); 72 TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
66 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); 73 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
67 } 74 }
@@ -81,10 +88,9 @@ public class AppTradeOrderController { @@ -81,10 +88,9 @@ public class AppTradeOrderController {
81 public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) { 88 public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
82 // 查询订单 89 // 查询订单
83 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); 90 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
84 - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;  
85 -// if (order == null) {  
86 -// return success(null, ORDER_NOT_FOUND.getMsg());  
87 -// } 91 + if (order == null) {
  92 + return success(null);
  93 + }
88 94
89 // 查询订单项 95 // 查询订单项
90 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId()); 96 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
@@ -52,15 +52,12 @@ public interface BrokerageRecordConvert { @@ -52,15 +52,12 @@ public interface BrokerageRecordConvert {
52 52
53 default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) { 53 default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
54 PageResult<BrokerageRecordRespVO> result = convertPage(pageResult); 54 PageResult<BrokerageRecordRespVO> result = convertPage(pageResult);
55 -  
56 for (BrokerageRecordRespVO respVO : result.getList()) { 55 for (BrokerageRecordRespVO respVO : result.getList()) {
57 Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user -> 56 Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user ->
58 respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar())); 57 respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
59 -  
60 Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user -> 58 Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user ->
61 respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar())); 59 respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar()));
62 } 60 }
63 -  
64 return result; 61 return result;
65 } 62 }
66 } 63 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
@@ -35,18 +35,18 @@ public interface BrokerageUserConvert { @@ -35,18 +35,18 @@ public interface BrokerageUserConvert {
35 Map<Long, Long> brokerageUserCountMap, 35 Map<Long, Long> brokerageUserCountMap,
36 Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap) { 36 Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap) {
37 PageResult<BrokerageUserRespVO> result = convertPage(pageResult); 37 PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
38 - for (BrokerageUserRespVO vo : result.getList()) { 38 + for (BrokerageUserRespVO userVO : result.getList()) {
39 // 用户信息 39 // 用户信息
40 - copyTo(userMap.get(vo.getId()), vo); 40 + copyTo(userMap.get(userVO.getId()), userVO);
41 41
42 // 推广用户数量 42 // 推广用户数量
43 - vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0)); 43 + userVO.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, userVO.getId(), 0));
44 // 推广订单数量、推广订单金额 44 // 推广订单数量、推广订单金额
45 - Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));  
46 - vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0)) 45 + Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(userVO.getId()));
  46 + userVO.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
47 .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0)); 47 .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
48 // todo 已提现次数、已提现金额 48 // todo 已提现次数、已提现金额
49 - vo.setWithdrawCount(0).setWithdrawPrice(0); 49 + userVO.setWithdrawCount(0).setWithdrawPrice(0);
50 } 50 }
51 return result; 51 return result;
52 } 52 }
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 @@ -14,7 +14,9 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
14 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; 14 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
15 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 15 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
16 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 16 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
  17 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
17 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 18 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  19 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
18 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 20 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
19 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; 21 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
20 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; 22 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@@ -32,6 +34,8 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn @@ -32,6 +34,8 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn
32 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; 34 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
33 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 35 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
34 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; 36 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  37 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  38 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
35 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 39 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
36 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 40 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
37 import org.mapstruct.Mapper; 41 import org.mapstruct.Mapper;
@@ -254,21 +258,15 @@ public interface TradeOrderConvert { @@ -254,21 +258,15 @@ public interface TradeOrderConvert {
254 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address); 258 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
255 259
256 @Mappings({ 260 @Mappings({
257 - @Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),  
258 - @Mapping(target = "spuId", source = "orderItem.spuId"),  
259 - @Mapping(target = "skuId", source = "orderItem.skuId"),  
260 - @Mapping(target = "userId", source = "order.userId"),  
261 - @Mapping(target = "orderId", source = "order.id"),  
262 - @Mapping(target = "headId", source = "createReqVO.combinationHeadId"),  
263 - @Mapping(target = "spuName", source = "orderItem.spuName"),  
264 - @Mapping(target = "picUrl", source = "orderItem.picUrl"),  
265 - @Mapping(target = "combinationPrice", source = "orderItem.payPrice"),  
266 - @Mapping(target = "nickname", source = "user.nickname"),  
267 - @Mapping(target = "avatar", source = "user.avatar"),  
268 - @Mapping(target = "status", ignore = true) 261 + @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
  262 + @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
  263 + @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
  264 + @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
  265 + @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
  266 + @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
  267 + @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
269 }) 268 })
270 - CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,  
271 - AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user); 269 + CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
272 270
273 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list); 271 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
274 272
@@ -279,11 +277,29 @@ public interface TradeOrderConvert { @@ -279,11 +277,29 @@ public interface TradeOrderConvert {
279 TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); 277 TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
280 278
281 default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) { 279 default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
282 - return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))  
283 - .setSourceUserId(item.getUserId()) 280 + return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
284 .setBasePrice(item.getPayPrice() * item.getCount()) 281 .setBasePrice(item.getPayPrice() * item.getCount())
285 - .setFirstFixedPrice(sku.getSubCommissionFirstPrice())  
286 - .setSecondFixedPrice(sku.getSubCommissionSecondPrice())  
287 - .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()); 282 + .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:标题类似:木晴冰雪成功购买云时代的JVM原理与实战;茫农成功购买深入拆解消息队列47讲
  283 + .setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord());
288 } 284 }
  285 +
  286 + @Mapping(target = "activityId", source = "reqBO.seckillActivityId")
  287 + SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
  288 +
  289 + @Mapping(target = "activityId", source = "reqBO.combinationActivityId")
  290 + CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
  291 +
  292 + TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
  293 +
  294 + @Mappings({
  295 + @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
  296 + @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
  297 + @Mapping(target = "spuId", source = "orderItem.spuId"),
  298 + @Mapping(target = "skuId", source = "orderItem.skuId"),
  299 + @Mapping(target = "orderId", source = "tradeOrderDO.id"),
  300 + @Mapping(target = "userId", source = "userId"),
  301 + @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
  302 + })
  303 + TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
  304 +
289 } 305 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java
@@ -85,13 +85,13 @@ public class BrokerageRecordDO extends BaseDO { @@ -85,13 +85,13 @@ public class BrokerageRecordDO extends BaseDO {
85 /** 85 /**
86 * 来源用户类型 86 * 来源用户类型
87 * <p> 87 * <p>
88 - * 枚举 {@link BrokerageUserTypeEnum} 88 + * 枚举 {@link BrokerageUserTypeEnum},被推广用户和 {@link #userId} 的推广层级关系
89 */ 89 */
90 private Integer sourceUserType; 90 private Integer sourceUserType;
91 /** 91 /**
92 * 来源用户编号 92 * 来源用户编号
93 * <p> 93 * <p>
94 - * 关联 MemberUserDO.id 94 + * 关联 MemberUserDO.id 字段,被推广用户的编号
95 */ 95 */
96 private Long sourceUserId; 96 private Long sourceUserId;
97 97
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.dataobject.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +/**
  12 + * 订单日志 DO
  13 + *
  14 + * @author 陈賝
  15 + */
  16 +@TableName("trade_order_log")
  17 +@KeySequence("trade_order_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class TradeOrderLogDO extends BaseDO {
  25 +
  26 + /**
  27 + * 用户类型 - 系统
  28 + *
  29 + * 例如说:Job 自动过期订单时,通过系统自动操作
  30 + */
  31 + public static final Integer USER_TYPE_SYSTEM = 0;
  32 + /**
  33 + * 用户编号 - 系统
  34 + */
  35 + public static final Long USER_ID_SYSTEM = 0L;
  36 +
  37 + /**
  38 + * 编号
  39 + */
  40 + @TableId
  41 + private Long id;
  42 + /**
  43 + * 用户编号
  44 + *
  45 + * 关联 AdminUserDO 的 id 字段、或者 MemberUserDO 的 id 字段
  46 + */
  47 + private Long userId;
  48 + /**
  49 + * 用户类型
  50 + *
  51 + * 枚举 {@link UserTypeEnum}
  52 + */
  53 + private Integer userType;
  54 +
  55 + /**
  56 + * 订单号
  57 + *
  58 + * 关联 {@link TradeOrderDO#getId()}
  59 + */
  60 + private Long orderId;
  61 + /**
  62 + * 操作前状态
  63 + */
  64 + private Integer beforeStatus;
  65 + /**
  66 + * 操作后状态
  67 + */
  68 + private Integer afterStatus;
  69 +
  70 + /**
  71 + * 操作类型
  72 + *
  73 + * {@link TradeOrderOperateTypeEnum}
  74 + */
  75 + private Integer operateType;
  76 + /**
  77 + * 订单日志信息
  78 + */
  79 + private String content;
  80 +
  81 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
@@ -26,7 +26,7 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; { @@ -26,7 +26,7 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; {
26 default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) { 26 default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
27 boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null && 27 boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
28 !BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType()); 28 !BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
29 - 29 + // 分页查询
30 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>() 30 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
31 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) 31 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
32 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) 32 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
@@ -54,7 +54,8 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; { @@ -54,7 +54,8 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; {
54 BrokerageRecordDO::getUserId, userId); 54 BrokerageRecordDO::getUserId, userId);
55 } 55 }
56 56
57 - @Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status}") 57 + @Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record " +
  58 + "WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status}")
58 UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, 59 UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
59 @Param("bizType") Integer bizType, 60 @Param("bizType") Integer bizType,
60 @Param("status") Integer status); 61 @Param("status") Integer status);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
@@ -36,8 +36,9 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; { @@ -36,8 +36,9 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
36 } else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) { 36 } else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {
37 buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper); 37 buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);
38 } else { 38 } else {
  39 + // TODO @疯狂:要不要把这个逻辑,挪到 Service 里,算出子用户有哪些,然后 IN?
39 buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper); 40 buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
40 - buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); 41 + buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); // 通过 or 实现多个条件
41 } 42 }
42 } 43 }
43 44
@@ -45,8 +46,8 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; { @@ -45,8 +46,8 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
45 wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId); 46 wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
46 } 47 }
47 48
48 - static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> w) {  
49 - w.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId)); 49 + static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
  50 + wrapper.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId));
50 } 51 }
51 52
52 /** 53 /**
@@ -142,4 +143,5 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; { @@ -142,4 +143,5 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
142 143
143 @Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})") 144 @Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})")
144 Long selectCountByBindUserIdInBindUserId(Long bindUserId); 145 Long selectCountByBindUserIdInBindUserId(Long bindUserId);
  146 +
145 } 147 }
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&lt;TradeOrderItemDO&gt; { @@ -29,7 +29,7 @@ public interface TradeOrderItemMapper extends BaseMapperX&lt;TradeOrderItemDO&gt; {
29 default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) { 29 default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
30 return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>() 30 return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
31 .in(TradeOrderItemDO::getOrderId, orderIds) 31 .in(TradeOrderItemDO::getOrderId, orderIds)
32 - .eq(TradeOrderItemDO::getSkuId, skuIds)); 32 + .in(TradeOrderItemDO::getSkuId, skuIds));
33 } 33 }
34 34
35 default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) { 35 default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
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&lt;TradeOrderDO&gt; { @@ -27,13 +27,12 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
27 return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>() 27 return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>()
28 .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo()) 28 .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo())
29 .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId()) 29 .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId())
  30 + .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType())
30 .inIfPresent(TradeOrderDO::getUserId, userIds) 31 .inIfPresent(TradeOrderDO::getUserId, userIds)
31 - .likeIfPresent(TradeOrderDO::getReceiverName, reqVO.getReceiverName())  
32 - .likeIfPresent(TradeOrderDO::getReceiverMobile, reqVO.getReceiverMobile())  
33 .eqIfPresent(TradeOrderDO::getType, reqVO.getType()) 32 .eqIfPresent(TradeOrderDO::getType, reqVO.getType())
34 .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus()) 33 .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus())
35 .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode()) 34 .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode())
36 - .eqIfPresent(TradeOrderDO::getTerminal,reqVO.getTerminal()) 35 + .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal())
37 .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId()) 36 .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId())
38 .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds()) 37 .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds())
39 .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime())); 38 .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()));
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.framework.order.core.annotations;
  2 +
  3 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
  4 +
  5 +import java.lang.annotation.*;
  6 +
  7 +import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
  8 +import static java.lang.annotation.ElementType.METHOD;
  9 +
  10 +/**
  11 + * 交易订单的操作日志 AOP 注解
  12 + *
  13 + * @author 陈賝
  14 + * @since 2023/7/6 15:37
  15 + */
  16 +@Target({METHOD, ANNOTATION_TYPE})
  17 +@Retention(RetentionPolicy.RUNTIME)
  18 +@Documented
  19 +public @interface TradeOrderLog {
  20 +
  21 + /**
  22 + * 操作类型
  23 + */
  24 + TradeOrderOperateTypeEnum operateType();
  25 +
  26 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.framework.order.core.aop;
  2 +
  3 +
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
  8 +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
  9 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService;
  10 +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.aspectj.lang.JoinPoint;
  13 +import org.aspectj.lang.annotation.AfterReturning;
  14 +import org.aspectj.lang.annotation.Aspect;
  15 +import org.springframework.stereotype.Component;
  16 +
  17 +import javax.annotation.Resource;
  18 +import java.util.Map;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  21 +import static java.util.Collections.emptyMap;
  22 +
  23 +/**
  24 + * 交易订单的操作日志的记录 AOP 切面
  25 + *
  26 + * @author 陈賝
  27 + * @since 2023/6/13 13:54
  28 + */
  29 +@Component
  30 +@Aspect
  31 +@Slf4j
  32 +public class TradeOrderLogAspect {
  33 +
  34 + /**
  35 + * 订单编号
  36 + */
  37 + private static final ThreadLocal<Long> ORDER_ID = new ThreadLocal<>();
  38 + /**
  39 + * 操作前的状态
  40 + */
  41 + private static final ThreadLocal<Integer> BEFORE_STATUS = new ThreadLocal<>();
  42 + /**
  43 + * 操作后的状态
  44 + */
  45 + private static final ThreadLocal<Integer> AFTER_STATUS = new ThreadLocal<>();
  46 + /**
  47 + * 拓展参数 Map,用于格式化操作内容
  48 + */
  49 + private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>();
  50 +
  51 + public TradeOrderLogAspect() {
  52 + System.out.println();
  53 + }
  54 +
  55 + @Resource
  56 + private TradeOrderLogService orderLogService;
  57 +
  58 + @AfterReturning("@annotation(orderLog)")
  59 + public void doAfterReturning(JoinPoint joinPoint, TradeOrderLog orderLog) {
  60 + try {
  61 + // 1.1 操作用户
  62 + Integer userType = getUserType();
  63 + Long userId = getUserId();
  64 + // 1.2 订单信息
  65 + Long orderId = ORDER_ID.get();
  66 + Integer beforeStatus = BEFORE_STATUS.get();
  67 + Integer afterStatus = AFTER_STATUS.get();
  68 + Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap());
  69 + String content = StrUtil.format(orderLog.operateType().getContent(), exts);
  70 +
  71 + // 2.1 记录日志
  72 + TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO()
  73 + .setUserId(userId).setUserType(userType)
  74 + .setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)
  75 + .setOperateType(orderLog.operateType().getType()).setContent(content);
  76 + orderLogService.createOrderLog(createBO);
  77 + } catch (Exception ex) {
  78 + // todo 芋艿:清理上下文
  79 + log.error("[doAfterReturning][orderLog({}) 订单日志错误]", toJsonString(orderLog), ex);
  80 + }
  81 + }
  82 +
  83 + /**
  84 + * 获得用户类型
  85 + *
  86 + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserType()} 系统
  87 + *
  88 + * @return 用户类型
  89 + */
  90 + private static Integer getUserType() {
  91 + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM);
  92 + }
  93 +
  94 + /**
  95 + * 获得用户编号
  96 + *
  97 + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserId()} 系统
  98 + *
  99 + * @return 用户类型
  100 + */
  101 + private static Long getUserId() {
  102 + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM);
  103 + }
  104 +
  105 + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, Map<String, Object> exts) {
  106 + ORDER_ID.set(id);
  107 + BEFORE_STATUS.set(beforeStatus);
  108 + AFTER_STATUS.set(afterStatus);
  109 + EXTS.set(exts);
  110 + }
  111 +
  112 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.framework.order.core.utils;
  2 +
  3 +import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect;
  4 +
  5 +import java.util.Map;
  6 +
  7 +/**
  8 + * 交易订单的操作日志 Utils
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public class TradeOrderLogUtils {
  13 +
  14 + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus) {
  15 + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, null);
  16 + }
  17 +
  18 + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus,
  19 + Map<String, Object> exts) {
  20 + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts);
  21 + }
  22 +
  23 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java
@@ -5,6 +5,7 @@ import lombok.Data; @@ -5,6 +5,7 @@ import lombok.Data;
5 import lombok.NoArgsConstructor; 5 import lombok.NoArgsConstructor;
6 6
7 import javax.validation.constraints.NotBlank; 7 import javax.validation.constraints.NotBlank;
  8 +import javax.validation.constraints.NotEmpty;
8 import javax.validation.constraints.NotNull; 9 import javax.validation.constraints.NotNull;
9 10
10 /** 11 /**
@@ -30,6 +31,7 @@ public class BrokerageAddReqBO { @@ -30,6 +31,7 @@ public class BrokerageAddReqBO {
30 /** 31 /**
31 * 一级佣金(固定) 32 * 一级佣金(固定)
32 */ 33 */
  34 + @NotNull(message = "一级佣金(固定)不能为空")
33 private Integer firstFixedPrice; 35 private Integer firstFixedPrice;
34 /** 36 /**
35 * 二级佣金(固定) 37 * 二级佣金(固定)
@@ -39,10 +41,13 @@ public class BrokerageAddReqBO { @@ -39,10 +41,13 @@ public class BrokerageAddReqBO {
39 /** 41 /**
40 * 来源用户编号 42 * 来源用户编号
41 */ 43 */
  44 + @NotNull(message = "来源用户编号不能为空")
42 private Long sourceUserId; 45 private Long sourceUserId;
43 46
44 /** 47 /**
45 * 佣金记录标题 48 * 佣金记录标题
46 */ 49 */
  50 + @NotEmpty(message = "佣金记录标题不能为空")
47 private String title; 51 private String title;
  52 +
48 } 53 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage.record; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage.record;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.BooleanUtil; 4 import cn.hutool.core.util.BooleanUtil;
5 import cn.hutool.core.util.ObjectUtil; 5 import cn.hutool.core.util.ObjectUtil;
  6 +import cn.hutool.core.util.StrUtil;
6 import cn.hutool.extra.spring.SpringUtil; 7 import cn.hutool.extra.spring.SpringUtil;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; 9 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
@@ -154,21 +155,24 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -154,21 +155,24 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
154 int totalBrokerage = 0; 155 int totalBrokerage = 0;
155 List<BrokerageRecordDO> records = new ArrayList<>(); 156 List<BrokerageRecordDO> records = new ArrayList<>();
156 for (BrokerageAddReqBO item : list) { 157 for (BrokerageAddReqBO item : list) {
157 - Integer fixedPrice = 0; 158 + // 计算金额
  159 + Integer fixedPrice;
158 if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) { 160 if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) {
159 fixedPrice = item.getFirstFixedPrice(); 161 fixedPrice = item.getFirstFixedPrice();
160 } else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) { 162 } else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) {
161 fixedPrice = item.getSecondFixedPrice(); 163 fixedPrice = item.getSecondFixedPrice();
  164 + } else {
  165 + throw new IllegalArgumentException(StrUtil.format("来源用户({}) 不合法", sourceUserType));
162 } 166 }
163 -  
164 - int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);  
165 - if (brokeragePerItem <= 0) { 167 + int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
  168 + if (brokeragePrice <= 0) {
166 continue; 169 continue;
167 } 170 }
  171 + totalBrokerage += brokeragePrice;
  172 + // 创建记录实体
168 records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), 173 records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
169 - brokerageFrozenDays, brokeragePerItem, unfreezeTime, item.getTitle(), 174 + brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(),
170 item.getSourceUserId(), sourceUserType.getType())); 175 item.getSourceUserId(), sourceUserType.getType()));
171 - totalBrokerage += brokeragePerItem;  
172 } 176 }
173 if (CollUtil.isEmpty(records)) { 177 if (CollUtil.isEmpty(records)) {
174 return; 178 return;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
@@ -134,7 +134,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -134,7 +134,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
134 @Override 134 @Override
135 public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) { 135 public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
136 switch (userType) { 136 switch (userType) {
137 - case ALL: 137 + case ALL: // TODO @疯狂:ALL 是不是不用搞个枚举,默认为空就是不过滤哈~
138 Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId); 138 Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);
139 Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId); 139 Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
140 return firstCount + secondCount; 140 return firstCount + secondCount;
@@ -183,7 +183,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -183,7 +183,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
183 public Boolean getUserBrokerageEnabled(Long userId) { 183 public Boolean getUserBrokerageEnabled(Long userId) {
184 // 全局分销功能是否开启 184 // 全局分销功能是否开启
185 TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); 185 TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
186 - if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { 186 + if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) {
187 return false; 187 return false;
188 } 188 }
189 189
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order;
  2 +
  3 +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
  4 +import org.springframework.scheduling.annotation.Async;
  5 +
  6 +/**
  7 + * 交易下单日志 Service 接口
  8 + *
  9 + * @author 陈賝
  10 + * @since 2023/7/6 15:44
  11 + */
  12 +public interface TradeOrderLogService {
  13 +
  14 + /**
  15 + * 创建交易下单日志
  16 + *
  17 + * @param logDTO 日志记录
  18 + * @author 陈賝
  19 + * @since 2023/7/6 15:45
  20 + */
  21 + @Async
  22 + void createOrderLog(TradeOrderLogCreateReqBO logDTO);
  23 +
  24 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order;
  2 +
  3 +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
  4 +import org.springframework.stereotype.Service;
  5 +
  6 +/**
  7 + * 交易下单日志 Service 实现类
  8 + *
  9 + * @author 陈賝
  10 + * @since 2023/7/6 15:44
  11 + */
  12 +@Service
  13 +public class TradeOrderLogServiceImpl implements TradeOrderLogService {
  14 +
  15 + @Override
  16 + public void createOrderLog(TradeOrderLogCreateReqBO createReqBO) {
  17 + // TODO 芋艿:存储还没搞
  18 + System.out.println();
  19 + }
  20 +
  21 +}
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 { @@ -119,4 +119,13 @@ public interface TradeOrderQueryService {
119 */ 119 */
120 List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds); 120 List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
121 121
  122 + /**
  123 + * 获取订单项商品购买数量总和
  124 + *
  125 + * @param orderIds 订单编号
  126 + * @param skuIds sku 编号
  127 + * @return 订单项商品购买数量总和
  128 + */
  129 + Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
  130 +
122 } 131 }
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; @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 8 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
9 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; 10 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
@@ -167,4 +168,10 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { @@ -167,4 +168,10 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
167 return tradeOrderItemMapper.selectListByOrderId(orderIds); 168 return tradeOrderItemMapper.selectListByOrderId(orderIds);
168 } 169 }
169 170
  171 + @Override
  172 + public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
  173 + List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
  174 + return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
  175 + }
  176 +
170 } 177 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -7,14 +7,11 @@ import cn.hutool.core.util.StrUtil; @@ -7,14 +7,11 @@ import cn.hutool.core.util.StrUtil;
7 import cn.hutool.extra.spring.SpringUtil; 7 import cn.hutool.extra.spring.SpringUtil;
8 import cn.iocoder.yudao.framework.common.core.KeyValue; 8 import cn.iocoder.yudao.framework.common.core.KeyValue;
9 import cn.iocoder.yudao.framework.common.enums.TerminalEnum; 9 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
10 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
11 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 10 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
12 import cn.iocoder.yudao.module.member.api.address.AddressApi; 11 import cn.iocoder.yudao.module.member.api.address.AddressApi;
13 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 12 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
14 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; 13 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
15 import cn.iocoder.yudao.module.member.api.point.MemberPointApi; 14 import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
16 -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;  
17 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
18 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; 15 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
19 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; 16 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
20 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 17 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@@ -24,15 +21,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; @@ -24,15 +21,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
24 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; 21 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
25 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; 22 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
26 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 23 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
27 -import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;  
28 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; 24 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
29 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; 25 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
30 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;  
31 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; 26 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
32 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; 27 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
33 -import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;  
34 -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;  
35 -import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;  
36 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; 28 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
37 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; 29 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
38 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; 30 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
@@ -53,12 +45,14 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; @@ -53,12 +45,14 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
53 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 45 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
54 import cn.iocoder.yudao.module.trade.enums.order.*; 46 import cn.iocoder.yudao.module.trade.enums.order.*;
55 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 47 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
56 -import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;  
57 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; 48 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  49 +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
58 import cn.iocoder.yudao.module.trade.service.cart.CartService; 50 import cn.iocoder.yudao.module.trade.service.cart.CartService;
59 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; 51 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
60 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; 52 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
61 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; 53 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
  54 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  55 +import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
62 import cn.iocoder.yudao.module.trade.service.price.TradePriceService; 56 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
63 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 57 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
64 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 58 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -70,14 +64,13 @@ import org.springframework.transaction.annotation.Transactional; @@ -70,14 +64,13 @@ import org.springframework.transaction.annotation.Transactional;
70 64
71 import javax.annotation.Resource; 65 import javax.annotation.Resource;
72 import java.time.LocalDateTime; 66 import java.time.LocalDateTime;
  67 +import java.util.ArrayList;
73 import java.util.List; 68 import java.util.List;
74 import java.util.Objects; 69 import java.util.Objects;
75 import java.util.Set; 70 import java.util.Set;
76 71
77 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 72 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
78 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 73 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
79 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;  
80 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;  
81 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 74 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
82 75
83 /** 76 /**
@@ -98,6 +91,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -98,6 +91,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
98 private TradeOrderNoRedisDAO orderNoRedisDAO; 91 private TradeOrderNoRedisDAO orderNoRedisDAO;
99 92
100 @Resource 93 @Resource
  94 + private List<TradeOrderHandler> tradeOrderHandlers;
  95 +
  96 + @Resource
101 private CartService cartService; 97 private CartService cartService;
102 @Resource 98 @Resource
103 private TradePriceService tradePriceService; 99 private TradePriceService tradePriceService;
@@ -119,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -119,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
119 @Resource 115 @Resource
120 private BargainRecordApi bargainRecordApi; 116 private BargainRecordApi bargainRecordApi;
121 @Resource 117 @Resource
122 - private SeckillActivityApi seckillActivityApi;  
123 - @Resource  
124 - private BargainActivityApi bargainActivityApi;  
125 - @Resource  
126 - private MemberUserApi memberUserApi;  
127 - @Resource  
128 private MemberLevelApi memberLevelApi; 118 private MemberLevelApi memberLevelApi;
129 @Resource 119 @Resource
130 private MemberPointApi memberPointApi; 120 private MemberPointApi memberPointApi;
@@ -189,7 +179,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -189,7 +179,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
189 @Override 179 @Override
190 @Transactional(rollbackFor = Exception.class) 180 @Transactional(rollbackFor = Exception.class)
191 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { 181 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
192 - // 1. 价格计算 182 + // 1、执行订单创建前置处理器
  183 + // TODO @puhui999:最好也抽个 beforeOrderCreate 方法;
  184 + TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
  185 + beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
  186 + beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
  187 + // TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
  188 + tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
  189 +
  190 + // 2. 价格计算
193 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); 191 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
194 192
195 // 2.1 插入 TradeOrderDO 订单 193 // 2.1 插入 TradeOrderDO 订单
@@ -199,37 +197,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -199,37 +197,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
199 197
200 // 3. 订单创建完后的逻辑 198 // 3. 订单创建完后的逻辑
201 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO); 199 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
202 - // 3.1 拼团的特殊逻辑  
203 - // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去  
204 - // 拼团  
205 - if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {  
206 - createCombinationRecord(userId, createReqVO, orderItems, order);  
207 - }  
208 - // 3.2 秒杀的特殊逻辑  
209 - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {  
210 -  
211 - }  
212 - // 3.3 砍价的特殊逻辑  
213 200
214 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! 201 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
215 return order; 202 return order;
216 } 203 }
217 204
218 - private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {  
219 - MemberUserRespDTO user = memberUserApi.getUser(userId);  
220 - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());  
221 - // TODO 拼团一次应该只能选择一种规格的商品  
222 - TradeOrderItemDO orderItemDO = orderItems.get(0);  
223 - if (CollUtil.isNotEmpty(recordRespDTOS)) {  
224 - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));  
225 - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,  
226 - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);  
227 - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),  
228 - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());  
229 - }  
230 -  
231 - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));  
232 - }  
233 205
234 // TODO @puhui999:订单超时,自动取消; 206 // TODO @puhui999:订单超时,自动取消;
235 207
@@ -311,23 +283,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -311,23 +283,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
311 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, 283 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
312 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, 284 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
313 TradePriceCalculateRespBO calculateRespBO) { 285 TradePriceCalculateRespBO calculateRespBO) {
314 - Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);  
315 - // 1)如果是秒杀商品:额外扣减秒杀的库存;  
316 - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {  
317 - SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();  
318 - updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());  
319 - updateStockReqDTO.setCount(count);  
320 - updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {  
321 - SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();  
322 - item1.setSpuId(item.getSpuId());  
323 - item1.setSkuId(item.getSkuId());  
324 - item1.setCount(item.getCount());  
325 - return item1;  
326 - }));  
327 - seckillActivityApi.updateSeckillStock(updateStockReqDTO);  
328 - }  
329 - // 2)如果是砍价活动:额外扣减砍价的库存;  
330 - bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count); 286 + // 执行订单创建后置处理器
  287 + tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
  288 +
331 // 扣减积分 TODO 芋艿:待实现,需要前置; 289 // 扣减积分 TODO 芋艿:待实现,需要前置;
332 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 290 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
333 291
@@ -352,6 +310,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -352,6 +310,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
352 // 增加订单日志 TODO 芋艿:待实现 310 // 增加订单日志 TODO 芋艿:待实现
353 } 311 }
354 312
  313 +
355 private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) { 314 private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
356 // 创建支付单,用于后续的支付 315 // 创建支付单,用于后续的支付
357 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( 316 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
@@ -562,35 +521,68 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -562,35 +521,68 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
562 } 521 }
563 522
564 @Override 523 @Override
565 - // TODO @puhui999:考虑事务性 524 + @Transactional(rollbackFor = Exception.class)
566 public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) { 525 public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
567 - // 校验交易订单 526 + // 1、校验交易订单
568 TradeOrderDO order = validateOrderExists(reqVO.getId()); 527 TradeOrderDO order = validateOrderExists(reqVO.getId());
569 if (order.getPayStatus()) { 528 if (order.getPayStatus()) {
570 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); 529 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
571 } 530 }
  531 + // 2、校验订单项
  532 + List<TradeOrderItemDO> items = tradeOrderItemMapper.selectListByOrderId(order.getId());
  533 + if (CollUtil.isEmpty(items)) {
  534 + throw exception(ORDER_UPDATE_PRICE_FAIL_NOT_ITEM);
  535 + }
  536 + // 3、校验调价金额是否变化
572 if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) { 537 if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
573 throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL); 538 throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
574 } 539 }
575 540
576 - // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的  
577 - List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());  
578 - // TradeOrderItemDO 需要做 adjustPrice 的分摊  
579 - int price = reqVO.getAdjustPrice() / itemDOs.size();  
580 - itemDOs.forEach(item -> {  
581 - item.setAdjustPrice(price);  
582 - });  
583 - // 更新 TradeOrderItem  
584 - // TODO @puhui999:不要整个对象去更新哈;应该 new 一下;  
585 - tradeOrderItemMapper.updateBatch(itemDOs);  
586 - // 更新订单  
587 - // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格;  
588 - TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);  
589 - update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());  
590 - // TODO @芋艿:改价时,赠送的积分,要不要做改动??? 541 + // 4、更新订单
  542 + TradeOrderDO update = new TradeOrderDO();
  543 + update.setId(order.getId());
  544 + update.setAdjustPrice(reqVO.getAdjustPrice());
  545 + int orderPayPrice = order.getAdjustPrice() != null ? (order.getPayPrice() - order.getAdjustPrice())
  546 + + reqVO.getAdjustPrice() : order.getPayPrice() + reqVO.getAdjustPrice();
  547 + update.setPayPrice(orderPayPrice);
591 tradeOrderMapper.updateById(update); 548 tradeOrderMapper.updateById(update);
592 - // 更新支付订单  
593 - payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice()); 549 + // TODO @芋艿:改价时,赠送的积分,要不要做改动???
  550 +
  551 + // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
  552 + // TODO:先按 adjustPrice 实现,没明白 payPrice 怎么搞哈哈哈
  553 + // TODO @puhui999:就是对比新老 adjustPrice 的差值,然后计算补充的 adjustPrice 最终值;另外,可以不用区分 items.size 是不是 > 1 哈;应该是一致的逻辑;分摊的逻辑,有点类似 dividePrice 方法噢;
  554 + // 5、更新 TradeOrderItem
  555 + if (items.size() > 1) {
  556 + // TradeOrderItemDO 需要做 adjustPrice 的分摊
  557 + int price = reqVO.getAdjustPrice() / items.size();
  558 + int remainderPrice = reqVO.getAdjustPrice() % items.size();
  559 + List<TradeOrderItemDO> orders = new ArrayList<>();
  560 + for (int i = 0; i < items.size(); i++) {
  561 + // 把平摊后剩余的金额加到第一个订单项
  562 + if (remainderPrice != 0 && i == 0) {
  563 + orders.add(convertOrderItemPrice(items.get(i), price + remainderPrice));
  564 + }
  565 + orders.add(convertOrderItemPrice(items.get(i), price));
  566 + }
  567 + tradeOrderItemMapper.updateBatch(orders);
  568 + } else {
  569 + TradeOrderItemDO orderItem = items.get(0);
  570 + TradeOrderItemDO updateItem = convertOrderItemPrice(orderItem, reqVO.getAdjustPrice());
  571 + tradeOrderItemMapper.updateById(updateItem);
  572 + }
  573 +
  574 + // 6、更新支付订单
  575 + payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice());
  576 + }
  577 +
  578 + private TradeOrderItemDO convertOrderItemPrice(TradeOrderItemDO orderItem, Integer price) {
  579 + TradeOrderItemDO newOrderItem = new TradeOrderItemDO();
  580 + newOrderItem.setId(orderItem.getId());
  581 + newOrderItem.setAdjustPrice(price);
  582 + int payPrice = orderItem.getAdjustPrice() != null ? (orderItem.getPayPrice() - orderItem.getAdjustPrice())
  583 + + price : orderItem.getPayPrice() + price;
  584 + newOrderItem.setPayPrice(payPrice);
  585 + return newOrderItem;
594 } 586 }
595 587
596 @Override 588 @Override
@@ -733,6 +725,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -733,6 +725,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
733 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); 725 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
734 } 726 }
735 727
  728 + // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
  729 + tradeOrderHandlers.forEach(handler -> handler.rollbackStock());
  730 +
736 // 2.回滚库存 731 // 2.回滚库存
737 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); 732 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
738 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); 733 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.bo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +// TODO 芋艿:在想想这些参数的定义
  9 +/**
  10 + * 订单创建之后 Request BO
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@Data
  15 +public class TradeAfterOrderCreateReqBO {
  16 +
  17 + // ========== 拼团活动相关字段 ==========
  18 +
  19 + @Schema(description = "拼团活动编号", example = "1024")
  20 + private Long combinationActivityId;
  21 +
  22 + @Schema(description = "拼团团长编号", example = "2048")
  23 + private Long combinationHeadId;
  24 +
  25 + @NotNull(message = "SPU 编号不能为空")
  26 + private Long spuId;
  27 +
  28 + @NotNull(message = "SKU 编号活动商品不能为空")
  29 + private Long skuId;
  30 +
  31 + @NotNull(message = "订单编号不能为空")
  32 + private Long orderId;
  33 +
  34 + @NotNull(message = "用户编号不能为空")
  35 + private Long userId;
  36 +
  37 + @NotNull(message = "支付金额不能为空")
  38 + private Integer payPrice;
  39 +
  40 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.bo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.Valid;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +// TODO 芋艿:在想想这些参数的定义
  10 +/**
  11 + * 订单创建之前 Request BO
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@Data
  16 +public class TradeBeforeOrderCreateReqBO {
  17 +
  18 + @NotNull(message = "订单类型不能为空")
  19 + private Integer orderType;
  20 +
  21 + // ========== 秒杀活动相关字段 ==========
  22 +
  23 + @Schema(description = "秒杀活动编号", example = "1024")
  24 + private Long seckillActivityId;
  25 +
  26 + // ========== 拼团活动相关字段 ==========
  27 +
  28 + @Schema(description = "拼团活动编号", example = "1024")
  29 + private Long combinationActivityId;
  30 +
  31 + @Schema(description = "拼团团长编号", example = "2048")
  32 + private Long combinationHeadId;
  33 +
  34 + @Schema(description = "砍价活动编号", example = "123")
  35 + private Long bargainActivityId;
  36 +
  37 + @NotNull(message = "购买数量不能为空")
  38 + private Integer count;
  39 +
  40 + @NotNull(message = "活动商品不能为空")
  41 + private Item item;
  42 +
  43 + @Data
  44 + @Valid
  45 + public static class Item {
  46 +
  47 + @NotNull(message = "SPU 编号不能为空")
  48 + private Long spuId;
  49 +
  50 + @NotNull(message = "SKU 编号活动商品不能为空")
  51 + private Long skuId;
  52 +
  53 + @NotNull(message = "购买数量不能为空")
  54 + private Integer count;
  55 +
  56 + }
  57 +
  58 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/logger/TradeOrderLogCreateReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.bo.logger;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.constraints.NotNull;
  6 +
  7 +/**
  8 + * 订单日志的创建 Request BO
  9 + *
  10 + * @author 陈賝
  11 + * @since 2023/7/6 15:27
  12 + */
  13 +@Data
  14 +public class TradeOrderLogCreateReqBO {
  15 +
  16 + /**
  17 + * 用户编号
  18 + */
  19 + @NotNull(message = "用户编号不能为空")
  20 + private Long userId;
  21 + /**
  22 + * 用户类型
  23 + */
  24 + @NotNull(message = "用户类型不能为空")
  25 + private Integer userType;
  26 +
  27 + /**
  28 + * 订单编号
  29 + */
  30 + @NotNull(message = "订单编号")
  31 + private Long orderId;
  32 + /**
  33 + * 操作前状态
  34 + */
  35 + private Integer beforeStatus;
  36 + /**
  37 + * 操作后状态
  38 + */
  39 + @NotNull(message = "操作后的状态不能为空")
  40 + private Integer afterStatus;
  41 +
  42 + /**
  43 + * 操作类型
  44 + */
  45 + private Integer operateType;
  46 + /**
  47 + * 操作明细
  48 + */
  49 + private String content;
  50 +
  51 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
  5 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  6 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  7 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 砍价订单 handler 实现类
  14 + *
  15 + * @author HUIHUI
  16 + */
  17 +@Component
  18 +public class TradeBargainHandler implements TradeOrderHandler {
  19 +
  20 + @Resource
  21 + private BargainActivityApi bargainActivityApi;
  22 +
  23 + @Override
  24 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  25 + // 如果是秒杀订单
  26 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
  27 + return;
  28 + }
  29 +
  30 + // 额外扣减砍价的库存
  31 + bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
  32 + }
  33 +
  34 + @Override
  35 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void rollbackStock() {
  41 +
  42 + }
  43 +
  44 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
  6 +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  7 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  8 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  9 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import javax.annotation.Resource;
  13 +
  14 +/**
  15 + * 拼团订单 handler 接口实现类
  16 + *
  17 + * @author HUIHUI
  18 + */
  19 +@Component
  20 +public class TradeCombinationHandler implements TradeOrderHandler {
  21 +
  22 + @Resource
  23 + private CombinationApi combinationApi;
  24 + @Resource
  25 + private CombinationRecordApi combinationRecordApi;
  26 +
  27 + @Override
  28 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  29 + // 如果是拼团订单;
  30 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
  31 + return;
  32 + }
  33 +
  34 + // 校验是否满足拼团活动相关限制
  35 + combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
  36 + }
  37 +
  38 + @Override
  39 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  40 + // 创建砍价记录
  41 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
  42 + }
  43 +
  44 + @Override
  45 + public void rollbackStock() {
  46 +
  47 + }
  48 +
  49 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  4 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  5 +
  6 +/**
  7 + * 订单活动特殊逻辑处理器 handler 接口
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +public interface TradeOrderHandler {
  12 +
  13 + /**
  14 + * 订单创建前
  15 + *
  16 + * @param reqBO 请求
  17 + */
  18 + void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO);
  19 +
  20 + /**
  21 + * 订单创建后
  22 + *
  23 + * @param reqBO 请求
  24 + */
  25 + void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
  26 +
  27 + /**
  28 + * 回滚活动相关库存
  29 + */
  30 + void rollbackStock();
  31 +
  32 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
  5 +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  6 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  7 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  8 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import javax.annotation.Resource;
  12 +
  13 +/**
  14 + * 秒杀订单 handler 实现类
  15 + *
  16 + * @author HUIHUI
  17 + */
  18 +@Component
  19 +public class TradeSeckillHandler implements TradeOrderHandler {
  20 +
  21 + @Resource
  22 + private SeckillActivityApi seckillActivityApi;
  23 +
  24 + @Override
  25 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  26 + // 如果是秒杀订单:额外扣减秒杀的库存;
  27 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
  28 + return;
  29 + }
  30 +
  31 + seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
  32 + }
  33 +
  34 + @Override
  35 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void rollbackStock() {
  41 +
  42 + }
  43 +
  44 +}
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 { @@ -29,13 +29,12 @@ public interface PayOrderApi {
29 */ 29 */
30 PayOrderRespDTO getOrder(Long id); 30 PayOrderRespDTO getOrder(Long id);
31 31
32 - // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id;  
33 /** 32 /**
34 * 更新支付订单价格 33 * 更新支付订单价格
35 * 34 *
36 - * @param payOrderId 支付单编号 35 + * @param id 支付单编号
37 * @param payPrice 支付单价格 36 * @param payPrice 支付单价格
38 */ 37 */
39 - void updatePayOrderPriceById(Long payOrderId, Integer payPrice); 38 + void updatePayOrderPrice(Long id, Integer payPrice);
40 39
41 } 40 }
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 { @@ -21,19 +21,17 @@ public interface ErrorCodeConstants {
21 ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道"); 21 ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
22 22
23 // ========== ORDER 模块 1007002000 ========== 23 // ========== ORDER 模块 1007002000 ==========
24 - ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");  
25 - ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");  
26 - ErrorCode ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");  
27 - ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");  
28 - ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");  
29 - ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");  
30 - ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");  
31 - ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化"); 24 + ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
  25 + ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
  26 + ErrorCode PAY_ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
  27 + ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
  28 + ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
  29 + ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
32 30
33 // ========== ORDER 模块(拓展单) 1007003000 ========== 31 // ========== ORDER 模块(拓展单) 1007003000 ==========
34 - ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");  
35 - ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");  
36 - ErrorCode ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果"); 32 + ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
  33 + ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
  34 + ErrorCode PAY_ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
37 35
38 // ========== 支付模块(退款) 1007006000 ========== 36 // ========== 支付模块(退款) 1007006000 ==========
39 ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额"); 37 ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
@@ -48,6 +46,11 @@ public interface ErrorCodeConstants { @@ -48,6 +46,11 @@ public interface ErrorCodeConstants {
48 ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易"); 46 ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易");
49 ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对"); 47 ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对");
50 ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款"); 48 ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款");
  49 + ErrorCode WALLET_RECHARGE_NOT_FOUND = new ErrorCode(1007007005, "钱包充值记录不存在");
  50 + ErrorCode WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007007006, "钱包充值更新支付状态失败,钱包充值记录不是【未支付】状态");
  51 + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1007007007, "钱包充值更新支付状态失败,支付单编号不匹配");
  52 + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007007008, "钱包充值更新支付状态失败,支付单状态不是【支付成功】状态");
  53 + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1007007009, "钱包充值更新支付状态失败,支付单金额不匹配");
51 54
52 // ========== 示例订单 1007900000 ========== 55 // ========== 示例订单 1007900000 ==========
53 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在"); 56 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
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 { @@ -32,8 +32,8 @@ public class PayOrderApiImpl implements PayOrderApi {
32 } 32 }
33 33
34 @Override 34 @Override
35 - public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {  
36 - payOrderService.updatePayOrderPriceById(payOrderId, payPrice); 35 + public void updatePayOrderPrice(Long id, Integer payPrice) {
  36 + payOrderService.updatePayOrderPrice(id, payPrice);
37 } 37 }
38 38
39 } 39 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.app.wallet;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  5 +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
  6 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
  7 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO;
  8 +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert;
  9 +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
  10 +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargeService;
  11 +import io.swagger.v3.oas.annotations.Operation;
  12 +import io.swagger.v3.oas.annotations.tags.Tag;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.PostMapping;
  16 +import org.springframework.web.bind.annotation.RequestBody;
  17 +import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RestController;
  19 +
  20 +import javax.annotation.Resource;
  21 +import javax.annotation.security.PermitAll;
  22 +import javax.validation.Valid;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
  26 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
  27 +
  28 +@Tag(name = "用户 APP - 钱包充值")
  29 +@RestController
  30 +@RequestMapping("/pay/wallet-recharge")
  31 +@Validated
  32 +@Slf4j
  33 +public class AppPayWalletRechargeController {
  34 +
  35 + @Resource
  36 + private PayWalletRechargeService payWalletRechargeService;
  37 +
  38 + @PostMapping("/create")
  39 + @Operation(summary = "创建钱包充值记录")
  40 + public CommonResult<AppPayWalletRechargeCreateRespVO> createWalletRecharge(@Valid @RequestBody AppPayWalletRechargeCreateReqVO reqVO) {
  41 + PayWalletRechargeDO walletRecharge = payWalletRechargeService.createWalletRecharge(getLoginUserId(),
  42 + getLoginUserType(), reqVO);
  43 + return success(PayWalletRechargeConvert.INSTANCE.convert(walletRecharge));
  44 + }
  45 +
  46 + @PostMapping("/update-paid")
  47 + @Operation(summary = "更新钱包充值为已充值") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
  48 + @PermitAll // 无需登录,安全由 内部校验实现
  49 + @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
  50 + public CommonResult<Boolean> updateWalletRechargerPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
  51 + payWalletRechargeService.updateWalletRechargerPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
  52 + notifyReqDTO.getPayOrderId());
  53 + return success(true);
  54 + }
  55 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletTransactionController.java
@@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController; @@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController;
18 18
19 import javax.annotation.Resource; 19 import javax.annotation.Resource;
20 import javax.validation.Valid; 20 import javax.validation.Valid;
21 -  
22 import java.time.LocalDateTime; 21 import java.time.LocalDateTime;
23 22
24 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.DecimalMin;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "用户 APP - 创建钱包充值 Request VO")
  10 +@Data
  11 +public class AppPayWalletRechargeCreateReqVO {
  12 +
  13 + @Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  14 + @NotNull(message = "支付金额不能为空")
  15 + @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
  16 + private Integer payPrice;
  17 +
  18 + @Schema(description = "钱包赠送金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  19 + @NotNull(message = "钱包赠送金额不能为空")
  20 + @DecimalMin(value = "0", message = "钱包赠送金额必须大于等于零")
  21 + private Integer walletBonus;
  22 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 APP - 创建钱包充值 Resp VO")
  7 +@Data
  8 +public class AppPayWalletRechargeCreateRespVO {
  9 +
  10 + @Schema(description = "钱包充值编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  11 + private Long id;
  12 +
  13 + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  14 + private Long payOrderId;
  15 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.convert.wallet;
  2 +
  3 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
  4 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO;
  5 +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.factory.Mappers;
  8 +
  9 +/**
  10 + * @author jason
  11 + */
  12 +@Mapper
  13 +public interface PayWalletRechargeConvert {
  14 +
  15 + PayWalletRechargeConvert INSTANCE = Mappers.getMapper(PayWalletRechargeConvert.class);
  16 +
  17 + PayWalletRechargeDO convert(AppPayWalletRechargeCreateReqVO vo);
  18 +
  19 + default PayWalletRechargeDO convert(Long walletId, AppPayWalletRechargeCreateReqVO vo) {
  20 + PayWalletRechargeDO walletRecharge = convert(vo);
  21 + return walletRecharge.setWalletId(walletId)
  22 + .setPrice(walletRecharge.getPayPrice() + walletRecharge.getWalletBonus());
  23 + }
  24 +
  25 + AppPayWalletRechargeCreateRespVO convert(PayWalletRechargeDO bean);
  26 +
  27 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
@@ -42,6 +42,19 @@ public interface PayWalletMapper extends BaseMapperX&lt;PayWalletDO&gt; { @@ -42,6 +42,19 @@ public interface PayWalletMapper extends BaseMapperX&lt;PayWalletDO&gt; {
42 .ge(PayWalletDO::getBalance, price); // cas 逻辑 42 .ge(PayWalletDO::getBalance, price); // cas 逻辑
43 return update(null, lambdaUpdateWrapper); 43 return update(null, lambdaUpdateWrapper);
44 } 44 }
  45 +
  46 + /**
  47 + * 当充值的时候,更新钱包
  48 + * @param price 钱包金额
  49 + * @param id 钱包 id
  50 + */
  51 + default int updateWhenRecharge(Integer price, Long id){
  52 + LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
  53 + .setSql(" balance = balance + " + price
  54 + + ", total_recharge = total_recharge + " + price)
  55 + .eq(PayWalletDO::getId, id);
  56 + return update(null, lambdaUpdateWrapper);
  57 + }
45 } 58 }
46 59
47 60
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; @@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
26 import java.util.Map; 26 import java.util.Map;
27 27
28 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; 28 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
29 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND; 29 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND;
30 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND; 30 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
31 31
32 /** 32 /**
@@ -98,8 +98,8 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -98,8 +98,8 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
98 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); 98 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
99 // 支付交易拓展单不存在, 返回关闭状态 99 // 支付交易拓展单不存在, 返回关闭状态
100 if (orderExtension == null) { 100 if (orderExtension == null) {
101 - return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),  
102 - ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, ""); 101 + return PayOrderRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()),
  102 + PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
103 } 103 }
104 // 关闭状态 104 // 关闭状态
105 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { 105 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {
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; @@ -25,7 +25,7 @@ import java.util.HashMap;
25 import java.util.Map; 25 import java.util.Map;
26 import java.util.Objects; 26 import java.util.Objects;
27 27
28 -import static cn.hutool.core.util.ObjectUtil.*; 28 +import static cn.hutool.core.util.ObjectUtil.notEqual;
29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; 30 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
@@ -156,7 +156,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { @@ -156,7 +156,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
156 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); 156 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
157 if (payOrder == null) { 157 if (payOrder == null) {
158 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); 158 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
159 - throw exception(ORDER_NOT_FOUND); 159 + throw exception(PAY_ORDER_NOT_FOUND);
160 } 160 }
161 // 2.2 校验支付单已支付 161 // 2.2 校验支付单已支付
162 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { 162 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
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 { @@ -101,10 +101,10 @@ public interface PayOrderService {
101 /** 101 /**
102 * 更新支付订单价格 102 * 更新支付订单价格
103 * 103 *
104 - * @param payOrderId 支付单编号 104 + * @param id 支付单编号
105 * @param payPrice 支付单价格 105 * @param payPrice 支付单价格
106 */ 106 */
107 - void updatePayOrderPriceById(Long payOrderId, Integer payPrice); 107 + void updatePayOrderPrice(Long id, Integer payPrice);
108 108
109 /** 109 /**
110 * 获得支付订单 110 * 获得支付订单
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 { @@ -160,7 +160,7 @@ public class PayOrderServiceImpl implements PayOrderService {
160 getSelf().notifyOrder(channel, unifiedOrderResp); 160 getSelf().notifyOrder(channel, unifiedOrderResp);
161 // 如有渠道错误码,则抛出业务异常,提示用户 161 // 如有渠道错误码,则抛出业务异常,提示用户
162 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) { 162 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
163 - throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(), 163 + throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
164 unifiedOrderResp.getChannelErrorMsg()); 164 unifiedOrderResp.getChannelErrorMsg());
165 } 165 }
166 // 此处需要读取最新的状态 166 // 此处需要读取最新的状态
@@ -172,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -172,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService {
172 private PayOrderDO validateOrderCanSubmit(Long id) { 172 private PayOrderDO validateOrderCanSubmit(Long id) {
173 PayOrderDO order = orderMapper.selectById(id); 173 PayOrderDO order = orderMapper.selectById(id);
174 if (order == null) { // 是否存在 174 if (order == null) { // 是否存在
175 - throw exception(ORDER_NOT_FOUND); 175 + throw exception(PAY_ORDER_NOT_FOUND);
176 } 176 }
177 if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付 177 if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付
178 - throw exception(ORDER_STATUS_IS_SUCCESS); 178 + throw exception(PAY_ORDER_STATUS_IS_SUCCESS);
179 } 179 }
180 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 180 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
181 - throw exception(ORDER_STATUS_IS_NOT_WAITING); 181 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
182 } 182 }
183 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期 183 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
184 - throw exception(ORDER_IS_EXPIRED); 184 + throw exception(PAY_ORDER_IS_EXPIRED);
185 } 185 }
186 186
187 // 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常 187 // 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常
@@ -202,7 +202,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -202,7 +202,7 @@ public class PayOrderServiceImpl implements PayOrderService {
202 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { 202 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
203 log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]", 203 log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]",
204 id, orderExtension.getId()); 204 id, orderExtension.getId());
205 - throw exception(ORDER_EXTENSION_IS_PAID); 205 + throw exception(PAY_ORDER_EXTENSION_IS_PAID);
206 } 206 }
207 // 情况二:调用三方接口,查询支付单状态,是不是已支付 207 // 情况二:调用三方接口,查询支付单状态,是不是已支付
208 PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId()); 208 PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId());
@@ -214,7 +214,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -214,7 +214,7 @@ public class PayOrderServiceImpl implements PayOrderService {
214 if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) { 214 if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) {
215 log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]", 215 log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]",
216 id, toJsonString(respDTO)); 216 id, toJsonString(respDTO));
217 - throw exception(ORDER_EXTENSION_IS_PAID); 217 + throw exception(PAY_ORDER_EXTENSION_IS_PAID);
218 } 218 }
219 }); 219 });
220 } 220 }
@@ -254,9 +254,10 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -254,9 +254,10 @@ public class PayOrderServiceImpl implements PayOrderService {
254 * 通知并更新订单的支付结果 254 * 通知并更新订单的支付结果
255 * 255 *
256 * @param channel 支付渠道 256 * @param channel 支付渠道
257 - * @param notify 通知 257 + * @param notify 通知
258 */ 258 */
259 - @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效 259 + @Transactional(rollbackFor = Exception.class)
  260 + // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
260 public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) { 261 public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
261 // 情况一:支付成功的回调 262 // 情况一:支付成功的回调
262 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { 263 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
@@ -295,21 +296,21 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -295,21 +296,21 @@ public class PayOrderServiceImpl implements PayOrderService {
295 // 1. 查询 PayOrderExtensionDO 296 // 1. 查询 PayOrderExtensionDO
296 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); 297 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
297 if (orderExtension == null) { 298 if (orderExtension == null) {
298 - throw exception(ORDER_EXTENSION_NOT_FOUND); 299 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
299 } 300 }
300 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 301 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
301 log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId()); 302 log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId());
302 return orderExtension; 303 return orderExtension;
303 } 304 }
304 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 305 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
305 - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 306 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
306 } 307 }
307 308
308 // 2. 更新 PayOrderExtensionDO 309 // 2. 更新 PayOrderExtensionDO
309 int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), 310 int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
310 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); 311 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
311 if (updateCounts == 0) { // 校验状态,必须是待支付 312 if (updateCounts == 0) { // 校验状态,必须是待支付
312 - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 313 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
313 } 314 }
314 log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId()); 315 log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId());
315 return orderExtension; 316 return orderExtension;
@@ -318,17 +319,17 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -318,17 +319,17 @@ public class PayOrderServiceImpl implements PayOrderService {
318 /** 319 /**
319 * 更新 PayOrderDO 支付成功 320 * 更新 PayOrderDO 支付成功
320 * 321 *
321 - * @param channel 支付渠道 322 + * @param channel 支付渠道
322 * @param orderExtension 支付拓展单 323 * @param orderExtension 支付拓展单
323 - * @param notify 通知回调 324 + * @param notify 通知回调
324 * @return 是否之前已经成功回调 325 * @return 是否之前已经成功回调
325 */ 326 */
326 private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension, 327 private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
327 - PayOrderRespDTO notify) { 328 + PayOrderRespDTO notify) {
328 // 1. 判断 PayOrderDO 是否处于待支付 329 // 1. 判断 PayOrderDO 是否处于待支付
329 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); 330 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
330 if (order == null) { 331 if (order == null) {
331 - throw exception(ORDER_NOT_FOUND); 332 + throw exception(PAY_ORDER_NOT_FOUND);
332 } 333 }
333 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新 334 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
334 && Objects.equals(order.getExtensionId(), orderExtension.getId())) { 335 && Objects.equals(order.getExtensionId(), orderExtension.getId())) {
@@ -336,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -336,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
336 return true; 337 return true;
337 } 338 }
338 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 339 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
339 - throw exception(ORDER_STATUS_IS_NOT_WAITING); 340 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
340 } 341 }
341 342
342 // 2. 更新 PayOrderDO 343 // 2. 更新 PayOrderDO
@@ -346,10 +347,10 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -346,10 +347,10 @@ public class PayOrderServiceImpl implements PayOrderService {
346 .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo()) 347 .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
347 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId()) 348 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
348 .channelFeeRate(channel.getFeeRate()) 349 .channelFeeRate(channel.getFeeRate())
349 - .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate())) 350 + .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
350 .build()); 351 .build());
351 if (updateCounts == 0) { // 校验状态,必须是待支付 352 if (updateCounts == 0) { // 校验状态,必须是待支付
352 - throw exception(ORDER_STATUS_IS_NOT_WAITING); 353 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
353 } 354 }
354 log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId()); 355 log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
355 return false; 356 return false;
@@ -363,7 +364,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -363,7 +364,7 @@ public class PayOrderServiceImpl implements PayOrderService {
363 // 1. 查询 PayOrderExtensionDO 364 // 1. 查询 PayOrderExtensionDO
364 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); 365 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
365 if (orderExtension == null) { 366 if (orderExtension == null) {
366 - throw exception(ORDER_EXTENSION_NOT_FOUND); 367 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
367 } 368 }
368 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新 369 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
369 log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId()); 370 log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId());
@@ -375,7 +376,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -375,7 +376,7 @@ public class PayOrderServiceImpl implements PayOrderService {
375 return; 376 return;
376 } 377 }
377 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 378 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
378 - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 379 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
379 } 380 }
380 381
381 // 2. 更新 PayOrderExtensionDO 382 // 2. 更新 PayOrderExtensionDO
@@ -383,7 +384,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -383,7 +384,7 @@ public class PayOrderServiceImpl implements PayOrderService {
383 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) 384 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
384 .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); 385 .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
385 if (updateCounts == 0) { // 校验状态,必须是待支付 386 if (updateCounts == 0) { // 校验状态,必须是待支付
386 - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 387 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
387 } 388 }
388 log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId()); 389 log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId());
389 } 390 }
@@ -392,10 +393,10 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -392,10 +393,10 @@ public class PayOrderServiceImpl implements PayOrderService {
392 public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) { 393 public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
393 PayOrderDO order = orderMapper.selectById(id); 394 PayOrderDO order = orderMapper.selectById(id);
394 if (order == null) { 395 if (order == null) {
395 - throw exception(ORDER_NOT_FOUND); 396 + throw exception(PAY_ORDER_NOT_FOUND);
396 } 397 }
397 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) { 398 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
398 - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR); 399 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
399 } 400 }
400 if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) { 401 if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
401 throw exception(REFUND_PRICE_EXCEED); 402 throw exception(REFUND_PRICE_EXCEED);
@@ -407,16 +408,21 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -407,16 +408,21 @@ public class PayOrderServiceImpl implements PayOrderService {
407 .setStatus(PayOrderStatusEnum.REFUND.getStatus()); 408 .setStatus(PayOrderStatusEnum.REFUND.getStatus());
408 int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj); 409 int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
409 if (updateCount == 0) { 410 if (updateCount == 0) {
410 - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR); 411 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
411 } 412 }
412 } 413 }
413 414
414 @Override 415 @Override
415 - public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {  
416 - // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈;  
417 - PayOrderDO order = orderMapper.selectById(payOrderId); 416 + public void updatePayOrderPrice(Long id, Integer payPrice) {
  417 + PayOrderDO order = orderMapper.selectById(id);
418 if (order == null) { 418 if (order == null) {
419 - throw exception(ORDER_NOT_FOUND); 419 + throw exception(PAY_ORDER_NOT_FOUND);
  420 + }
  421 + if (ObjectUtil.notEqual(PayOrderStatusEnum.WAITING.getStatus(), order.getStatus())) {
  422 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
  423 + }
  424 + if (ObjectUtil.equal(order.getPrice(), payPrice)) {
  425 + return;
420 } 426 }
421 427
422 order.setPrice(payPrice); 428 order.setPrice(payPrice);
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 { @@ -160,11 +160,11 @@ public class PayRefundServiceImpl implements PayRefundService {
160 private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { 160 private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
161 PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); 161 PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
162 if (order == null) { 162 if (order == null) {
163 - throw exception(ORDER_NOT_FOUND); 163 + throw exception(PAY_ORDER_NOT_FOUND);
164 } 164 }
165 // 校验状态,必须是已支付、或者已退款 165 // 校验状态,必须是已支付、或者已退款
166 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) { 166 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
167 - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR); 167 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
168 } 168 }
169 169
170 // 校验金额,退款金额不能大于原定的金额 170 // 校验金额,退款金额不能大于原定的金额
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.service.wallet;
  2 +
  3 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
  4 +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
  5 +
  6 +/**
  7 + * 钱包充值 Service 接口
  8 + *
  9 + * @author jason
  10 + */
  11 +public interface PayWalletRechargeService {
  12 +
  13 + /**
  14 + * 创建钱包充值记录
  15 + * @param userId 用户 id
  16 + * @param userType 用户类型
  17 + * @param vo 钱包充值请求 vo
  18 + * @return 钱包充值记录
  19 + */
  20 + PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, AppPayWalletRechargeCreateReqVO vo);
  21 +
  22 +
  23 + /**
  24 + * 更新钱包充值成功
  25 + * @param walletRechargeId 钱包充值 id
  26 + * @param payOrderId 支付订单 id
  27 + */
  28 + void updateWalletRechargerPaid(Long walletRechargeId, Long payOrderId);
  29 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.service.wallet;
  2 +
  3 +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
  4 +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
  5 +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert;
  6 +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
  7 +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
  8 +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
  9 +import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
  10 +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  11 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
  12 +import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
  16 +
  17 +import javax.annotation.Resource;
  18 +import java.time.Duration;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.ObjectUtil.notEqual;
  22 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
  24 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  25 +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
  26 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
  27 +
  28 +/**
  29 + * 钱包充值 Service 实现类
  30 + *
  31 + * @author jason
  32 + */
  33 +@Service
  34 +@Slf4j
  35 +public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
  36 + /**
  37 + * TODO 放到 配置文件中
  38 + */
  39 + private static final Long WALLET_PAY_APP_ID = 8L;
  40 +
  41 + private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值";
  42 +
  43 + @Resource
  44 + private PayWalletRechargeMapper walletRechargeMapper;
  45 + @Resource
  46 + private PayWalletService payWalletService;
  47 + @Resource
  48 + private PayOrderService payOrderService;
  49 +
  50 +
  51 + @Override
  52 + @Transactional(rollbackFor = Exception.class)
  53 + public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, AppPayWalletRechargeCreateReqVO vo) {
  54 + // 1. 获取钱包
  55 + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType);
  56 + // 2. 新增钱包充值记录
  57 + PayWalletRechargeDO walletRecharge = PayWalletRechargeConvert.INSTANCE.convert(wallet.getId(), vo);
  58 + walletRechargeMapper.insert(walletRecharge);
  59 + // 3.创建支付单
  60 + Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO()
  61 + .setAppId(WALLET_PAY_APP_ID).setUserIp(getClientIP())
  62 + .setMerchantOrderId(walletRecharge.getId().toString()) // 业务的订单编号
  63 + .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("").setPrice(walletRecharge.getPayPrice())
  64 + .setExpireTime(addTime(Duration.ofHours(2L))));
  65 + // 4.更新钱包充值记录中支付订单
  66 + walletRechargeMapper.updateById(new PayWalletRechargeDO().setPayOrderId(payOrderId)
  67 + .setId(walletRecharge.getId()));
  68 + return walletRechargeMapper.selectById(walletRecharge.getId());
  69 + }
  70 +
  71 + @Override
  72 + @Transactional(rollbackFor = Exception.class)
  73 + public void updateWalletRechargerPaid(Long walletRechargeId, Long payOrderId) {
  74 + // 1. 获取钱包充值记录
  75 + PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(walletRechargeId);
  76 + if (walletRecharge == null) {
  77 + log.error("[updateWalletRechargerPaid],钱包充值记录不存在,钱包充值 Id:{} ", walletRechargeId);
  78 + throw exception(WALLET_RECHARGE_NOT_FOUND);
  79 + }
  80 + // 2. 校验钱包充值是否可以支付
  81 + PayOrderDO payOrderDO = validateWalletRechargerCanPaid(walletRecharge, payOrderId);
  82 + // 3. 更新钱包充值的支付状态
  83 + int updateCount = walletRechargeMapper.updateByIdAndPaid(walletRechargeId,false, new PayWalletRechargeDO().setId(walletRechargeId)
  84 + .setPayStatus(true).setPayTime(LocalDateTime.now())
  85 + .setPayChannelCode(payOrderDO.getChannelCode()));
  86 + if (updateCount == 0) {
  87 + throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID);
  88 + }
  89 + // 4. 更新钱包余额
  90 + payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(walletRechargeId),
  91 + PayWalletBizTypeEnum.RECHARGE, walletRecharge.getPrice());
  92 + }
  93 +
  94 + private PayOrderDO validateWalletRechargerCanPaid(PayWalletRechargeDO walletRecharge, Long payOrderId) {
  95 +
  96 + // 1.1 校验充值记录的支付状态
  97 + if (walletRecharge.getPayStatus()) {
  98 + log.error("[validateWalletRechargerCanPaid][钱包({}) 不处于未支付状态! 钱包数据是:{}]",
  99 + walletRecharge.getId(), toJsonString(walletRecharge));
  100 + throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID);
  101 + }
  102 + // 1.2 校验支付订单匹配
  103 + if (notEqual(walletRecharge.getPayOrderId(), payOrderId)) { // 支付单号
  104 + log.error("[validateWalletRechargerCanPaid][钱包({}) 支付单不匹配({}),请进行处理! 钱包数据是:{}]",
  105 + walletRecharge.getId(), payOrderId, toJsonString(walletRecharge));
  106 + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR);
  107 + }
  108 + // 2.1 校验支付单是否存在
  109 + PayOrderDO payOrder = payOrderService.getOrder(payOrderId);
  110 + if (payOrder == null) {
  111 + log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 不存在,请进行处理!]",
  112 + walletRecharge.getId(), payOrderId);
  113 + throw exception(PAY_ORDER_NOT_FOUND);
  114 + }
  115 + // 2.2 校验支付单已支付
  116 + if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
  117 + log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
  118 + walletRecharge.getId(), payOrderId, toJsonString(payOrder));
  119 + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS);
  120 + }
  121 + // 2.3 校验支付金额一致
  122 + if (notEqual(payOrder.getPrice(), walletRecharge.getPayPrice())) {
  123 + log.error("[validateDemoOrderCanPaid][钱包({}) payOrder({}) 支付金额不匹配,请进行处理!钱包 数据是:{},payOrder 数据是:{}]",
  124 + walletRecharge.getId(), payOrderId, toJsonString(walletRecharge), toJsonString(payOrder));
  125 + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH);
  126 + }
  127 + // 2.4 校验支付订单的商户订单匹配
  128 + if (notEqual(payOrder.getMerchantOrderId(), walletRecharge.getId().toString())) {
  129 + log.error("[validateDemoOrderCanPaid][钱包({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
  130 + walletRecharge.getId(), payOrderId, toJsonString(payOrder));
  131 + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR);
  132 + }
  133 + return payOrder;
  134 + }
  135 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
@@ -22,6 +22,13 @@ public interface PayWalletService { @@ -22,6 +22,13 @@ public interface PayWalletService {
22 PayWalletDO getOrCreateWallet(Long userId, Integer userType); 22 PayWalletDO getOrCreateWallet(Long userId, Integer userType);
23 23
24 /** 24 /**
  25 + * 获取钱包信息
  26 + *
  27 + * @param walletId 钱包 id
  28 + */
  29 + PayWalletDO getWallet(Long walletId);
  30 +
  31 + /**
25 * 钱包订单支付 32 * 钱包订单支付
26 * 33 *
27 * @param userId 用户 id 34 * @param userId 用户 id
@@ -56,14 +63,13 @@ public interface PayWalletService { @@ -56,14 +63,13 @@ public interface PayWalletService {
56 /** 63 /**
57 * 增加钱包余额 64 * 增加钱包余额
58 * 65 *
59 - * @param userId 用户 id  
60 - * @param userType 用户类型 66 + * @param walletId 钱包 id
61 * @param bizId 业务关联 id 67 * @param bizId 业务关联 id
62 * @param bizType 业务关联分类 68 * @param bizType 业务关联分类
63 * @param price 增加金额 69 * @param price 增加金额
64 * @return 钱包流水 70 * @return 钱包流水
65 */ 71 */
66 - PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,  
67 - Long bizId, PayWalletBizTypeEnum bizType, Integer price); 72 + PayWalletTransactionDO addWalletBalance(Long walletId, String bizId,
  73 + PayWalletBizTypeEnum bizType, Integer price);
68 74
69 } 75 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
@@ -56,12 +56,17 @@ public class PayWalletServiceImpl implements PayWalletService { @@ -56,12 +56,17 @@ public class PayWalletServiceImpl implements PayWalletService {
56 } 56 }
57 57
58 @Override 58 @Override
  59 + public PayWalletDO getWallet(Long walletId) {
  60 + return walletMapper.selectById(walletId);
  61 + }
  62 +
  63 + @Override
59 @Transactional(rollbackFor = Exception.class) 64 @Transactional(rollbackFor = Exception.class)
60 public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) { 65 public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
61 // 1. 判断支付交易拓展单是否存 66 // 1. 判断支付交易拓展单是否存
62 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); 67 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
63 if (orderExtension == null) { 68 if (orderExtension == null) {
64 - throw exception(ORDER_EXTENSION_NOT_FOUND); 69 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
65 } 70 }
66 // 2. 扣减余额 71 // 2. 扣减余额
67 return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price); 72 return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
@@ -80,7 +85,7 @@ public class PayWalletServiceImpl implements PayWalletService { @@ -80,7 +85,7 @@ public class PayWalletServiceImpl implements PayWalletService {
80 PayWalletDO wallet = walletMapper.selectById(walletId); 85 PayWalletDO wallet = walletMapper.selectById(walletId);
81 Assert.notNull(wallet, "钱包 {} 不存在", walletId); 86 Assert.notNull(wallet, "钱包 {} 不存在", walletId);
82 // 2. 增加余额 87 // 2. 增加余额
83 - return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice); 88 + return addWalletBalance(walletId, String.valueOf(payRefund.getId()), PAYMENT_REFUND, refundPrice);
84 } 89 }
85 90
86 /** 91 /**
@@ -139,25 +144,33 @@ public class PayWalletServiceImpl implements PayWalletService { @@ -139,25 +144,33 @@ public class PayWalletServiceImpl implements PayWalletService {
139 } 144 }
140 145
141 @Override 146 @Override
142 - public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,  
143 - Long bizId, PayWalletBizTypeEnum bizType, Integer price) { 147 + public PayWalletTransactionDO addWalletBalance(Long walletId,
  148 + String bizId, PayWalletBizTypeEnum bizType, Integer price) {
144 // 1. 获取钱包 149 // 1. 获取钱包
145 - PayWalletDO payWallet = getOrCreateWallet(userId, userType); 150 + PayWalletDO payWallet = getWallet(walletId);
  151 +
  152 + if (payWallet == null) {
  153 + log.error("[addWalletBalance],用户钱包({})不存在.", walletId);
  154 + throw exception(WALLET_NOT_FOUND);
  155 + }
  156 +
146 switch (bizType) { 157 switch (bizType) {
147 case PAYMENT_REFUND: { 158 case PAYMENT_REFUND: {
148 - // 更新退款 159 + // 退款更新
149 walletMapper.updateWhenConsumptionRefund(price, payWallet.getId()); 160 walletMapper.updateWhenConsumptionRefund(price, payWallet.getId());
150 break; 161 break;
151 } 162 }
152 case RECHARGE: { 163 case RECHARGE: {
153 - //TODO 164 + // 充值更新
  165 + walletMapper.updateWhenRecharge(price, payWallet.getId());
154 break; 166 break;
155 } 167 }
  168 + // TODO 其它类型
156 } 169 }
157 170
158 // 2. 生成钱包流水 171 // 2. 生成钱包流水
159 CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId()) 172 CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId())
160 - .setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(String.valueOf(bizId)) 173 + .setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(bizId)
161 .setBizType(bizType.getType()).setTitle(bizType.getDescription()); 174 .setBizType(bizType.getType()).setTitle(bizType.getDescription());
162 return walletTransactionService.createWalletTransaction(bo); 175 return walletTransactionService.createWalletTransaction(bo);
163 } 176 }
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 { @@ -261,7 +261,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
261 String userIp = randomString(); 261 String userIp = randomString();
262 262
263 // 调用, 并断言异常 263 // 调用, 并断言异常
264 - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND); 264 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_NOT_FOUND);
265 } 265 }
266 266
267 @Test 267 @Test
@@ -274,7 +274,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -274,7 +274,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
274 String userIp = randomString(); 274 String userIp = randomString();
275 275
276 // 调用, 并断言异常 276 // 调用, 并断言异常
277 - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING); 277 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_NOT_WAITING);
278 } 278 }
279 279
280 @Test 280 @Test
@@ -287,7 +287,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -287,7 +287,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
287 String userIp = randomString(); 287 String userIp = randomString();
288 288
289 // 调用, 并断言异常 289 // 调用, 并断言异常
290 - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_SUCCESS); 290 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_SUCCESS);
291 } 291 }
292 292
293 @Test 293 @Test
@@ -301,7 +301,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -301,7 +301,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
301 String userIp = randomString(); 301 String userIp = randomString();
302 302
303 // 调用, 并断言异常 303 // 调用, 并断言异常
304 - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED); 304 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_IS_EXPIRED);
305 } 305 }
306 306
307 @Test 307 @Test
@@ -366,7 +366,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -366,7 +366,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
366 366
367 // 调用,并断言异常 367 // 调用,并断言异常
368 assertServiceException(() -> orderService.submitOrder(reqVO, userIp), 368 assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
369 - ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常"); 369 + PAY_ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
370 // 断言,数据记录(PayOrderExtensionDO) 370 // 断言,数据记录(PayOrderExtensionDO)
371 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null); 371 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
372 assertNotNull(orderExtension); 372 assertNotNull(orderExtension);
@@ -450,7 +450,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -450,7 +450,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
450 450
451 // 调用,并断言异常 451 // 调用,并断言异常
452 assertServiceException(() -> orderService.validateOrderActuallyPaid(id), 452 assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
453 - ORDER_EXTENSION_IS_PAID); 453 + PAY_ORDER_EXTENSION_IS_PAID);
454 } 454 }
455 455
456 @Test 456 @Test
@@ -469,7 +469,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -469,7 +469,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
469 469
470 // 调用,并断言异常 470 // 调用,并断言异常
471 assertServiceException(() -> orderService.validateOrderActuallyPaid(id), 471 assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
472 - ORDER_EXTENSION_IS_PAID); 472 + PAY_ORDER_EXTENSION_IS_PAID);
473 } 473 }
474 474
475 @Test 475 @Test
@@ -519,7 +519,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -519,7 +519,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
519 519
520 // 调用,并断言异常 520 // 调用,并断言异常
521 assertServiceException(() -> orderService.notifyOrder(channel, notify), 521 assertServiceException(() -> orderService.notifyOrder(channel, notify),
522 - ORDER_EXTENSION_NOT_FOUND); 522 + PAY_ORDER_EXTENSION_NOT_FOUND);
523 } 523 }
524 524
525 @Test 525 @Test
@@ -537,7 +537,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -537,7 +537,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
537 537
538 // 调用,并断言异常 538 // 调用,并断言异常
539 assertServiceException(() -> orderService.notifyOrder(channel, notify), 539 assertServiceException(() -> orderService.notifyOrder(channel, notify),
540 - ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 540 + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
541 } 541 }
542 542
543 @Test 543 @Test
@@ -555,7 +555,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -555,7 +555,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
555 555
556 // 调用,并断言异常 556 // 调用,并断言异常
557 assertServiceException(() -> orderService.notifyOrder(channel, notify), 557 assertServiceException(() -> orderService.notifyOrder(channel, notify),
558 - ORDER_NOT_FOUND); 558 + PAY_ORDER_NOT_FOUND);
559 // 断言 PayOrderExtensionDO :数据更新被回滚 559 // 断言 PayOrderExtensionDO :数据更新被回滚
560 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); 560 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
561 } 561 }
@@ -588,7 +588,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -588,7 +588,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
588 588
589 // 调用,并断言异常 589 // 调用,并断言异常
590 assertServiceException(() -> orderService.notifyOrder(channel, notify), 590 assertServiceException(() -> orderService.notifyOrder(channel, notify),
591 - ORDER_STATUS_IS_NOT_WAITING); 591 + PAY_ORDER_STATUS_IS_NOT_WAITING);
592 // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS 592 // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
593 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); 593 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
594 } 594 }
@@ -673,7 +673,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -673,7 +673,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
673 673
674 // 调用,并断言异常 674 // 调用,并断言异常
675 assertServiceException(() -> orderService.notifyOrder(channel, notify), 675 assertServiceException(() -> orderService.notifyOrder(channel, notify),
676 - ORDER_EXTENSION_NOT_FOUND); 676 + PAY_ORDER_EXTENSION_NOT_FOUND);
677 } 677 }
678 678
679 @Test 679 @Test
@@ -729,7 +729,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -729,7 +729,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
729 729
730 // 调用,并断言异常 730 // 调用,并断言异常
731 assertServiceException(() -> orderService.notifyOrder(channel, notify), 731 assertServiceException(() -> orderService.notifyOrder(channel, notify),
732 - ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 732 + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
733 } 733 }
734 734
735 @Test 735 @Test
@@ -762,7 +762,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -762,7 +762,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
762 762
763 // 调用,并断言异常 763 // 调用,并断言异常
764 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), 764 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
765 - ORDER_NOT_FOUND); 765 + PAY_ORDER_NOT_FOUND);
766 } 766 }
767 767
768 @Test 768 @Test
@@ -786,7 +786,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -786,7 +786,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
786 786
787 // 调用,并断言异常 787 // 调用,并断言异常
788 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), 788 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
789 - ORDER_REFUND_FAIL_STATUS_ERROR); 789 + PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
790 } 790 }
791 791
792 @Test 792 @Test
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 { @@ -219,7 +219,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
219 219
220 // 调用,并断言异常 220 // 调用,并断言异常
221 assertServiceException(() -> refundService.createPayRefund(reqDTO), 221 assertServiceException(() -> refundService.createPayRefund(reqDTO),
222 - ORDER_NOT_FOUND); 222 + PAY_ORDER_NOT_FOUND);
223 } 223 }
224 224
225 @Test 225 @Test
@@ -245,7 +245,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -245,7 +245,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
245 245
246 // 调用,并断言异常 246 // 调用,并断言异常
247 assertServiceException(() -> refundService.createPayRefund(reqDTO), 247 assertServiceException(() -> refundService.createPayRefund(reqDTO),
248 - ORDER_REFUND_FAIL_STATUS_ERROR); 248 + PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
249 } 249 }
250 250
251 @Test 251 @Test