Commit c880dbfa609c6244721db844168882322f5eba5b

Authored by jason
2 parents dbd7ab5f 35569c5e

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

Showing 112 changed files with 2008 additions and 967 deletions
sql/mysql/brokerage.sql
@@ -2,41 +2,50 @@ @@ -2,41 +2,50 @@
2 create table trade_config 2 create table trade_config
3 ( 3 (
4 id bigint auto_increment comment '自增主键' primary key, 4 id bigint auto_increment comment '自增主键' primary key,
5 - brokerage_enabled bit default 1 not null comment '是å¦å¯ç”¨åˆ†ä½£',  
6 - brokerage_enabled_condition tinyint default 0 not null comment '分佣模å¼ï¼š1-人人分销 2-指定分销',  
7 - brokerage_bind_mode tinyint default 0 not null comment '分销关系绑定模å¼: 1-没有推广人,2-新用户, 3-扫ç è¦†ç›–',  
8 - brokerage_post_urls varchar(2000) default '' null comment 'åˆ†é”€æµ·æŠ¥å›¾åœ°å€æ•°ç»„',  
9 - brokerage_first_percent int default 0 not null comment '一级返佣比例',  
10 - brokerage_second_percent int default 0 not null comment '二级返佣比例',  
11 - brokerage_withdraw_min_price int default 0 not null comment '用户æçŽ°æœ€ä½Žé‡‘é¢',  
12 - brokerage_bank_names varchar(200) default '' not null comment 'æçŽ°é“¶è¡Œï¼ˆå­—å…¸ç±»åž‹=brokerage_bank_name)',  
13 - brokerage_frozen_days int default 7 not null comment '佣金冻结时间(天)',  
14 - brokerage_withdraw_type varchar(32) default '1,2,3,4' not null comment 'æçŽ°æ–¹å¼ï¼š1-钱包;2-银行å¡ï¼›3-微信;4-支付å®',  
15 - creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',  
16 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
17 - updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',  
18 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',  
19 - deleted bit default b'0' not null comment '是å¦åˆ é™¤',  
20 - tenant_id bigint default 0 not null comment '租户编å·' 5 + brokerage_enabled bit default 1 not null comment '是å¦å¯ç”¨åˆ†ä½£',
  6 + brokerage_enabled_condition tinyint default 0 not null comment '分佣模å¼ï¼š1-人人分销 2-指定分销',
  7 + brokerage_bind_mode tinyint default 0 not null comment '分销关系绑定模å¼: 1-没有推广人,2-新用户, 3-扫ç è¦†ç›–',
  8 + brokerage_post_urls varchar(2000) default '' null comment 'åˆ†é”€æµ·æŠ¥å›¾åœ°å€æ•°ç»„',
  9 + brokerage_first_percent int default 0 not null comment '一级返佣比例',
  10 + brokerage_second_percent int default 0 not null comment '二级返佣比例',
  11 + brokerage_withdraw_min_price int default 0 not null comment '用户æçŽ°æœ€ä½Žé‡‘é¢',
  12 + brokerage_bank_names varchar(200) default '' not null comment 'æçŽ°é“¶è¡Œï¼ˆå­—å…¸ç±»åž‹=brokerage_bank_name)',
  13 + brokerage_frozen_days int default 7 not null comment '佣金冻结时间(天)',
  14 + brokerage_withdraw_type varchar(32) default '1,2,3,4' not null comment 'æçŽ°æ–¹å¼ï¼š1-钱包;2-银行å¡ï¼›3-微信;4-支付å®',
  15 + creator varchar(64) default '' null comment '创建者',
  16 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  17 + updater varchar(64) default '' null comment '更新者',
  18 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',
  19 + deleted bit default b'0' not null comment '是å¦åˆ é™¤',
  20 + tenant_id bigint default 0 not null comment '租户编å·'
21 ) comment '交易中心é…ç½®'; 21 ) comment '交易中心é…ç½®';
22 22
  23 +# alter table trade_brokerage_user
  24 +# add level int not null default 1 comment '等级' after frozen_price;
  25 +# alter table trade_brokerage_user
  26 +# add path varchar(2000) null comment '路径' after level;
  27 +
  28 +
23 -- 增加分销用户扩展表 29 -- 增加分销用户扩展表
24 create table trade_brokerage_user 30 create table trade_brokerage_user
25 ( 31 (
26 id bigint auto_increment comment '用户编å·' primary key, 32 id bigint auto_increment comment '用户编å·' primary key,
27 - bind_user_id bigint null comment '推广员编å·',  
28 - bind_user_time datetime null comment '推广员绑定时间',  
29 - brokerage_enabled bit default 1 not null comment 'æ˜¯å¦æˆä¸ºæŽ¨å¹¿å‘˜',  
30 - brokerage_time datetime null comment 'æˆä¸ºåˆ†é”€å‘˜æ—¶é—´',  
31 - price int default 0 not null comment 'å¯ç”¨ä½£é‡‘',  
32 - frozen_price int default 0 not null comment '冻结佣金',  
33 - creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',  
34 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
35 - updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',  
36 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',  
37 - deleted bit default b'0' not null comment '是å¦åˆ é™¤',  
38 - tenant_id bigint default 0 not null comment '租户编å·'  
39 -) comment '分销用户'; 33 + bind_user_id bigint null comment '推广员编å·',
  34 + bind_user_time datetime null comment '推广员绑定时间',
  35 + brokerage_enabled bit default 1 not null comment 'æ˜¯å¦æˆä¸ºæŽ¨å¹¿å‘˜',
  36 + brokerage_time datetime null comment 'æˆä¸ºåˆ†é”€å‘˜æ—¶é—´',
  37 + price int default 0 not null comment 'å¯ç”¨ä½£é‡‘',
  38 + frozen_price int default 0 not null comment '冻结佣金',
  39 + level int default 1 not null comment '等级',
  40 + path varchar(2000) null comment '路径',
  41 + creator varchar(64) default '' null comment '创建者',
  42 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  43 + updater varchar(64) default '' null comment '更新者',
  44 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',
  45 + deleted bit default b'0' not null comment '是å¦åˆ é™¤',
  46 + tenant_id bigint default 0 not null comment '租户编å·'
  47 +)
  48 + comment '分销用户';
40 49
41 create index idx_invite_user_id on trade_brokerage_user (bind_user_id) comment '推广员编å·'; 50 create index idx_invite_user_id on trade_brokerage_user (bind_user_id) comment '推广员编å·';
42 create index idx_agent on trade_brokerage_user (brokerage_enabled) comment 'æ˜¯å¦æˆä¸ºæŽ¨å¹¿å‘˜'; 51 create index idx_agent on trade_brokerage_user (brokerage_enabled) comment 'æ˜¯å¦æˆä¸ºæŽ¨å¹¿å‘˜';
@@ -44,26 +53,26 @@ create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是å @@ -44,26 +53,26 @@ create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是å
44 53
45 create table trade_brokerage_record 54 create table trade_brokerage_record
46 ( 55 (
47 - id int auto_increment comment 'ç¼–å·' 56 + id int auto_increment comment 'ç¼–å·'
48 primary key, 57 primary key,
49 - user_id bigint not null comment '用户编å·',  
50 - biz_id varchar(64) default '' not null comment '业务编å·',  
51 - biz_type tinyint default 0 not null comment '业务类型:1-订å•,2-æçް',  
52 - title varchar(64) default '' not null comment '标题',  
53 - price int default 0 not null comment '金é¢',  
54 - total_price int default 0 not null comment '当剿€»ä½£é‡‘',  
55 - description varchar(500) default '' not null comment '说明',  
56 - status tinyint default 0 not null comment '状æ€ï¼š0-待结算,1-已结算,2-已喿¶ˆ',  
57 - frozen_days int default 0 not null comment '冻结时间(天)',  
58 - unfreeze_time datetime null comment '解冻时间',  
59 - source_user_type tinyint not null comment 'æ¥æºç”¨æˆ·ç±»åž‹ï¼š1-一级推广用户,2-二级推广用户',  
60 - source_user_id bigint not null comment 'æ¥æºç”¨æˆ·ç¼–å·',  
61 - creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',  
62 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
63 - updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',  
64 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',  
65 - deleted bit default b'0' not null comment '是å¦åˆ é™¤',  
66 - tenant_id bigint default 0 not null comment '租户编å·' 58 + user_id bigint not null comment '用户编å·',
  59 + biz_id varchar(64) default '' not null comment '业务编å·',
  60 + biz_type tinyint default 0 not null comment '业务类型:1-订å•,2-æçް',
  61 + title varchar(64) default '' not null comment '标题',
  62 + price int default 0 not null comment '金é¢',
  63 + total_price int default 0 not null comment '当剿€»ä½£é‡‘',
  64 + description varchar(500) default '' not null comment '说明',
  65 + status tinyint default 0 not null comment '状æ€ï¼š0-待结算,1-已结算,2-已喿¶ˆ',
  66 + frozen_days int default 0 not null comment '冻结时间(天)',
  67 + unfreeze_time datetime null comment '解冻时间',
  68 + source_user_level int not null comment 'æ¥æºç”¨æˆ·ç­‰çº§',
  69 + source_user_id bigint not null comment 'æ¥æºç”¨æˆ·ç¼–å·',
  70 + creator varchar(64) default '' null comment '创建者',
  71 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  72 + updater varchar(64) default '' null comment '更新者',
  73 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',
  74 + deleted bit default b'0' not null comment '是å¦åˆ é™¤',
  75 + tenant_id bigint default 0 not null comment '租户编å·'
67 ) 76 )
68 comment '佣金记录'; 77 comment '佣金记录';
69 78
@@ -76,26 +85,26 @@ create table trade_brokerage_withdraw @@ -76,26 +85,26 @@ create table trade_brokerage_withdraw
76 ( 85 (
77 id int auto_increment comment 'ç¼–å·' 86 id int auto_increment comment 'ç¼–å·'
78 primary key, 87 primary key,
79 - user_id bigint not null comment '用户编å·',  
80 - price int default 0 not null comment 'æçް金é¢',  
81 - fee_price int default 0 not null comment 'æçŽ°æ‰‹ç»­è´¹',  
82 - total_price int default 0 not null comment '当剿€»ä½£é‡‘',  
83 - type tinyint default 0 not null comment 'æçŽ°ç±»åž‹ï¼š1-钱包;2-银行å¡ï¼›3-微信;4-支付å®',  
84 - name varchar(64) null comment '真实姓å',  
85 - account_no varchar(64) null comment 'è´¦å·',  
86 - bank_name varchar(100) null comment '银行åç§°',  
87 - bank_address varchar(200) null comment '开户地å€',  
88 - account_qr_code_url varchar(512) null comment '收款ç ',  
89 - status tinyint(2) default 0 not null comment '状æ€ï¼š0-审核中,10-审核通过 20-审核ä¸é€šè¿‡ï¼›é¢„留:11 - æçްæˆåŠŸï¼›21-æçŽ°å¤±è´¥',  
90 - audit_reason varchar(128) null comment '审核驳回原因',  
91 - audit_time datetime null comment '审核时间',  
92 - remark varchar(500) null comment '备注',  
93 - creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',  
94 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
95 - updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',  
96 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',  
97 - deleted bit default b'0' not null comment '是å¦åˆ é™¤',  
98 - tenant_id bigint default 0 not null comment '租户编å·' 88 + user_id bigint not null comment '用户编å·',
  89 + price int default 0 not null comment 'æçް金é¢',
  90 + fee_price int default 0 not null comment 'æçŽ°æ‰‹ç»­è´¹',
  91 + total_price int default 0 not null comment '当剿€»ä½£é‡‘',
  92 + type tinyint default 0 not null comment 'æçŽ°ç±»åž‹ï¼š1-钱包;2-银行å¡ï¼›3-微信;4-支付å®',
  93 + name varchar(64) null comment '真实姓å',
  94 + account_no varchar(64) null comment 'è´¦å·',
  95 + bank_name varchar(100) null comment '银行åç§°',
  96 + bank_address varchar(200) null comment '开户地å€',
  97 + account_qr_code_url varchar(512) null comment '收款ç ',
  98 + status tinyint(2) default 0 not null comment '状æ€ï¼š0-审核中,10-审核通过 20-审核ä¸é€šè¿‡ï¼›é¢„留:11 - æçްæˆåŠŸï¼›21-æçŽ°å¤±è´¥',
  99 + audit_reason varchar(128) null comment '审核驳回原因',
  100 + audit_time datetime null comment '审核时间',
  101 + remark varchar(500) null comment '备注',
  102 + creator varchar(64) default '' null comment '创建者',
  103 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  104 + updater varchar(64) default '' null comment '更新者',
  105 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'æ›´æ–°æ—¶é—´',
  106 + deleted bit default b'0' not null comment '是å¦åˆ é™¤',
  107 + tenant_id bigint default 0 not null comment '租户编å·'
99 ) 108 )
100 comment '佣金æçް'; 109 comment '佣金æçް';
101 110
@@ -139,12 +148,12 @@ values ('brokerage_record_status', '待结算', 0, 0), @@ -139,12 +148,12 @@ values ('brokerage_record_status', '待结算', 0, 0),
139 148
140 insert into system_dict_type(type, name) 149 insert into system_dict_type(type, name)
141 values ('brokerage_withdraw_status', '佣金æçŽ°çŠ¶æ€'); 150 values ('brokerage_withdraw_status', '佣金æçŽ°çŠ¶æ€');
142 -insert into system_dict_data(dict_type, label, value, sort)  
143 -values ('brokerage_withdraw_status', '审核中', 0, 0),  
144 - ('brokerage_withdraw_status', '审核通过', 10, 10),  
145 - ('brokerage_withdraw_status', 'æçްæˆåŠŸ', 11, 11),  
146 - ('brokerage_withdraw_status', '审核ä¸é€šè¿‡', 20, 20),  
147 - ('brokerage_withdraw_status', 'æçŽ°å¤±è´¥', 21, 21); 151 +insert into system_dict_data(dict_type, label, value, sort, color_type)
  152 +values ('brokerage_withdraw_status', '审核中', 0, 0, ''),
  153 + ('brokerage_withdraw_status', '审核通过', 10, 10, 'success'),
  154 + ('brokerage_withdraw_status', 'æçްæˆåŠŸ', 11, 11, 'success'),
  155 + ('brokerage_withdraw_status', '审核ä¸é€šè¿‡', 20, 20, 'danger'),
  156 + ('brokerage_withdraw_status', 'æçŽ°å¤±è´¥', 21, 21, 'danger');
148 157
149 insert into system_dict_type(type, name) 158 insert into system_dict_type(type, name)
150 values ('brokerage_bank_name', '佣金æçŽ°é“¶è¡Œ'); 159 values ('brokerage_bank_name', '佣金æçŽ°é“¶è¡Œ');
@@ -220,4 +229,10 @@ SELECT @parentId := LAST_INSERT_ID(); @@ -220,4 +229,10 @@ SELECT @parentId := LAST_INSERT_ID();
220 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) 229 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
221 VALUES ('佣金æçŽ°æŸ¥è¯¢', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0); 230 VALUES ('佣金æçŽ°æŸ¥è¯¢', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0);
222 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) 231 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
223 -VALUES ('佣金æçŽ°å®¡æ ¸', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);  
224 \ No newline at end of file 232 \ No newline at end of file
  233 +VALUES ('佣金æçŽ°å®¡æ ¸', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);
  234 +
  235 +-- 站内信模æ¿
  236 +INSERT INTO `ruoyi-vue-pro`.system_notify_template (name, code, nickname, content, type, params, status)
  237 +VALUES
  238 + ('佣金æçŽ°ï¼ˆå®¡æ ¸é€šè¿‡ï¼‰', 'brokerage_withdraw_audit_approve', 'system', '您在{createTime}æçŽ°ï¿¥{price}元的申请已通过审核', 2, '["createTime","price"]', 0),
  239 + ('佣金æçŽ°ï¼ˆå®¡æ ¸ä¸é€šè¿‡ï¼‰', 'brokerage_withdraw_audit_reject', 'system', '您在{createTime}æçŽ°ï¿¥{price}元的申请未通过审核,原因:{reason}', 2, '["createTime","price","reason"]', 0);
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
@@ -43,6 +43,17 @@ public class LocalDateTimeUtils { @@ -43,6 +43,17 @@ public class LocalDateTimeUtils {
43 return LocalDateTime.of(year, mouth, day, 0, 0, 0); 43 return LocalDateTime.of(year, mouth, day, 0, 0, 0);
44 } 44 }
45 45
  46 + /**
  47 + * 创建指定时间
  48 + *
  49 + * @param timeStr 时间字符串
  50 + * @return 指定时间
  51 + */
  52 + public static LocalDateTime buildTime(String timeStr) {
  53 + // TODO @puhui999:这个方法的实现,和 LocalDateTimeUtil.parse() 的差异点是啥呀
  54 + return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
  55 + }
  56 +
46 public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1, 57 public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
47 int year2, int mouth2, int day2) { 58 int year2, int mouth2, int day2) {
48 return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)}; 59 return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
@@ -63,6 +74,22 @@ public class LocalDateTimeUtils { @@ -63,6 +74,22 @@ public class LocalDateTimeUtils {
63 } 74 }
64 75
65 /** 76 /**
  77 + * 判断当前时间是否在该时间范围内
  78 + *
  79 + * @param startTime 开始时间
  80 + * @param endTime 结束时间
  81 + * @return 是否
  82 + */
  83 + public static boolean isBetween(String startTime, String endTime) {
  84 + if (startTime == null || endTime == null) {
  85 + return false;
  86 + }
  87 + LocalDate nowDate = LocalDate.now();
  88 + return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
  89 + LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
  90 + }
  91 +
  92 + /**
66 * 判断时间段是否重叠 93 * 判断时间段是否重叠
67 * 94 *
68 * @param startTime1 开始 time1 95 * @param startTime1 开始 time1
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
@@ -100,6 +100,14 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> { @@ -100,6 +100,14 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> {
100 return betweenIfPresent(column, val1, val2); 100 return betweenIfPresent(column, val1, val2);
101 } 101 }
102 102
  103 + // TODO @疯狂:这个是 mysql 独有的,不好做成通用的哈。如果多层级,有没可能先查询一个层级,再查询一个层级;形成 set 后,直接去 in?
  104 + public LambdaQueryWrapperX<T> findInSetIfPresent(SFunction<T, ?> column, Object val) {
  105 + if (val != null) {
  106 + return (LambdaQueryWrapperX<T>) super.apply("FIND_IN_SET({0}, " + columnToString(column) + ")", val);
  107 + }
  108 + return this;
  109 + }
  110 +
103 // ========== 重写父类方法,方便链式调用 ========== 111 // ========== 重写父类方法,方便链式调用 ==========
104 112
105 @Override 113 @Override
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
@@ -64,14 +64,14 @@ public class ${table.className}ServiceImpl implements ${table.className}Service @@ -64,14 +64,14 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
64 64
65 @Override 65 @Override
66 public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { 66 public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
67 - if (CollUtil.isEmpty(ids)) {  
68 - return ListUtil.empty();  
69 - }  
70 return ${classNameVar}Mapper.selectById(id); 67 return ${classNameVar}Mapper.selectById(id);
71 } 68 }
72 69
73 @Override 70 @Override
74 public List<${table.className}DO> get${simpleClassName}List(Collection<${primaryColumn.javaType}> ids) { 71 public List<${table.className}DO> get${simpleClassName}List(Collection<${primaryColumn.javaType}> ids) {
  72 + if (CollUtil.isEmpty(ids)) {
  73 + return ListUtil.empty();
  74 + }
75 return ${classNameVar}Mapper.selectBatchIds(ids); 75 return ${classNameVar}Mapper.selectBatchIds(ids);
76 } 76 }
77 77
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
@@ -39,7 +39,7 @@ public interface ProductSkuApi { @@ -39,7 +39,7 @@ public interface ProductSkuApi {
39 List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds); 39 List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
40 40
41 /** 41 /**
42 - * 更新 SKU 库存 42 + * 更新 SKU 库存(增加 or 减少)
43 * 43 *
44 * @param updateStockReqDTO 更新请求 44 * @param updateStockReqDTO 更新请求
45 */ 45 */
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
@@ -59,14 +59,13 @@ public class ProductSkuRespDTO { @@ -59,14 +59,13 @@ public class ProductSkuRespDTO {
59 * 商品体积,单位:m^3 平米 59 * 商品体积,单位:m^3 平米
60 */ 60 */
61 private Double volume; 61 private Double volume;
62 - // TODO @puhui999:firstBrokeragePrice ;尴尬,我当时打错了;secondBrokeragePrice  
63 /** 62 /**
64 * 一级分销的佣金,单位:分 63 * 一级分销的佣金,单位:分
65 */ 64 */
66 - private Integer firstBrokerageRecord; 65 + private Integer firstBrokeragePrice;
67 /** 66 /**
68 * 二级分销的佣金,单位:分 67 * 二级分销的佣金,单位:分
69 */ 68 */
70 - private Integer secondBrokerageRecord; 69 + private Integer secondBrokeragePrice;
71 70
72 } 71 }
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
1 package cn.iocoder.yudao.module.product.api.spu.dto; 1 package cn.iocoder.yudao.module.product.api.spu.dto;
2 2
3 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
4 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; 3 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
5 import lombok.Data; 4 import lombok.Data;
6 5
@@ -32,6 +31,12 @@ public class ProductSpuRespDTO { @@ -32,6 +31,12 @@ public class ProductSpuRespDTO {
32 */ 31 */
33 private String keyword; 32 private String keyword;
34 /** 33 /**
  34 + * 单位
  35 + *
  36 + * 对应 product_unit 数据字典
  37 + */
  38 + private Integer unit;
  39 + /**
35 * 商品简介 40 * 商品简介
36 */ 41 */
37 private String introduction; 42 private String introduction;
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 firstBrokerageRecord; 54 + private Integer firstBrokeragePrice;
55 55
56 @Schema(description = "二级分销的佣金,单位:分", example = "19") 56 @Schema(description = "二级分销的佣金,单位:分", example = "19")
57 - private Integer secondBrokerageRecord; 57 + private Integer secondBrokeragePrice;
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 firstBrokerageRecord; 84 + private Integer firstBrokeragePrice;
85 /** 85 /**
86 * 二级分销的佣金,单位:分 86 * 二级分销的佣金,单位:分
87 */ 87 */
88 - private Integer secondBrokerageRecord; 88 + private Integer secondBrokeragePrice;
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.setFirstBrokerageRecord(generaInt());  
96 - o.setSecondBrokerageRecord(generaInt()); 95 + o.setFirstBrokeragePrice(generaInt());
  96 + o.setSecondBrokeragePrice(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.setFirstBrokerageRecord(generaInt());  
147 - o.setSecondBrokerageRecord(generaInt()); 146 + o.setFirstBrokeragePrice(generaInt());
  147 + o.setSecondBrokeragePrice(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/combination/CombinationApi.java renamed to yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;  
4 -  
5 -// TODO @puhui999:是不是改成 CombinationActivityApi  
6 /** 3 /**
7 * 拼团活动 Api 接口 4 * 拼团活动 Api 接口
8 * 5 *
9 * @author HUIHUI 6 * @author HUIHUI
10 */ 7 */
11 -public interface CombinationApi { 8 +public interface CombinationActivityApi {
12 9
13 /** 10 /**
14 - * 更新活动库存 11 + * 校验是否满足拼团条件
15 * 12 *
16 - * @param reqDTO 请求 13 + * @param activityId 活动编号
  14 + * @param userId 用户编号
  15 + * @param skuId sku 编号
  16 + * @param count 数量
17 */ 17 */
18 - // TODO @puhui999:应该是更新哇?还是校验哈;  
19 - void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO); 18 + void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
20 19
21 } 20 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
4 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;  
5 4
6 import javax.validation.Valid; 5 import javax.validation.Valid;
7 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
8 -import java.util.List;  
9 7
10 // TODO @芋艿:后面也再撸撸这几个接口 8 // TODO @芋艿:后面也再撸撸这几个接口
11 9
@@ -33,26 +31,7 @@ public interface CombinationRecordApi { @@ -33,26 +31,7 @@ public interface CombinationRecordApi {
33 boolean isCombinationRecordSuccess(Long userId, Long orderId); 31 boolean isCombinationRecordSuccess(Long userId, Long orderId);
34 32
35 /** 33 /**
36 - * 获取拼团记录  
37 - *  
38 - * @param userId 用户编号  
39 - * @param activityId 活动编号  
40 - * @return 拼团记录列表  
41 - */  
42 - List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);  
43 -  
44 - /**  
45 - * 验证组合限制数  
46 - * 校验是否满足限购要求  
47 - *  
48 - * @param count 本次购买数量  
49 - * @param sumCount 已购买数量合计  
50 - * @param activityId 活动编号  
51 - */  
52 - void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);  
53 -  
54 - /**  
55 - * 更新拼团状态为成功 34 + * 更新拼团状态为【成功】
56 * 35 *
57 * @param userId 用户编号 36 * @param userId 用户编号
58 * @param orderId 订单编号 37 * @param orderId 订单编号
@@ -60,7 +39,7 @@ public interface CombinationRecordApi { @@ -60,7 +39,7 @@ public interface CombinationRecordApi {
60 void updateRecordStatusToSuccess(Long userId, Long orderId); 39 void updateRecordStatusToSuccess(Long userId, Long orderId);
61 40
62 /** 41 /**
63 - * 更新拼团状态为失败 42 + * 更新拼团状态为【失败】
64 * 43 *
65 * @param userId 用户编号 44 * @param userId 用户编号
66 * @param orderId 订单编号 45 * @param orderId 订单编号
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java deleted
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
@@ -13,26 +13,39 @@ import javax.validation.constraints.NotNull; @@ -13,26 +13,39 @@ import javax.validation.constraints.NotNull;
13 @Data 13 @Data
14 public class CombinationRecordCreateReqDTO { 14 public class CombinationRecordCreateReqDTO {
15 15
16 - // TODO @puhui999:注释还是要的哈  
17 - 16 + /**
  17 + * 拼团活动编号
  18 + */
18 @NotNull(message = "拼团活动编号不能为空") 19 @NotNull(message = "拼团活动编号不能为空")
19 private Long activityId; 20 private Long activityId;
20 - 21 + /**
  22 + * spu 编号
  23 + */
21 @NotNull(message = "spu 编号不能为空") 24 @NotNull(message = "spu 编号不能为空")
22 private Long spuId; 25 private Long spuId;
23 - 26 + /**
  27 + * sku 编号
  28 + */
24 @NotNull(message = "sku 编号不能为空") 29 @NotNull(message = "sku 编号不能为空")
25 private Long skuId; 30 private Long skuId;
26 - 31 + /**
  32 + * 订单编号
  33 + */
27 @NotNull(message = "订单编号不能为空") 34 @NotNull(message = "订单编号不能为空")
28 private Long orderId; 35 private Long orderId;
29 - 36 + /**
  37 + * 用户编号
  38 + */
30 @NotNull(message = "用户编号不能为空") 39 @NotNull(message = "用户编号不能为空")
31 private Long userId; 40 private Long userId;
32 - 41 + /**
  42 + * 团长编号
  43 + */
33 @NotNull(message = "团长编号不能为空") 44 @NotNull(message = "团长编号不能为空")
34 private Long headId; 45 private Long headId;
35 - 46 + /**
  47 + * 拼团商品单价
  48 + */
36 @NotNull(message = "拼团商品单价不能为空") 49 @NotNull(message = "拼团商品单价不能为空")
37 private Integer combinationPrice; 50 private Integer combinationPrice;
38 51
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.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.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;  
4 -  
5 /** 3 /**
6 * 秒杀活动 API 接口 4 * 秒杀活动 API 接口
7 * 5 *
@@ -9,11 +7,14 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateSt @@ -9,11 +7,14 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateSt
9 */ 7 */
10 public interface SeckillActivityApi { 8 public interface SeckillActivityApi {
11 9
  10 + // TODO @puhui999:activityId 改成 id 好点哈;
12 /** 11 /**
13 * 更新秒杀库存 12 * 更新秒杀库存
14 * 13 *
15 - * @param updateStockReqDTO 请求 14 + * @param activityId 活动编号
  15 + * @param skuId sku 编号
  16 + * @param count 数量
16 */ 17 */
17 - void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); 18 + void updateSeckillStock(Long activityId, Long skuId, Integer count);
18 19
19 } 20 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.seckill.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 SeckillActivityUpdateStockReqDTO {  
15 -  
16 - // TODO @puhui999:可以不用 dto,直接 activityId、skuId、count 即可  
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/enums/ErrorCodeConstants.java
@@ -56,6 +56,7 @@ public interface ErrorCodeConstants { @@ -56,6 +56,7 @@ public interface ErrorCodeConstants {
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 + ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
59 60
60 // ========== 秒杀时段 1013009000 ========== 61 // ========== 秒杀时段 1013009000 ==========
61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); 62 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
yudao-module-mall/yudao-module-promotion-biz/pom.xml
@@ -77,6 +77,10 @@ @@ -77,6 +77,10 @@
77 <groupId>cn.iocoder.boot</groupId> 77 <groupId>cn.iocoder.boot</groupId>
78 <artifactId>yudao-spring-boot-starter-excel</artifactId> 78 <artifactId>yudao-spring-boot-starter-excel</artifactId>
79 </dependency> 79 </dependency>
  80 + <dependency>
  81 + <groupId>cn.iocoder.boot</groupId>
  82 + <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
  83 + </dependency>
80 </dependencies> 84 </dependencies>
81 85
82 </project> 86 </project>
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;  
4 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; 3 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
5 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
6 -import org.springframework.validation.annotation.Validated;  
7 5
8 import javax.annotation.Resource; 6 import javax.annotation.Resource;
9 7
@@ -13,15 +11,14 @@ import javax.annotation.Resource; @@ -13,15 +11,14 @@ import javax.annotation.Resource;
13 * @author HUIHUI 11 * @author HUIHUI
14 */ 12 */
15 @Service 13 @Service
16 -@Validated  
17 -public class CombinationApiImpl implements CombinationApi { 14 +public class CombinationActivityApiImpl implements CombinationActivityApi {
18 15
19 @Resource 16 @Resource
20 private CombinationActivityService activityService; 17 private CombinationActivityService activityService;
21 18
22 @Override 19 @Override
23 - public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {  
24 - activityService.validateCombination(reqDTO); 20 + public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
  21 + activityService.validateCombination(activityId, userId, skuId, count);
25 } 22 }
26 23
27 } 24 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
4 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;  
5 -import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;  
6 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 4 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
7 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; 5 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
8 import org.springframework.stereotype.Service; 6 import org.springframework.stereotype.Service;
9 7
10 import javax.annotation.Resource; 8 import javax.annotation.Resource;
11 import java.time.LocalDateTime; 9 import java.time.LocalDateTime;
12 -import java.util.List;  
13 10
14 /** 11 /**
15 * 拼团活动 API 实现类 12 * 拼团活动 API 实现类
@@ -33,16 +30,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { @@ -33,16 +30,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
33 } 30 }
34 31
35 @Override 32 @Override
36 - public List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {  
37 - return CombinationActivityConvert.INSTANCE.convert(recordService.getRecordListByUserIdAndActivityId(userId, activityId));  
38 - }  
39 -  
40 - @Override  
41 - public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {  
42 - recordService.validateCombinationLimitCount(activityId, count, sumCount);  
43 - }  
44 -  
45 - @Override  
46 public void updateRecordStatusToSuccess(Long userId, Long orderId) { 33 public void updateRecordStatusToSuccess(Long userId, Long orderId) {
47 recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId); 34 recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);
48 } 35 }
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.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;  
4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; 3 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
5 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
6 5
@@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi { @@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
18 private SeckillActivityService activityService; 17 private SeckillActivityService activityService;
19 18
20 @Override 19 @Override
21 - public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {  
22 - activityService.updateSeckillStock(updateStockReqDTO); 20 + public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
  21 + activityService.updateSeckillStock(activityId, skuId, count);
23 } 22 }
24 23
25 } 24 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.controller.admin.bargain; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
@@ -19,8 +21,10 @@ import org.springframework.web.bind.annotation.*; @@ -19,8 +21,10 @@ import org.springframework.web.bind.annotation.*;
19 21
20 import javax.annotation.Resource; 22 import javax.annotation.Resource;
21 import javax.validation.Valid; 23 import javax.validation.Valid;
  24 +import java.util.List;
22 25
23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
24 28
25 @Tag(name = "管理后台 - 砍价活动") 29 @Tag(name = "管理后台 - 砍价活动")
26 @RestController 30 @RestController
@@ -30,6 +34,8 @@ public class BargainActivityController { @@ -30,6 +34,8 @@ public class BargainActivityController {
30 34
31 @Resource 35 @Resource
32 private BargainActivityService activityService; 36 private BargainActivityService activityService;
  37 + @Resource
  38 + private ProductSpuApi spuApi;
33 39
34 @PostMapping("/create") 40 @PostMapping("/create")
35 @Operation(summary = "创建砍价活动") 41 @Operation(summary = "创建砍价活动")
@@ -73,7 +79,10 @@ public class BargainActivityController { @@ -73,7 +79,10 @@ public class BargainActivityController {
73 if (CollUtil.isEmpty(pageResult.getList())) { 79 if (CollUtil.isEmpty(pageResult.getList())) {
74 return success(PageResult.empty(pageResult.getTotal())); 80 return success(PageResult.empty(pageResult.getTotal()));
75 } 81 }
76 - return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO))); 82 +
  83 + // 拼接数据
  84 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), BargainActivityDO::getSpuId));
  85 + return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, spuList));
77 } 86 }
78 87
79 } 88 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainActivityController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.bargain; 1 package cn.iocoder.yudao.module.promotion.controller.app.bargain;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
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.PageParam; 5 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 7 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  8 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
7 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO; 9 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
8 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
  11 +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
  13 +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
9 import io.swagger.v3.oas.annotations.Operation; 14 import io.swagger.v3.oas.annotations.Operation;
  15 +import io.swagger.v3.oas.annotations.Parameter;
10 import io.swagger.v3.oas.annotations.tags.Tag; 16 import io.swagger.v3.oas.annotations.tags.Tag;
11 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
12 import org.springframework.web.bind.annotation.GetMapping; 18 import org.springframework.web.bind.annotation.GetMapping;
@@ -14,97 +20,60 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -14,97 +20,60 @@ import org.springframework.web.bind.annotation.RequestMapping;
14 import org.springframework.web.bind.annotation.RequestParam; 20 import org.springframework.web.bind.annotation.RequestParam;
15 import org.springframework.web.bind.annotation.RestController; 21 import org.springframework.web.bind.annotation.RestController;
16 22
17 -import java.time.Duration;  
18 -import java.util.ArrayList; 23 +import javax.annotation.Resource;
19 import java.util.List; 24 import java.util.List;
20 25
21 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 28
23 @Tag(name = "用户 App - 砍价活动") 29 @Tag(name = "用户 App - 砍价活动")
24 @RestController 30 @RestController
25 @RequestMapping("/promotion/bargain-activity") 31 @RequestMapping("/promotion/bargain-activity")
26 @Validated 32 @Validated
27 public class AppBargainActivityController { 33 public class AppBargainActivityController {
  34 + @Resource
  35 + private BargainActivityService bargainActivityService;
  36 + @Resource
  37 + private ProductSpuApi spuApi;
28 38
29 @GetMapping("/page") 39 @GetMapping("/page")
30 - @Operation(summary = "获得砍价活动活动") // TODO 芋艿:只查询进行中,且在时间范围内的  
31 - // TODO 芋艿:缺少 swagger 注解 40 + @Operation(summary = "获得砍价活动分页")
32 public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) { 41 public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
33 - List<AppBargainActivityRespVO> activityList = new ArrayList<>();  
34 - AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();  
35 - activity1.setId(1L);  
36 - activity1.setName("618 大砍价");  
37 - activity1.setSpuId(2048L);  
38 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
39 - activity1.setMarketPrice(50);  
40 - activity1.setBargainPrice(100);  
41 - activity1.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));  
42 - activity1.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));  
43 - activity1.setStock(10);  
44 - activityList.add(activity1);  
45 -  
46 - AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();  
47 - activity2.setId(2L);  
48 - activity2.setName("双十一砍价");  
49 - activity2.setSpuId(4096L);  
50 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
51 - activity2.setMarketPrice(100);  
52 - activity2.setBargainPrice(200);  
53 - activity2.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));  
54 - activity2.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));  
55 - activity2.setStock(0);  
56 - activityList.add(activity2);  
57 -  
58 - return success(new PageResult<>(activityList, 10L)); 42 + PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPageForApp(pageReqVO);
  43 + if (CollUtil.isEmpty(result.getList())) {
  44 + return success(PageResult.empty(result.getTotal()));
  45 + }
  46 + // 拼接数据
  47 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(result.getList(), BargainActivityDO::getSpuId));
  48 + return success(BargainActivityConvert.INSTANCE.convertAppPage(result, spuList));
59 } 49 }
60 50
  51 + // TODO 芋艿:增加 Spring Cache
61 @GetMapping("/list") 52 @GetMapping("/list")
62 @Operation(summary = "获得砍价活动列表", description = "用于小程序首页") 53 @Operation(summary = "获得砍价活动列表", description = "用于小程序首页")
63 - // TODO 芋艿:增加 Spring Cache  
64 - // TODO 芋艿:缺少 swagger 注解 54 + @Parameter(name = "count", description = "需要展示的数量", example = "6")
65 public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList( 55 public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
66 @RequestParam(name = "count", defaultValue = "6") Integer count) { 56 @RequestParam(name = "count", defaultValue = "6") Integer count) {
67 - List<AppBargainActivityRespVO> activityList = new ArrayList<>();  
68 - AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();  
69 - activity1.setId(1L);  
70 - activity1.setName("618 大砍价");  
71 - activity1.setSpuId(2048L);  
72 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
73 - activity1.setMarketPrice(50);  
74 - activity1.setBargainPrice(100);  
75 - activityList.add(activity1);  
76 -  
77 - AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();  
78 - activity2.setId(2L);  
79 - activity2.setName("双十一砍价");  
80 - activity2.setSpuId(4096L);  
81 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
82 - activity2.setMarketPrice(100);  
83 - activity2.setBargainPrice(200);  
84 - activityList.add(activity2);  
85 -  
86 - return success(activityList); 57 + List<BargainActivityDO> list = bargainActivityService.getBargainActivityListForApp(count);
  58 + if (CollUtil.isEmpty(list)) {
  59 + return success(BargainActivityConvert.INSTANCE.convertAppList(list));
  60 + }
  61 + // 拼接数据
  62 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, BargainActivityDO::getSpuId));
  63 + return success(BargainActivityConvert.INSTANCE.convertAppList(list, spuList));
87 } 64 }
88 65
89 @GetMapping("/get-detail") 66 @GetMapping("/get-detail")
90 @Operation(summary = "获得砍价活动详情") 67 @Operation(summary = "获得砍价活动详情")
91 - // TODO 芋艿:缺少 swagger 注解 68 + @Parameter(name = "id", description = "活动编号", example = "1")
92 public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) { 69 public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) {
93 - AppBargainActivityDetailRespVO activity = new AppBargainActivityDetailRespVO();  
94 - activity.setId(2L);  
95 - activity.setName("618 大砍价");  
96 - activity.setSpuId(2048L);  
97 - activity.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
98 - activity.setMarketPrice(50);  
99 - activity.setBargainPrice(100);  
100 - activity.setStock(10);  
101 - activity.setUnitName("件");  
102 - activity.setPrice(40);  
103 - activity.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));  
104 - activity.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(-10)));  
105 - activity.setDescription("我吃西红柿");  
106 - activity.setSuccessCount(10);  
107 - return success(activity); 70 + BargainActivityDO activity = bargainActivityService.getBargainActivity(id);
  71 + if (activity == null) {
  72 + return success(null);
  73 + }
  74 + // 拼接数据
  75 + ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId());
  76 + return success(BargainActivityConvert.INSTANCE.convert(activity, spu));
108 } 77 }
109 78
110 } 79 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityDetailRespVO.java
@@ -45,7 +45,7 @@ public class AppBargainActivityDetailRespVO { @@ -45,7 +45,7 @@ public class AppBargainActivityDetailRespVO {
45 @Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换 45 @Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换
46 private String unitName; 46 private String unitName;
47 47
48 - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价 48 + @Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
49 private Integer bargainPrice; 49 private Integer bargainPrice;
50 50
51 @Schema(description = "砍价成功数量", required = true, example = "100") 51 @Schema(description = "砍价成功数量", required = true, example = "100")
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityRespVO.java
@@ -36,7 +36,7 @@ public class AppBargainActivityRespVO { @@ -36,7 +36,7 @@ public class AppBargainActivityRespVO {
36 @Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取 36 @Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取
37 private Integer marketPrice; 37 private Integer marketPrice;
38 38
39 - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价 39 + @Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
40 private Integer bargainPrice; 40 private Integer bargainPrice;
41 41
42 } 42 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.seckill; 1 package cn.iocoder.yudao.module.promotion.controller.app.seckill;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  8 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; 9 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
7 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; 11 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; 12 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
9 -import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; 13 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
  14 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  15 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  16 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
  17 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
  18 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
10 import io.swagger.v3.oas.annotations.Operation; 19 import io.swagger.v3.oas.annotations.Operation;
11 import io.swagger.v3.oas.annotations.Parameter; 20 import io.swagger.v3.oas.annotations.Parameter;
12 import io.swagger.v3.oas.annotations.tags.Tag; 21 import io.swagger.v3.oas.annotations.tags.Tag;
  22 +import org.springframework.context.annotation.Lazy;
13 import org.springframework.validation.annotation.Validated; 23 import org.springframework.validation.annotation.Validated;
14 import org.springframework.web.bind.annotation.GetMapping; 24 import org.springframework.web.bind.annotation.GetMapping;
15 import org.springframework.web.bind.annotation.RequestMapping; 25 import org.springframework.web.bind.annotation.RequestMapping;
16 import org.springframework.web.bind.annotation.RequestParam; 26 import org.springframework.web.bind.annotation.RequestParam;
17 import org.springframework.web.bind.annotation.RestController; 27 import org.springframework.web.bind.annotation.RestController;
18 28
19 -import java.time.LocalDateTime;  
20 -import java.util.ArrayList; 29 +import javax.annotation.Resource;
  30 +import java.util.Arrays;
21 import java.util.List; 31 import java.util.List;
22 32
  33 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  36 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
  37 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_FAIL_STATUS_CLOSED;
24 38
25 @Tag(name = "用户 App - 秒杀活动") 39 @Tag(name = "用户 App - 秒杀活动")
26 @RestController 40 @RestController
27 @RequestMapping("/promotion/seckill-activity") 41 @RequestMapping("/promotion/seckill-activity")
28 @Validated 42 @Validated
29 public class AppSeckillActivityController { 43 public class AppSeckillActivityController {
  44 + @Resource
  45 + private SeckillActivityService activityService;
  46 + @Resource
  47 + @Lazy
  48 + private SeckillConfigService configService;
  49 +
  50 + @Resource
  51 + private ProductSpuApi spuApi;
30 52
31 @GetMapping("/get-now") 53 @GetMapping("/get-now")
32 @Operation(summary = "获得当前秒杀活动") // 提供给首页使用 54 @Operation(summary = "获得当前秒杀活动") // 提供给首页使用
33 // TODO 芋艿:需要增加 spring cache 55 // TODO 芋艿:需要增加 spring cache
34 public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() { 56 public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
35 - AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();  
36 - respVO.setConfig(new AppSeckillConfigRespVO().setId(10L).setStartTime("01:00").setEndTime("09:59"));  
37 - List<AppSeckillActivityRespVO> activityList = new ArrayList<>();  
38 - AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();  
39 - activity1.setId(1L);  
40 - activity1.setName("618 大秒杀");  
41 - activity1.setSpuId(2048L);  
42 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
43 - activity1.setMarketPrice(50);  
44 - activity1.setSeckillPrice(100);  
45 - activityList.add(activity1); 57 + // 1. 获取当前时间处在哪个秒杀阶段
  58 + // TODO @puhui999:可以考虑在 service 写个方法;这样 controller 不用关注过多逻辑
  59 + List<SeckillConfigDO> configList = configService.getSeckillConfigList();
  60 + SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
  61 + CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
  62 + if (filteredConfig == null) { // 时段不存在直接返回 null
  63 + return success(null);
  64 + }
  65 +
  66 + // 2. 查询满足当前阶段的活动
  67 + // TODO @puhui999:最好直接返回开启的;不多查询数据
  68 + List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
  69 + List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
46 70
47 - AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();  
48 - activity2.setId(2L);  
49 - activity2.setName("双十一大秒杀");  
50 - activity2.setSpuId(4096L);  
51 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
52 - activity2.setMarketPrice(100);  
53 - activity2.setSeckillPrice(200);  
54 - activityList.add(activity2);  
55 - respVO.setActivities(activityList);  
56 - return success(respVO); 71 + // 3. 拼接数据
  72 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(filteredList, SeckillActivityDO::getSpuId));
  73 + return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
57 } 74 }
58 75
59 @GetMapping("/page") 76 @GetMapping("/page")
60 @Operation(summary = "获得秒杀活动分页") 77 @Operation(summary = "获得秒杀活动分页")
61 - // TODO @芋艿:分页参数  
62 public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) { 78 public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
63 - List<AppSeckillActivityRespVO> activityList = new ArrayList<>();  
64 - AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();  
65 - activity1.setId(1L);  
66 - activity1.setName("618 大秒杀");  
67 - activity1.setSpuId(2048L);  
68 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
69 - activity1.setMarketPrice(50);  
70 - activity1.setSeckillPrice(100);  
71 - activity1.setUnitName("个");  
72 - activity1.setStock(1);  
73 - activity1.setTotalStock(2);  
74 - activityList.add(activity1); 79 + // 1. 查询满足当前阶段的活动
  80 + PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
75 81
76 - AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();  
77 - activity2.setId(2L);  
78 - activity2.setName("双十一大秒杀");  
79 - activity2.setSpuId(4096L);  
80 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
81 - activity2.setMarketPrice(100);  
82 - activity2.setSeckillPrice(200);  
83 - activity2.setUnitName("套");  
84 - activity2.setStock(2);  
85 - activity2.setTotalStock(3);  
86 - activityList.add(activity2);  
87 - return success(new PageResult<>(activityList, 100L)); 82 + // 2. 拼接数据
  83 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
  84 + return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
88 } 85 }
89 86
90 @GetMapping("/get-detail") 87 @GetMapping("/get-detail")
91 @Operation(summary = "获得秒杀活动明细") 88 @Operation(summary = "获得秒杀活动明细")
92 @Parameter(name = "id", description = "活动编号", required = true, example = "1024") 89 @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
93 public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) { 90 public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
  91 + // 1、获取当前时间处在哪个秒杀阶段
  92 + // TODO puhui999:这里,和 58 行是雷同的
  93 + List<SeckillConfigDO> configList = configService.getSeckillConfigList();
  94 + SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
  95 + CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
  96 + if (filteredConfig == null) { // 时段不存在直接返回 null
  97 + return success(null);
  98 + }
  99 +
  100 + // 2. 获取活动
  101 + SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
  102 + if (seckillActivity == null) {
  103 + return success(null);
  104 + }
94 // TODO 芋艿:如果禁用的时候,需要抛出异常; 105 // TODO 芋艿:如果禁用的时候,需要抛出异常;
95 - AppSeckillActivityDetailRespVO obj = new AppSeckillActivityDetailRespVO();  
96 - // 设置其属性的值  
97 - obj.setId(id);  
98 - obj.setName("晚九点限时秒杀");  
99 - obj.setStatus(1);  
100 - obj.setStartTime(LocalDateTime.of(2023, 6, 16, 0, 0, 0));  
101 - obj.setEndTime(LocalDateTime.of(2023, 6, 20, 23, 59, 0));  
102 - obj.setSpuId(633L);  
103 - obj.setSingleLimitCount(2);  
104 - obj.setTotalLimitCount(3);  
105 - obj.setStock(100);  
106 - obj.setTotalStock(200); 106 + if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  107 + throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
  108 + }
107 109
108 - // 创建一个Product对象的列表  
109 - List<AppSeckillActivityDetailRespVO.Product> productList = new ArrayList<>();  
110 - // 创建三个新的Product对象并设置其属性的值  
111 - AppSeckillActivityDetailRespVO.Product product1 = new AppSeckillActivityDetailRespVO.Product();  
112 - product1.setSkuId(1L);  
113 - product1.setSeckillPrice(100);  
114 - product1.setStock(50);  
115 - // 将第一个Product对象添加到列表中  
116 - productList.add(product1);  
117 - // 创建第二个Product对象并设置其属性的值  
118 - AppSeckillActivityDetailRespVO.Product product2 = new AppSeckillActivityDetailRespVO.Product();  
119 - product2.setSkuId(2L);  
120 - product2.setSeckillPrice(200);  
121 - product2.setStock(100);  
122 - // 将第二个Product对象添加到列表中  
123 - productList.add(product2);  
124 - // 创建第三个Product对象并设置其属性的值  
125 - AppSeckillActivityDetailRespVO.Product product3 = new AppSeckillActivityDetailRespVO.Product();  
126 - product3.setSkuId(3L);  
127 - product3.setSeckillPrice(300);  
128 - product3.setStock(150);  
129 - // 将第三个Product对象添加到列表中  
130 - productList.add(product3);  
131 - // 将Product列表设置为对象的属性值  
132 - obj.setProducts(productList);  
133 - return success(obj); 110 + // 3. 拼接数据
  111 + List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
  112 + return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
134 } 113 }
135 114
136 } 115 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.seckill; 1 package cn.iocoder.yudao.module.promotion.controller.app.seckill;
2 2
  3 +import cn.hutool.core.collection.CollectionUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
  7 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
  9 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
5 import io.swagger.v3.oas.annotations.Operation; 10 import io.swagger.v3.oas.annotations.Operation;
6 import io.swagger.v3.oas.annotations.tags.Tag; 11 import io.swagger.v3.oas.annotations.tags.Tag;
7 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
@@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping; @@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping;
9 import org.springframework.web.bind.annotation.RequestMapping; 14 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RestController; 15 import org.springframework.web.bind.annotation.RestController;
11 16
12 -import java.util.Arrays; 17 +import javax.annotation.Resource;
  18 +import java.util.Collections;
13 import java.util.List; 19 import java.util.List;
14 20
15 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 21 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -19,18 +25,19 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -19,18 +25,19 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
19 @RequestMapping("/promotion/seckill-config") 25 @RequestMapping("/promotion/seckill-config")
20 @Validated 26 @Validated
21 public class AppSeckillConfigController { 27 public class AppSeckillConfigController {
  28 + @Resource
  29 + private SeckillConfigService configService;
22 30
23 @GetMapping("/list") 31 @GetMapping("/list")
24 @Operation(summary = "获得秒杀时间段列表") 32 @Operation(summary = "获得秒杀时间段列表")
25 public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() { 33 public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
26 - return success(Arrays.asList(  
27 - new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")  
28 - .setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",  
29 - "https://static.iocoder.cn/mall/132.jpeg")),  
30 - new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),  
31 - new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),  
32 - new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")  
33 - )); 34 + List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
  35 + // TODO @puhui999:如果这种,不用判空也问题不大;
  36 + if (CollectionUtil.isEmpty(list)) {
  37 + return success(Collections.emptyList());
  38 + }
  39 +
  40 + return success(SeckillConfigConvert.INSTANCE.convertList2(list));
34 } 41 }
35 42
36 } 43 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java
@@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO { @@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO {
19 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 19 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 private Integer status; 20 private Integer status;
21 21
22 - // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈; 22 + // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
23 23
24 @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) 24 @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
25 private LocalDateTime startTime; 25 private LocalDateTime startTime;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityRespVO.java
@@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO { @@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO {
31 private Integer totalStock; 31 private Integer totalStock;
32 32
33 @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") 33 @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
34 - // 从秒杀商品里取最低价  
35 private Integer seckillPrice; 34 private Integer seckillPrice;
36 35
37 } 36 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainActivityConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.bargain; 1 package cn.iocoder.yudao.module.promotion.convert.bargain;
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.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
  6 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  7 +import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
4 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
  11 +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
  12 +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
8 import org.mapstruct.Mapper; 14 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 15 import org.mapstruct.factory.Mappers;
10 16
11 import java.util.List; 17 import java.util.List;
  18 +import java.util.Map;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
12 22
13 /** 23 /**
14 * 拼团活动 Convert 24 * 拼团活动 Convert
@@ -30,4 +40,65 @@ public interface BargainActivityConvert { @@ -30,4 +40,65 @@ public interface BargainActivityConvert {
30 40
31 PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page); 41 PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page);
32 42
  43 + default PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
  44 + PageResult<BargainActivityRespVO> result = convertPage(page);
  45 + // 拼接关联属性
  46 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  47 + List<BargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
  48 + findAndThen(spuMap, item.getSpuId(), spu -> {
  49 + // TODO @puhui999:这里可以使用链式哈
  50 + item.setPicUrl(spu.getPicUrl());
  51 + item.setSpuName(spu.getName());
  52 + });
  53 + return item;
  54 + });
  55 + result.setList(list);
  56 + return result;
  57 + }
  58 +
  59 + AppBargainActivityDetailRespVO convert1(BargainActivityDO bean);
  60 +
  61 + default AppBargainActivityDetailRespVO convert(BargainActivityDO bean, ProductSpuRespDTO spu) {
  62 + AppBargainActivityDetailRespVO detail = convert1(bean);
  63 + if (spu != null) {
  64 + detail.setPicUrl(spu.getPicUrl());
  65 + detail.setMarketPrice(spu.getMarketPrice());
  66 + detail.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
  67 + }
  68 + return detail;
  69 + }
  70 +
  71 + PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page);
  72 +
  73 + default PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
  74 + PageResult<AppBargainActivityRespVO> result = convertAppPage(page);
  75 + // 拼接关联属性
  76 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  77 + List<AppBargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
  78 + findAndThen(spuMap, item.getSpuId(), spu -> {
  79 + // TODO @puhui999:这里可以使用链式哈
  80 + item.setPicUrl(spu.getPicUrl());
  81 + item.setMarketPrice(spu.getMarketPrice());
  82 + });
  83 + return item;
  84 + });
  85 + result.setList(list);
  86 + return result;
  87 + }
  88 +
  89 + List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list);
  90 +
  91 + default List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list, List<ProductSpuRespDTO> spuList) {
  92 + List<AppBargainActivityRespVO> activityList = convertAppList(list);
  93 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  94 + return CollectionUtils.convertList(activityList, item -> {
  95 + findAndThen(spuMap, item.getSpuId(), spu -> {
  96 + // TODO @puhui999:这里可以使用链式哈
  97 + item.setPicUrl(spu.getPicUrl());
  98 + item.setMarketPrice(spu.getMarketPrice());
  99 + });
  100 + return item;
  101 + });
  102 + }
  103 +
33 } 104 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.convert.combination; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.convert.combination;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  7 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
7 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 9 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
8 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; 10 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
@@ -92,6 +94,21 @@ public interface CombinationActivityConvert { @@ -92,6 +94,21 @@ public interface CombinationActivityConvert {
92 94
93 CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO); 95 CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
94 96
  97 + default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
  98 + CombinationActivityDO activity, MemberUserRespDTO user,
  99 + ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
  100 + // TODO @puhui999:搞成链式的 set;这样会更规整一点;
  101 + CombinationRecordDO record = convert(reqDTO);
  102 + record.setVirtualGroup(false);
  103 + record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
  104 + record.setUserSize(activity.getUserSize());
  105 + record.setNickname(user.getNickname());
  106 + record.setAvatar(user.getAvatar());
  107 + record.setSpuName(spu.getName());
  108 + record.setPicUrl(sku.getPicUrl());
  109 + return record;
  110 + }
  111 +
95 List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean); 112 List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
96 113
97 } 114 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
@@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; @@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 7 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  8 +import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
  15 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
  16 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
  17 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
  18 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
14 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 20 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  21 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
15 import org.mapstruct.Mapper; 22 import org.mapstruct.Mapper;
16 import org.mapstruct.Mapping; 23 import org.mapstruct.Mapping;
17 import org.mapstruct.Mappings; 24 import org.mapstruct.Mappings;
@@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers; @@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers;
20 import java.util.List; 27 import java.util.List;
21 import java.util.Map; 28 import java.util.Map;
22 29
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  32 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  33 +
23 /** 34 /**
24 * 秒杀活动 Convert 35 * 秒杀活动 Convert
25 * 36 *
@@ -79,4 +90,53 @@ public interface SeckillActivityConvert { @@ -79,4 +90,53 @@ public interface SeckillActivityConvert {
79 90
80 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list); 91 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list);
81 92
  93 + List<AppSeckillActivityRespVO> convertList3(List<SeckillActivityDO> activityList);
  94 +
  95 + default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList, List<ProductSpuRespDTO> spuList) {
  96 + AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
  97 + respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig));
  98 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  99 + respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
  100 + findAndThen(spuMap, item.getSpuId(), spu -> {
  101 + // TODO @puhui999:可以尝试链式 set 哈;
  102 + item.setPicUrl(spu.getPicUrl());
  103 + item.setMarketPrice(spu.getMarketPrice());
  104 + item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
  105 + });
  106 + return item;
  107 + }));
  108 + return respVO;
  109 + }
  110 +
  111 + PageResult<AppSeckillActivityRespVO> convertPage1(PageResult<SeckillActivityDO> pageResult);
  112 +
  113 + default PageResult<AppSeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> pageResult, List<ProductSpuRespDTO> spuList) {
  114 + PageResult<AppSeckillActivityRespVO> result = convertPage1(pageResult);
  115 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  116 + List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
  117 + findAndThen(spuMap, item.getSpuId(), spu -> {
  118 + // TODO @puhui999:可以尝试链式 set 哈;
  119 + item.setPicUrl(spu.getPicUrl());
  120 + item.setMarketPrice(spu.getMarketPrice());
  121 + item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
  122 + });
  123 + return item;
  124 + });
  125 + result.setList(list);
  126 + return result;
  127 + }
  128 +
  129 + AppSeckillActivityDetailRespVO convert2(SeckillActivityDO seckillActivity);
  130 +
  131 + List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
  132 +
  133 + default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
  134 + AppSeckillActivityDetailRespVO respVO = convert2(seckillActivity);
  135 + respVO.setProducts(convertList1(products));
  136 + // TODO @puhui999:可以尝试链式 set 哈;
  137 + respVO.setStartTime(buildTime(filteredConfig.getStartTime()));
  138 + respVO.setEndTime(buildTime(filteredConfig.getEndTime()));
  139 + return respVO;
  140 + }
  141 +
82 } 142 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillconfig/SeckillConfigConvert.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
9 import org.mapstruct.Mapper; 10 import org.mapstruct.Mapper;
10 import org.mapstruct.factory.Mappers; 11 import org.mapstruct.factory.Mappers;
@@ -33,4 +34,7 @@ public interface SeckillConfigConvert { @@ -33,4 +34,7 @@ public interface SeckillConfigConvert {
33 34
34 PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page); 35 PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page);
35 36
  37 + List<AppSeckillConfigRespVO> convertList2(List<SeckillConfigDO> list);
  38 +
  39 + AppSeckillConfigRespVO convert1(SeckillConfigDO filteredConfig);
36 } 40 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
@@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO { @@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO {
87 */ 87 */
88 private Integer singleLimitCount; 88 private Integer singleLimitCount;
89 /** 89 /**
90 - * 秒杀库存 90 + * 秒杀库存(剩余库存秒杀时扣减)
91 */ 91 */
92 private Integer stock; 92 private Integer stock;
93 /** 93 /**
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
1 package cn.iocoder.yudao.module.promotion.dal.mysql.bargain; 1 package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
@@ -8,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD @@ -8,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
8 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 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
  12 +import java.time.LocalDateTime;
11 import java.util.List; 13 import java.util.List;
12 14
13 /** 15 /**
@@ -39,8 +41,15 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; { @@ -39,8 +41,15 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; {
39 default int updateActivityStock(Long id, int count) { 41 default int updateActivityStock(Long id, int count) {
40 return update(null, new LambdaUpdateWrapper<BargainActivityDO>() 42 return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
41 .eq(BargainActivityDO::getId, id) 43 .eq(BargainActivityDO::getId, id)
42 - .gt(BargainActivityDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈 44 + .ge(BargainActivityDO::getStock, count)
43 .setSql("stock = stock - " + count)); 45 .setSql("stock = stock - " + count));
44 } 46 }
45 47
  48 + default PageResult<BargainActivityDO> selectAppPage(PageParam pageReqVO, Integer status, LocalDateTime now) {
  49 + return selectPage(pageReqVO, new LambdaQueryWrapperX<BargainActivityDO>()
  50 + .eq(BargainActivityDO::getStatus, status)
  51 + .le(BargainActivityDO::getStartTime, now)
  52 + .ge(BargainActivityDO::getEndTime, now));
  53 + }
  54 +
46 } 55 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 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.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 10 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
10 import org.apache.ibatis.annotations.Mapper; 11 import org.apache.ibatis.annotations.Mapper;
@@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
24 .likeIfPresent(SeckillActivityDO::getName, reqVO.getName()) 25 .likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
25 .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus()) 26 .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
26 .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime()) 27 .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
27 - .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0") 28 + .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0")
28 .orderByDesc(SeckillActivityDO::getId)); 29 .orderByDesc(SeckillActivityDO::getId));
29 } 30 }
30 31
@@ -48,4 +49,11 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -48,4 +49,11 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
48 .setSql("totalStock = totalStock - " + count)); 49 .setSql("totalStock = totalStock - " + count));
49 } 50 }
50 51
  52 + default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
  53 + return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
  54 + .eqIfPresent(SeckillActivityDO::getStatus, status)
  55 + // TODO 芋艿:对 find in set 的想法;
  56 + .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
  57 + }
  58 +
51 } 59 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
@@ -34,7 +34,7 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; { @@ -34,7 +34,7 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; {
34 default int updateActivityStock(Long id, int count) { 34 default int updateActivityStock(Long id, int count) {
35 return update(null, new LambdaUpdateWrapper<SeckillProductDO>() 35 return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
36 .eq(SeckillProductDO::getId, id) 36 .eq(SeckillProductDO::getId, id)
37 - .gt(SeckillProductDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈 37 + .gt(SeckillProductDO::getStock, count)
38 .setSql("stock = stock - " + count)); 38 .setSql("stock = stock - " + count));
39 } 39 }
40 40
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
1 package cn.iocoder.yudao.module.promotion.service.bargain; 1 package cn.iocoder.yudao.module.promotion.service.bargain;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
@@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActi @@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActi
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
8 9
9 import javax.validation.Valid; 10 import javax.validation.Valid;
  11 +import java.util.List;
10 12
11 /** 13 /**
12 * 砍价活动 Service 接口 14 * 砍价活动 Service 接口
@@ -61,4 +63,22 @@ public interface BargainActivityService { @@ -61,4 +63,22 @@ public interface BargainActivityService {
61 */ 63 */
62 PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO); 64 PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
63 65
  66 + // TODO @puhui999:这里可以改成进行中的活动;尽量避免专门为 app 定制,或者类似的名字哈;mapper 那也是
  67 +
  68 + /**
  69 + * 获取 APP 端活动分页数据
  70 + *
  71 + * @param pageReqVO 分页请求
  72 + * @return 砍价活动分页
  73 + */
  74 + PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO);
  75 +
  76 + /**
  77 + * 获取 APP 端活动展示数据
  78 + *
  79 + * @param count 需要的数量
  80 + * @return 砍价活动分页
  81 + */
  82 + List<BargainActivityDO> getBargainActivityListForApp(Integer count);
  83 +
64 } 84 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain;
2 2
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 7 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
@@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional; @@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
16 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
17 18
18 import javax.annotation.Resource; 19 import javax.annotation.Resource;
  20 +import java.time.LocalDateTime;
19 import java.util.List; 21 import java.util.List;
20 22
21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -113,9 +115,9 @@ public class BargainActivityServiceImpl implements BargainActivityService { @@ -113,9 +115,9 @@ public class BargainActivityServiceImpl implements BargainActivityService {
113 // 校验存在 115 // 校验存在
114 BargainActivityDO activityDO = validateBargainActivityExists(id); 116 BargainActivityDO activityDO = validateBargainActivityExists(id);
115 // 校验状态 117 // 校验状态
116 - if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {  
117 - throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);  
118 - } 118 + //if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  119 + // throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
  120 + //}
119 121
120 // 删除 122 // 删除
121 bargainActivityMapper.deleteById(id); 123 bargainActivityMapper.deleteById(id);
@@ -139,4 +141,22 @@ public class BargainActivityServiceImpl implements BargainActivityService { @@ -139,4 +141,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
139 return bargainActivityMapper.selectPage(pageReqVO); 141 return bargainActivityMapper.selectPage(pageReqVO);
140 } 142 }
141 143
  144 + @Override
  145 + public PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO) {
  146 + // 只查询进行中,且在时间范围内的
  147 + return bargainActivityMapper.selectAppPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
  148 + }
  149 +
  150 + @Override
  151 + public List<BargainActivityDO> getBargainActivityListForApp(Integer count) {
  152 + // TODO @puhui999:这种 default count 的逻辑,可以放到 controller 哈;然后可以使用 ObjectUtils.default 方法
  153 + if (count == null) {
  154 + count = 6;
  155 + }
  156 + // TODO @puhui999:这种不要用 page;会浪费一次 count;
  157 + PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count),
  158 + CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
  159 + return result.getList();
  160 + }
  161 +
142 } 162 }
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;  
5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 4 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -74,10 +73,14 @@ public interface CombinationActivityService { @@ -74,10 +73,14 @@ public interface CombinationActivityService {
74 List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds); 73 List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
75 74
76 /** 75 /**
77 - * 更新拼图活动库存 76 + * 校验是否满足拼团条件
  77 + * 如果不满足,会抛出异常
78 * 78 *
79 - * @param reqDTO 请求 79 + * @param activityId 活动编号
  80 + * @param userId 用户编号
  81 + * @param skuId sku 编号
  82 + * @param count 数量
80 */ 83 */
81 - void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO); 84 + void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
82 85
83 } 86 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; @@ -9,7 +9,6 @@ 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;  
13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
15 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -34,7 +33,6 @@ import java.util.Map; @@ -34,7 +33,6 @@ import java.util.Map;
34 33
35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
36 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
37 -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;  
38 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; 36 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
39 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; 37 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
40 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 38 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@@ -88,7 +86,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -88,7 +86,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
88 /** 86 /**
89 * 校验拼团商品参与的活动是否存在冲突 87 * 校验拼团商品参与的活动是否存在冲突
90 * 88 *
91 - * @param spuId 商品 SPU 编号 89 + * @param spuId 商品 SPU 编号
92 * @param activityId 拼团活动编号 90 * @param activityId 拼团活动编号
93 */ 91 */
94 private void validateProductConflict(Long spuId, Long activityId) { 92 private void validateProductConflict(Long spuId, Long activityId) {
@@ -107,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -107,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
107 /** 105 /**
108 * 校验拼团商品是否都存在 106 * 校验拼团商品是否都存在
109 * 107 *
110 - * @param spuId 商品 SPU 编号 108 + * @param spuId 商品 SPU 编号
111 * @param products 拼团商品 109 * @param products 拼团商品
112 */ 110 */
113 private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) { 111 private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
@@ -152,7 +150,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -152,7 +150,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
152 * 更新拼团商品 150 * 更新拼团商品
153 * 151 *
154 * @param activity 拼团活动 152 * @param activity 拼团活动
155 - * @param products 该活动的最新商品配置 153 + * @param products 该活动的最新商品配置
156 */ 154 */
157 private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) { 155 private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
158 // 第一步,对比新老数据,获得添加、修改、删除的列表 156 // 第一步,对比新老数据,获得添加、修改、删除的列表
@@ -217,34 +215,33 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -217,34 +215,33 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
217 } 215 }
218 216
219 @Override 217 @Override
220 - public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) { 218 + public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
221 // 1.1 校验拼团活动是否存在 219 // 1.1 校验拼团活动是否存在
222 - CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId()); 220 + CombinationActivityDO activity = validateCombinationActivityExists(activityId);
223 // 1.2 校验活动是否开启 221 // 1.2 校验活动是否开启
224 if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { 222 if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
225 throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); 223 throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
226 } 224 }
227 // 1.3 校验是否超出单次限购数量 225 // 1.3 校验是否超出单次限购数量
228 - if (activity.getSingleLimitCount() < reqDTO.getCount()) { 226 + // TODO puhui999:count > activity.getSingleLimitCount() 会更好理解点;
  227 + if (activity.getSingleLimitCount() < count) {
229 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); 228 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
230 } 229 }
231 230
232 // 2. 校验是否超出总限购数量 231 // 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 - } 232 + List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
  233 + if (CollUtil.isEmpty(recordList)) {
  234 + return;
  235 + }
  236 + // 过滤出拼团成功的
  237 + // TODO @puhui999:count 要不存一个在 record 里?
  238 + List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
  239 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
  240 + Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
  241 + CombinationRecordDO::getOrderId,
  242 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
  243 + if (activity.getTotalLimitCount() < countSum) {
  244 + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
248 } 245 }
249 } 246 }
250 247
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
@@ -57,14 +57,4 @@ public interface CombinationRecordService { @@ -57,14 +57,4 @@ public interface CombinationRecordService {
57 */ 57 */
58 List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId); 58 List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
59 59
60 - /**  
61 - * 验证组合限制数  
62 - * 校验是否满足限购要求  
63 - *  
64 - * @param count 本次购买数量  
65 - * @param sumCount 已购买数量合计  
66 - * @param activityId 活动编号  
67 - */  
68 - void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);  
69 -  
70 } 60 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -129,19 +129,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -129,19 +129,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
129 } 129 }
130 130
131 // 2. 创建拼团记录 131 // 2. 创建拼团记录
132 - // TODO @puhui999:可以把 user、spu、sku 一起放 convert 里哈;  
133 - CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);  
134 - record.setVirtualGroup(false);  
135 - record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));  
136 - record.setUserSize(activity.getUserSize());  
137 MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId()); 132 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());  
144 - recordMapper.insert(record); 133 + ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
  134 + ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
  135 + recordMapper.insert(CombinationActivityConvert.INSTANCE.convert(reqDTO, activity, user, spu, sku));
145 } 136 }
146 137
147 @Override 138 @Override
@@ -154,20 +145,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -154,20 +145,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
154 return recordMapper.selectListByUserIdAndActivityId(userId, activityId); 145 return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
155 } 146 }
156 147
157 - @Override  
158 - public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {  
159 - // 1.1 校验拼团活动  
160 - CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);  
161 - // 校验是否达到限购总限购标准  
162 - if ((sumCount + count) > activity.getTotalLimitCount()) {  
163 - throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);  
164 - }  
165 - // 单次购买是否达到限购标准  
166 - if (count > activity.getSingleLimitCount()) {  
167 - throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);  
168 - }  
169 - }  
170 -  
171 /** 148 /**
172 * APP 端获取开团记录 149 * APP 端获取开团记录
173 * 150 *
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;  
5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
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 cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
10 10
@@ -37,9 +37,11 @@ public interface SeckillActivityService { @@ -37,9 +37,11 @@ public interface SeckillActivityService {
37 /** 37 /**
38 * 更新秒杀库存 38 * 更新秒杀库存
39 * 39 *
40 - * @param updateStockReqDTO 更新信息 40 + * @param activityId 活动编号
  41 + * @param skuId sku 编号
  42 + * @param count 数量
41 */ 43 */
42 - void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); 44 + void updateSeckillStock(Long activityId, Long skuId, Integer count);
43 45
44 /** 46 /**
45 * 关闭秒杀活动 47 * 关闭秒杀活动
@@ -87,4 +89,20 @@ public interface SeckillActivityService { @@ -87,4 +89,20 @@ public interface SeckillActivityService {
87 */ 89 */
88 List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds); 90 List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
89 91
  92 + /**
  93 + * 通过活动时段获取秒杀活动
  94 + *
  95 + * @param ids 时段配置编号
  96 + * @return 秒杀活动列表
  97 + */
  98 + List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
  99 +
  100 + /**
  101 + * 通过活动时段获取秒杀活动
  102 + *
  103 + * @param pageReqVO 请求
  104 + * @return 秒杀活动列表
  105 + */
  106 + PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
  107 +
90 } 108 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
@@ -3,15 +3,16 @@ package cn.iocoder.yudao.module.promotion.service.seckill; @@ -3,15 +3,16 @@ package cn.iocoder.yudao.module.promotion.service.seckill;
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 7 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 9 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
9 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 10 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
10 -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;  
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.SeckillActivityCreateReqVO;
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.SeckillActivityPageReqVO;
13 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;
14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
  15 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
15 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; 16 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
16 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 17 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
17 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@@ -147,32 +148,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -147,32 +148,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
147 148
148 @Override 149 @Override
149 @Transactional(rollbackFor = Exception.class) 150 @Transactional(rollbackFor = Exception.class)
150 - public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { 151 + public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
151 // 1、校验秒杀活动是否存在 152 // 1、校验秒杀活动是否存在
152 - SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId()); 153 + SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
153 // 1.1、校验库存是否充足 154 // 1.1、校验库存是否充足
154 - if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) { 155 + if (seckillActivity.getTotalStock() < count) {
155 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); 156 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
156 } 157 }
157 158
158 // 2、获取活动商品 159 // 2、获取活动商品
159 - List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId()); 160 + List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
160 // 2.1、过滤出购买的商品 161 // 2.1、过滤出购买的商品
161 - SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId())); 162 + SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(skuId, item.getSkuId()));
162 // 2.2、检查活动商品库存是否充足 163 // 2.2、检查活动商品库存是否充足
163 - boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0); 164 + boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < count) || (product.getStock() - count) < 0);
164 if (isSufficient) { 165 if (isSufficient) {
165 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); 166 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
166 } 167 }
167 168
168 // 3、更新活动商品库存 169 // 3、更新活动商品库存
169 - int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount()); 170 + int updateCount = seckillProductMapper.updateActivityStock(product.getId(), count);
170 if (updateCount == 0) { 171 if (updateCount == 0) {
171 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); 172 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
172 } 173 }
173 174
174 // 4、更新活动库存 175 // 4、更新活动库存
175 - updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount()); 176 + updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), count);
176 if (updateCount == 0) { 177 if (updateCount == 0) {
177 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); 178 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
178 } 179 }
@@ -265,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -265,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
265 return seckillProductMapper.selectListByActivityId(activityIds); 266 return seckillProductMapper.selectListByActivityId(activityIds);
266 } 267 }
267 268
  269 + @Override
  270 + public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
  271 + return CollectionUtils.filterList(seckillActivityMapper.selectList(),
  272 + item -> CollectionUtils.anyMatch(item.getConfigIds(), ids::contains));
  273 + }
  274 +
  275 + @Override
  276 + public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
  277 + return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
  278 + }
  279 +
268 } 280 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java deleted
1 -package cn.iocoder.yudao.module.trade.api.brokerage;  
2 -  
3 -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;  
4 -import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;  
5 -  
6 -import javax.validation.constraints.NotNull;  
7 -import java.time.LocalDateTime;  
8 -  
9 -// TODO @疯狂:是不是不需要这个啦?  
10 -/**  
11 - * 分销 API 接口  
12 - *  
13 - * @author owen  
14 - */  
15 -public interface BrokerageApi {  
16 -  
17 - /**  
18 - * 获得分销用户  
19 - *  
20 - * @param userId 用户编号  
21 - * @return 分销用户信息  
22 - */  
23 - BrokerageUserDTO getBrokerageUser(Long userId);  
24 -  
25 - /**  
26 - * 【会员】绑定推广员  
27 - *  
28 - * @param userId 用户编号  
29 - * @param bindUserId 推广员编号  
30 - * @param registerTime 用户注册时间  
31 - * @return 是否绑定  
32 - */  
33 - default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {  
34 - // 注册时间在30秒内的,都算新用户  
35 - // TODO @疯狂:这个要不抽到 service 里哈?  
36 - boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));  
37 - return bindUser(userId, bindUserId, isNewUser);  
38 - }  
39 -  
40 - /**  
41 - * 绑定推广员  
42 - *  
43 - * @param userId 用户编号  
44 - * @param bindUserId 推广员编号  
45 - * @param isNewUser 是否为新用户  
46 - * @return 是否绑定  
47 - */  
48 - boolean bindUser(@NotNull(message = "用户编号不能为空") Long userId,  
49 - @NotNull(message = "推广员编号不能为空") Long bindUserId,  
50 - @NotNull Boolean isNewUser);  
51 -  
52 -}  
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/dto/BrokerageUserDTO.java deleted
1 -package cn.iocoder.yudao.module.trade.api.brokerage.dto;  
2 -  
3 -import lombok.Data;  
4 -  
5 -import java.time.LocalDateTime;  
6 -  
7 -/**  
8 - * 分销用户 DTO  
9 - *  
10 - * @author owen  
11 - */  
12 -@Data  
13 -public class BrokerageUserDTO {  
14 -  
15 - /**  
16 - * 用户编号  
17 - * <p>  
18 - * 对应 MemberUserDO 的 id 字段  
19 - */  
20 - private Long id;  
21 -  
22 - /**  
23 - * 推广员编号  
24 - * <p>  
25 - * 关联 MemberUserDO 的 id 字段  
26 - */  
27 - private Long bindUserId;  
28 - /**  
29 - * 推广员绑定时间  
30 - */  
31 - private LocalDateTime bindUserTime;  
32 -  
33 - /**  
34 - * 推广资格  
35 - */  
36 - private Boolean brokerageEnabled;  
37 - /**  
38 - * 成为分销员时间  
39 - */  
40 - private LocalDateTime brokerageTime;  
41 -  
42 - /**  
43 - * 可用佣金  
44 - */  
45 - private Integer price;  
46 - /**  
47 - * 冻结佣金  
48 - */  
49 - private Integer frozenPrice;  
50 -  
51 -}  
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
@@ -58,8 +58,9 @@ public interface ErrorCodeConstants { @@ -58,8 +58,9 @@ public interface ErrorCodeConstants {
58 58
59 // ========== Price 相关 1011003000 ============ 59 // ========== Price 相关 1011003000 ============
60 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0"); 60 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0");
61 - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空"); 61 + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空");
62 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板"); 62 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板");
  63 + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_PICK_UP_STORE_IS_EMPTY = new ErrorCode(1011003003, "计算快递运费异常,自提点为空");
63 64
64 // ========== 物流 Express 模块 1011004000 ========== 65 // ========== 物流 Express 模块 1011004000 ==========
65 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在"); 66 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在");
@@ -88,4 +89,9 @@ public interface ErrorCodeConstants { @@ -88,4 +89,9 @@ public interface ErrorCodeConstants {
88 ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人"); 89 ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人");
89 ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级"); 90 ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级");
90 91
  92 +
  93 + // ========== 分销提现 模块 1011008000 ==========
  94 + ErrorCode BROKERAGE_WITHDRAW_NOT_EXISTS = new ErrorCode(1011008000, "佣金提现记录不存在");
  95 + ErrorCode BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING = new ErrorCode(1011008001, "佣金提现记录状态不是审核中");
  96 +
91 } 97 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java
@@ -10,4 +10,7 @@ public interface MessageTemplateConstants { @@ -10,4 +10,7 @@ public interface MessageTemplateConstants {
10 10
11 String ORDER_DELIVERY = "order_delivery"; // 短信模版编号 11 String ORDER_DELIVERY = "order_delivery"; // 短信模版编号
12 12
  13 + String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过)
  14 + String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过)
  15 +
13 } 16 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java deleted
1 -package cn.iocoder.yudao.module.trade.enums.brokerage;  
2 -  
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Getter;  
6 -  
7 -import java.util.Arrays;  
8 -  
9 -// TODO @疯狂:是不是搞成层级,类似 level 这样?因为本质上,它是 1 级、2 级、3 级这样的关系哈  
10 -/**  
11 - * 分销用户类型枚举  
12 - *  
13 - * @author owen  
14 - */  
15 -@AllArgsConstructor  
16 -@Getter  
17 -public enum BrokerageUserTypeEnum implements IntArrayValuable {  
18 -  
19 - ALL(0, "全部"),  
20 - FIRST(1, "一级推广人"),  
21 - SECOND(2, "二级推广人"),  
22 - ;  
23 -  
24 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageUserTypeEnum::getType).toArray();  
25 -  
26 - /**  
27 - * 类型  
28 - */  
29 - private final Integer type;  
30 - /**  
31 - * 名字  
32 - */  
33 - private final String name;  
34 -  
35 - @Override  
36 - public int[] array() {  
37 - return ARRAYS;  
38 - }  
39 -  
40 -}  
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryTypeEnum.java
@@ -15,16 +15,15 @@ import java.util.Arrays; @@ -15,16 +15,15 @@ import java.util.Arrays;
15 @AllArgsConstructor 15 @AllArgsConstructor
16 public enum DeliveryTypeEnum implements IntArrayValuable { 16 public enum DeliveryTypeEnum implements IntArrayValuable {
17 17
18 - NULL(0, "无需物流"),  
19 EXPRESS(1, "快递发货"), 18 EXPRESS(1, "快递发货"),
20 PICK_UP(2, "用户自提"),; 19 PICK_UP(2, "用户自提"),;
21 20
22 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryTypeEnum::getMode).toArray(); 21 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryTypeEnum::getType).toArray();
23 22
24 /** 23 /**
25 * 配送方式 24 * 配送方式
26 */ 25 */
27 - private final Integer mode; 26 + private final Integer type;
28 /** 27 /**
29 * 状态名 28 * 状态名
30 */ 29 */
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java deleted
1 -package cn.iocoder.yudao.module.trade.api.brokerage;  
2 -  
3 -import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;  
4 -import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert;  
5 -import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;  
6 -import org.springframework.stereotype.Service;  
7 -import org.springframework.validation.annotation.Validated;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 分销 API 接口实现类  
13 - *  
14 - * @author owen  
15 - */  
16 -@Service  
17 -@Validated  
18 -public class BrokerageApiImpl implements BrokerageApi {  
19 -  
20 - @Resource  
21 - private BrokerageUserService brokerageUserService;  
22 -  
23 - @Override  
24 - public BrokerageUserDTO getBrokerageUser(Long userId) {  
25 - return BrokerageUserConvert.INSTANCE.convertDTO(brokerageUserService.getBrokerageUser(userId));  
26 - }  
27 -  
28 - @Override  
29 - public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {  
30 - return brokerageUserService.bindBrokerageUser(userId, bindUserId, isNewUser);  
31 - }  
32 -  
33 -}  
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java
@@ -57,8 +57,8 @@ public class BrokerageRecordBaseVO { @@ -57,8 +57,8 @@ public class BrokerageRecordBaseVO {
57 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 57 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
58 private LocalDateTime unfreezeTime; 58 private LocalDateTime unfreezeTime;
59 59
60 - @Schema(description = "来源用户类型")  
61 - private Integer sourceUserType; 60 + @Schema(description = "来源用户等级")
  61 + private Integer sourceUserLevel;
62 62
63 @Schema(description = "来源用户编号") 63 @Schema(description = "来源用户编号")
64 private Long sourceUserId; 64 private Long sourceUserId;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java
1 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo; 1 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 -import cn.iocoder.yudao.framework.common.validation.InEnum;  
5 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
6 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
7 import lombok.Data; 5 import lombok.Data;
8 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
@@ -32,8 +30,7 @@ public class BrokerageRecordPageReqVO extends PageParam { @@ -32,8 +30,7 @@ public class BrokerageRecordPageReqVO extends PageParam {
32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 30 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
33 private LocalDateTime[] createTime; 31 private LocalDateTime[] createTime;
34 32
35 - @Schema(description = "用户类型")  
36 - @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")  
37 - private Integer sourceUserType; 33 + @Schema(description = "用户类型", example = "1")
  34 + private Integer sourceUserLevel;
38 35
39 } 36 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java
@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert
9 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
10 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 10 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
11 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; 11 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
12 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
13 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; 12 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
14 import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; 13 import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
15 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; 14 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@@ -96,7 +95,7 @@ public class BrokerageUserController { @@ -96,7 +95,7 @@ public class BrokerageUserController {
96 // 合计推广用户数量 95 // 合计推广用户数量
97 Map<Long, Long> brokerageUserCountMap = convertMap(userIds, 96 Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
98 userId -> userId, 97 userId -> userId,
99 - userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, BrokerageUserTypeEnum.ALL)); 98 + userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null));
100 99
101 // todo 合计提现 100 // todo 合计提现
102 101
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java
1 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo; 1 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 -import cn.iocoder.yudao.framework.common.validation.InEnum;  
5 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
6 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
7 import lombok.Data; 5 import lombok.Data;
8 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
@@ -22,18 +20,18 @@ public class BrokerageUserPageReqVO extends PageParam { @@ -22,18 +20,18 @@ public class BrokerageUserPageReqVO extends PageParam {
22 @Schema(description = "推广员编号", example = "4587") 20 @Schema(description = "推广员编号", example = "4587")
23 private Long bindUserId; 21 private Long bindUserId;
24 22
25 - @Schema(description = "推广资格") 23 + @Schema(description = "推广资格", example = "true")
26 private Boolean brokerageEnabled; 24 private Boolean brokerageEnabled;
27 25
28 @Schema(description = "创建时间") 26 @Schema(description = "创建时间")
29 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 27 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
30 private LocalDateTime[] createTime; 28 private LocalDateTime[] createTime;
31 29
32 - @Schema(description = "用户类型")  
33 - @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")  
34 - private Integer userType; 30 + @Schema(description = "用户等级", example = "1") // 注意,这了不是用户的会员等级,而是过滤推广的层级
  31 + private Integer level;
35 32
36 @Schema(description = "绑定时间") 33 @Schema(description = "绑定时间")
37 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 34 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
38 private LocalDateTime[] bindUserTime; 35 private LocalDateTime[] bindUserTime;
  36 +
39 } 37 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/withdraw/BrokerageWithdrawController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  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.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRejectReqVO;
  8 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
  9 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
  10 +import cn.iocoder.yudao.module.trade.convert.brokerage.withdraw.BrokerageWithdrawConvert;
  11 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  12 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
  13 +import cn.iocoder.yudao.module.trade.service.brokerage.withdraw.BrokerageWithdrawService;
  14 +import io.swagger.v3.oas.annotations.Operation;
  15 +import io.swagger.v3.oas.annotations.Parameter;
  16 +import io.swagger.v3.oas.annotations.tags.Tag;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import javax.annotation.Resource;
  22 +import javax.validation.Valid;
  23 +import java.util.Map;
  24 +
  25 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  27 +
  28 +@Tag(name = "管理后台 - 佣金提现")
  29 +@RestController
  30 +@RequestMapping("/trade/brokerage-withdraw")
  31 +@Validated
  32 +public class BrokerageWithdrawController {
  33 +
  34 + @Resource
  35 + private BrokerageWithdrawService brokerageWithdrawService;
  36 +
  37 + @Resource
  38 + private MemberUserApi memberUserApi;
  39 +
  40 + @PutMapping("/approve")
  41 + @Operation(summary = "通过申请")
  42 + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
  43 + public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) {
  44 + brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "");
  45 + return success(true);
  46 + }
  47 +
  48 + @PutMapping("/reject")
  49 + @Operation(summary = "驳回申请")
  50 + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
  51 + public CommonResult<Boolean> rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawRejectReqVO reqVO) {
  52 + brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason());
  53 + return success(true);
  54 + }
  55 +
  56 + @GetMapping("/get")
  57 + @Operation(summary = "获得佣金提现")
  58 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  59 + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
  60 + public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) {
  61 + BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
  62 + return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
  63 + }
  64 +
  65 + @GetMapping("/page")
  66 + @Operation(summary = "获得佣金提现分页")
  67 + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
  68 + public CommonResult<PageResult<BrokerageWithdrawRespVO>> getBrokerageWithdrawPage(@Valid BrokerageWithdrawPageReqVO pageVO) {
  69 + // 分页查询
  70 + PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(pageVO);
  71 +
  72 + // 拼接信息
  73 + Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(
  74 + convertSet(pageResult.getList(), BrokerageWithdrawDO::getUserId));
  75 + return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap));
  76 + }
  77 +
  78 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/withdraw/vo/BrokerageWithdrawBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +/**
  13 + * 佣金提现 Base VO,提供给添加、修改、详细的子 VO 使用
  14 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  15 + */
  16 +@Data
  17 +public class BrokerageWithdrawBaseVO {
  18 +
  19 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11436")
  20 + @NotNull(message = "用户编号不能为空")
  21 + private Long userId;
  22 +
  23 + @Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18781")
  24 + @NotNull(message = "提现金额不能为空")
  25 + private Integer price;
  26 +
  27 + @Schema(description = "提现手续费", requiredMode = Schema.RequiredMode.REQUIRED, example = "11417")
  28 + @NotNull(message = "提现手续费不能为空")
  29 + private Integer feePrice;
  30 +
  31 + @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "18576")
  32 + @NotNull(message = "当前总佣金不能为空")
  33 + private Integer totalPrice;
  34 +
  35 + @Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  36 + @NotNull(message = "提现类型不能为空")
  37 + private Integer type;
  38 +
  39 + @Schema(description = "真实姓名", example = "赵六")
  40 + private String name;
  41 +
  42 + @Schema(description = "账号", example = "88677912132")
  43 + private String accountNo;
  44 +
  45 + @Schema(description = "银行名称", example = "1")
  46 + private String bankName;
  47 +
  48 + @Schema(description = "开户地址", example = "海淀支行")
  49 + private String bankAddress;
  50 +
  51 + @Schema(description = "收款码", example = "https://www.iocoder.cn")
  52 + private String accountQrCodeUrl;
  53 +
  54 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  55 + @NotNull(message = "状态不能为空")
  56 + private Integer status;
  57 +
  58 + @Schema(description = "审核驳回原因", example = "不对")
  59 + private String auditReason;
  60 +
  61 + @Schema(description = "审核时间")
  62 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  63 + private LocalDateTime auditTime;
  64 +
  65 + @Schema(description = "备注", example = "随便")
  66 + private String remark;
  67 +
  68 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/withdraw/vo/BrokerageWithdrawPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
  6 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +import org.springframework.format.annotation.DateTimeFormat;
  12 +
  13 +import java.time.LocalDateTime;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  16 +
  17 +@Schema(description = "管理后台 - 佣金提现分页 Request VO")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +public class BrokerageWithdrawPageReqVO extends PageParam {
  22 +
  23 + @Schema(description = "用户编号", example = "11436")
  24 + private Long userId;
  25 +
  26 + @Schema(description = "提现类型", example = "1")
  27 + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现类型必须是 {value}")
  28 + private Integer type;
  29 +
  30 + @Schema(description = "真实姓名", example = "赵六")
  31 + private String name;
  32 +
  33 + @Schema(description = "账号", example = "886779132")
  34 + private String accountNo;
  35 +
  36 + @Schema(description = "银行名称", example = "1")
  37 + private String bankName;
  38 +
  39 + @Schema(description = "状态", example = "1")
  40 + @InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}")
  41 + private Integer status;
  42 +
  43 + @Schema(description = "创建时间")
  44 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  45 + private LocalDateTime[] createTime;
  46 +
  47 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/withdraw/vo/BrokerageWithdrawRejectReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@Schema(description = "管理后台 - 驳回申请 Request VO")
  11 +@Data
  12 +@ToString(callSuper = true)
  13 +public class BrokerageWithdrawRejectReqVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
  16 + @NotNull(message = "编号不能为空")
  17 + private Integer id;
  18 +
  19 + @Schema(description = "审核驳回原因", example = "不对")
  20 + @NotEmpty(message = "审核驳回原因不能为空")
  21 + private String auditReason;
  22 +
  23 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/withdraw/vo/BrokerageWithdrawRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 佣金提现 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
  17 + private Integer id;
  18 +
  19 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + private LocalDateTime createTime;
  21 +
  22 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  23 + private String userNickname;
  24 +
  25 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http
@@ -8,14 +8,15 @@ GET {{appApi}}/trade/order/settlement?type=0&amp;items[0].cartId=50&amp;couponId=1 @@ -8,14 +8,15 @@ GET {{appApi}}/trade/order/settlement?type=0&amp;items[0].cartId=50&amp;couponId=1
8 Authorization: Bearer {{appToken}} 8 Authorization: Bearer {{appToken}}
9 tenant-id: {{appTenentId}} 9 tenant-id: {{appTenentId}}
10 10
11 -### /trade-order/create 创建订单(基于商品) 11 +### /trade-order/create 创建订单(基于商品)【快递】
12 POST {{appApi}}/trade/order/create 12 POST {{appApi}}/trade/order/create
13 Content-Type: application/json 13 Content-Type: application/json
14 Authorization: Bearer {{appToken}} 14 Authorization: Bearer {{appToken}}
15 tenant-id: {{appTenentId}} 15 tenant-id: {{appTenentId}}
16 16
17 { 17 {
18 - "type": 0, 18 + "pointStatus": true,
  19 + "deliveryType": 1,
19 "addressId": 21, 20 "addressId": 21,
20 "items": [ 21 "items": [
21 { 22 {
@@ -26,6 +27,27 @@ tenant-id: {{appTenentId}} @@ -26,6 +27,27 @@ tenant-id: {{appTenentId}}
26 "remark": "我是备注" 27 "remark": "我是备注"
27 } 28 }
28 29
  30 +### /trade-order/create 创建订单(基于商品)【自提】
  31 +POST {{appApi}}/trade/order/create
  32 +Content-Type: application/json
  33 +Authorization: Bearer {{appToken}}
  34 +tenant-id: {{appTenentId}}
  35 +
  36 +{
  37 + "pointStatus": true,
  38 + "deliveryType": 2,
  39 + "pickUpStoreId": 1,
  40 + "items": [
  41 + {
  42 + "skuId": 1,
  43 + "count": 2
  44 + }
  45 + ],
  46 + "remark": "我是备注",
  47 + "receiverName": "土豆",
  48 + "receiverMobile": "15601691300"
  49 +}
  50 +
29 ### 获得订单交易的分页 51 ### 获得订单交易的分页
30 GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10 52 GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10
31 Authorization: Bearer {{appToken}} 53 Authorization: Bearer {{appToken}}
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;  
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
@@ -12,11 +11,8 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; @@ -12,11 +11,8 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
12 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; 11 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 12 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
14 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
15 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;  
16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 14 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
17 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 15 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;  
20 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; 16 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
21 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; 17 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
22 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; 18 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
@@ -65,10 +61,7 @@ public class AppTradeOrderController { @@ -65,10 +61,7 @@ public class AppTradeOrderController {
65 @PostMapping("/create") 61 @PostMapping("/create")
66 @Operation(summary = "创建订单") 62 @Operation(summary = "创建订单")
67 @PreAuthenticated 63 @PreAuthenticated
68 - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST)  
69 - public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {  
70 - TradeOrderLogUtils.setOrderInfo(10L, 1, 2,  
71 - MapUtil.<String, Object>builder().put("nickname", "小明").put("thing", "种土豆").build()); 64 + public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
72 TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO); 65 TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
73 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); 66 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
74 } 67 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
1 package cn.iocoder.yudao.module.trade.controller.app.order.vo; 1 package cn.iocoder.yudao.module.trade.controller.app.order.vo;
2 2
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 5 import lombok.Data;
5 6
  7 +import javax.validation.constraints.AssertTrue;
  8 +
6 @Schema(description = "用户 App - 交易订单创建 Request VO") 9 @Schema(description = "用户 App - 交易订单创建 Request VO")
7 @Data 10 @Data
8 public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO { 11 public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
@@ -10,4 +13,10 @@ public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO { @@ -10,4 +13,10 @@ public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
10 @Schema(description = "备注", example = "这个是我的订单哟") 13 @Schema(description = "备注", example = "这个是我的订单哟")
11 private String remark; 14 private String remark;
12 15
  16 + @AssertTrue(message = "配送方式不能为空")
  17 + @JsonIgnore
  18 + public boolean isDeliveryTypeNotNull() {
  19 + return getDeliveryType() != null;
  20 + }
  21 +
13 } 22 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
@@ -30,7 +30,7 @@ public class AppTradeOrderSettlementReqVO { @@ -30,7 +30,7 @@ public class AppTradeOrderSettlementReqVO {
30 private Boolean pointStatus; 30 private Boolean pointStatus;
31 31
32 // ========== 配送相关相关字段 ========== 32 // ========== 配送相关相关字段 ==========
33 - @Schema(description = "配送方式", required = true, example = "1") 33 + @Schema(description = "配送方式", example = "1")
34 @InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确") 34 @InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确")
35 private Integer deliveryType; 35 private Integer deliveryType;
36 36
@@ -62,6 +62,8 @@ public class AppTradeOrderSettlementReqVO { @@ -62,6 +62,8 @@ public class AppTradeOrderSettlementReqVO {
62 @Schema(description = "砍价活动编号", example = "123") 62 @Schema(description = "砍价活动编号", example = "123")
63 private Long bargainActivityId; 63 private Long bargainActivityId;
64 64
  65 + // TODO @puhui999:可以写个参数校验,如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况,items 应该只有一个
  66 +
65 @Data 67 @Data
66 @Schema(description = "用户 App - 商品项") 68 @Schema(description = "用户 App - 商品项")
67 @Valid 69 @Valid
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
@@ -35,7 +35,7 @@ public interface BrokerageRecordConvert { @@ -35,7 +35,7 @@ public interface BrokerageRecordConvert {
35 35
36 default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, 36 default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
37 Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, 37 Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
38 - String title, Long sourceUserId, Integer sourceUserType) { 38 + String title, Long sourceUserId, Integer sourceUserLevel) {
39 brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); 39 brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
40 // 不冻结时,佣金直接就是结算状态 40 // 不冻结时,佣金直接就是结算状态
41 Integer status = brokerageFrozenDays > 0 41 Integer status = brokerageFrozenDays > 0
@@ -47,7 +47,7 @@ public interface BrokerageRecordConvert { @@ -47,7 +47,7 @@ public interface BrokerageRecordConvert {
47 .setTitle(title) 47 .setTitle(title)
48 .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d))) 48 .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
49 .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime) 49 .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime)
50 - .setSourceUserType(sourceUserType).setSourceUserId(sourceUserId); 50 + .setSourceUserLevel(sourceUserLevel).setSourceUserId(sourceUserId);
51 } 51 }
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) {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.user; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.user;
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 5 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
6 -import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;  
7 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserRespVO; 6 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserRespVO;
8 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
9 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; 8 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
@@ -56,6 +55,4 @@ public interface BrokerageUserConvert { @@ -56,6 +55,4 @@ public interface BrokerageUserConvert {
56 user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar())); 55 user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
57 return target; 56 return target;
58 } 57 }
59 -  
60 - BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser);  
61 } 58 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/withdraw/BrokerageWithdrawConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.convert.brokerage.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRejectReqVO;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  8 +import org.mapstruct.Mapper;
  9 +import org.mapstruct.factory.Mappers;
  10 +
  11 +import java.util.List;
  12 +import java.util.Map;
  13 +import java.util.Optional;
  14 +
  15 +/**
  16 + * 佣金提现 Convert
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Mapper
  21 +public interface BrokerageWithdrawConvert {
  22 +
  23 + BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class);
  24 +
  25 + BrokerageWithdrawDO convert(BrokerageWithdrawRejectReqVO bean);
  26 +
  27 + BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean);
  28 +
  29 + List<BrokerageWithdrawRespVO> convertList(List<BrokerageWithdrawDO> list);
  30 +
  31 + PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> page);
  32 +
  33 + default PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
  34 + PageResult<BrokerageWithdrawRespVO> result = convertPage(pageResult);
  35 + for (BrokerageWithdrawRespVO vo : result.getList()) {
  36 + vo.setUserNickname(Optional.ofNullable(userMap.get(vo.getUserId())).map(MemberUserRespDTO::getNickname).orElse(null));
  37 + }
  38 + return result;
  39 + }
  40 +
  41 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -14,9 +14,7 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT @@ -14,9 +14,7 @@ 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;  
18 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 17 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
19 -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;  
20 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 18 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
21 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; 19 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
22 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; 20 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@@ -29,7 +27,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; @@ -29,7 +27,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
29 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; 27 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
30 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 28 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
31 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 29 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
32 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;  
33 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; 30 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
34 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; 31 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
35 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 32 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@@ -59,6 +56,7 @@ public interface TradeOrderConvert { @@ -59,6 +56,7 @@ public interface TradeOrderConvert {
59 56
60 @Mappings({ 57 @Mappings({
61 @Mapping(target = "id", ignore = true), 58 @Mapping(target = "id", ignore = true),
  59 + @Mapping(source = "userId", target = "userId"),
62 @Mapping(source = "createReqVO.couponId", target = "couponId"), 60 @Mapping(source = "createReqVO.couponId", target = "couponId"),
63 @Mapping(target = "remark", ignore = true), 61 @Mapping(target = "remark", ignore = true),
64 @Mapping(source = "createReqVO.remark", target = "userRemark"), 62 @Mapping(source = "createReqVO.remark", target = "userRemark"),
@@ -67,14 +65,10 @@ public interface TradeOrderConvert { @@ -67,14 +65,10 @@ public interface TradeOrderConvert {
67 @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"), 65 @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
68 @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"), 66 @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"),
69 @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"), 67 @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"),
70 - @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"),  
71 - @Mapping(source = "address.name", target = "receiverName"),  
72 - @Mapping(source = "address.mobile", target = "receiverMobile"),  
73 - @Mapping(source = "address.areaId", target = "receiverAreaId"),  
74 - @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), 68 + @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice")
75 }) 69 })
76 TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, 70 TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
77 - TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address); 71 + TradePriceCalculateRespBO calculateRespBO);
78 72
79 TradeOrderRespDTO convert(TradeOrderDO orderDO); 73 TradeOrderRespDTO convert(TradeOrderDO orderDO);
80 74
@@ -92,23 +86,16 @@ public interface TradeOrderConvert { @@ -92,23 +86,16 @@ public interface TradeOrderConvert {
92 TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item); 86 TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);
93 87
94 default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) { 88 default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) {
95 - return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list)); 89 + List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
  90 + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
  91 + return new ProductSkuUpdateStockReqDTO(items);
96 } 92 }
97 -  
98 - default ProductSkuUpdateStockReqDTO convertNegative(List<TradeOrderItemDO> list) {  
99 - List<ProductSkuUpdateStockReqDTO.Item> items = TradeOrderConvert.INSTANCE.convertList(list);  
100 - items.forEach(item -> item.setIncrCount(-item.getIncrCount())); 93 + default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
  94 + List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
  95 + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
101 return new ProductSkuUpdateStockReqDTO(items); 96 return new ProductSkuUpdateStockReqDTO(items);
102 } 97 }
103 98
104 - List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);  
105 -  
106 - @Mappings({  
107 - @Mapping(source = "skuId", target = "id"),  
108 - @Mapping(source = "count", target = "incrCount"),  
109 - })  
110 - ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);  
111 -  
112 default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems, 99 default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
113 TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) { 100 TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) {
114 PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() 101 PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO()
@@ -221,8 +208,10 @@ public interface TradeOrderConvert { @@ -221,8 +208,10 @@ public interface TradeOrderConvert {
221 208
222 default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, 209 default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
223 List<CartDO> cartList) { 210 List<CartDO> cartList) {
224 - TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();  
225 - reqBO.setUserId(userId).setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId()) 211 + TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId)
  212 + .setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus())
  213 + .setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId())
  214 + .setPickUpStoreId(settlementReqVO.getPickUpStoreId())
226 .setItems(new ArrayList<>(settlementReqVO.getItems().size())); 215 .setItems(new ArrayList<>(settlementReqVO.getItems().size()));
227 // 商品项的构建 216 // 商品项的构建
228 Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); 217 Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
@@ -276,19 +265,13 @@ public interface TradeOrderConvert { @@ -276,19 +265,13 @@ public interface TradeOrderConvert {
276 265
277 TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); 266 TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
278 267
279 - default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) { 268 + default BrokerageAddReqBO convert(MemberUserRespDTO user, TradeOrderItemDO item, ProductSkuRespDTO sku) {
280 return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId()) 269 return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
281 .setBasePrice(item.getPayPrice() * item.getCount()) 270 .setBasePrice(item.getPayPrice() * item.getCount())
282 - .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:标题类似:木晴冰雪成功购买云时代的JVM原理与实战;茫农成功购买深入拆解消息队列47讲  
283 - .setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord()); 271 + .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName()))
  272 + .setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice());
284 } 273 }
285 274
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); 275 TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
293 276
294 @Mappings({ 277 @Mappings({
@@ -300,6 +283,7 @@ public interface TradeOrderConvert { @@ -300,6 +283,7 @@ public interface TradeOrderConvert {
300 @Mapping(target = "userId", source = "userId"), 283 @Mapping(target = "userId", source = "userId"),
301 @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"), 284 @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
302 }) 285 })
303 - TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem); 286 + TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO,
  287 + TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
304 288
305 } 289 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record;
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 4 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
5 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; 5 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
6 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
7 import com.baomidou.mybatisplus.annotation.KeySequence; 6 import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableId; 7 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 8 import com.baomidou.mybatisplus.annotation.TableName;
@@ -83,11 +82,11 @@ public class BrokerageRecordDO extends BaseDO { @@ -83,11 +82,11 @@ public class BrokerageRecordDO extends BaseDO {
83 private LocalDateTime unfreezeTime; 82 private LocalDateTime unfreezeTime;
84 83
85 /** 84 /**
86 - * 来源用户类型 85 + * 来源用户等级
87 * <p> 86 * <p>
88 - * 枚举 {@link BrokerageUserTypeEnum},被推广用户和 {@link #userId} 的推广层级关系 87 + * 被推广用户和 {@link #userId} 的推广层级关系
89 */ 88 */
90 - private Integer sourceUserType; 89 + private Integer sourceUserLevel;
91 /** 90 /**
92 * 来源用户编号 91 * 来源用户编号
93 * <p> 92 * <p>
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/BrokerageUserDO.java
@@ -60,4 +60,12 @@ public class BrokerageUserDO extends BaseDO { @@ -60,4 +60,12 @@ public class BrokerageUserDO extends BaseDO {
60 */ 60 */
61 private Integer frozenPrice; 61 private Integer frozenPrice;
62 62
  63 + /**
  64 + * 等级
  65 + */
  66 + private Integer level;
  67 + /**
  68 + * 路径
  69 + */
  70 + private String path;
63 } 71 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/withdraw/BrokerageWithdrawDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
  5 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
  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 +import java.time.LocalDateTime;
  12 +
  13 +/**
  14 + * 佣金提现 DO
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@TableName("trade_brokerage_withdraw")
  19 +@KeySequence("trade_brokerage_withdraw_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  20 +@Data
  21 +@EqualsAndHashCode(callSuper = true)
  22 +@ToString(callSuper = true)
  23 +@Builder
  24 +@NoArgsConstructor
  25 +@AllArgsConstructor
  26 +public class BrokerageWithdrawDO extends BaseDO {
  27 +
  28 + /**
  29 + * 编号
  30 + */
  31 + @TableId
  32 + private Integer id;
  33 + /**
  34 + * 用户编号
  35 + *
  36 + * 关联 MemberUserDO 的 id 字段
  37 + */
  38 + private Long userId;
  39 +
  40 + /**
  41 + * 提现金额,单位:分
  42 + */
  43 + private Integer price;
  44 + /**
  45 + * 提现手续费,单位:分
  46 + */
  47 + private Integer feePrice;
  48 + /**
  49 + * 当前总佣金,单位:分
  50 + */
  51 + private Integer totalPrice;
  52 + /**
  53 + * 提现类型
  54 + * <p>
  55 + * 枚举 {@link BrokerageWithdrawTypeEnum}
  56 + */
  57 + private Integer type;
  58 +
  59 + /**
  60 + * 真实姓名
  61 + */
  62 + private String name;
  63 + /**
  64 + * 账号
  65 + */
  66 + private String accountNo;
  67 + /**
  68 + * 银行名称
  69 + */
  70 + private String bankName;
  71 + /**
  72 + * 开户地址
  73 + */
  74 + private String bankAddress;
  75 + /**
  76 + * 收款码
  77 + */
  78 + private String accountQrCodeUrl;
  79 + /**
  80 + * 状态
  81 + * <p>
  82 + * 枚举 {@link BrokerageWithdrawStatusEnum}
  83 + */
  84 + private Integer status;
  85 + /**
  86 + * 审核驳回原因
  87 + */
  88 + private String auditReason;
  89 + /**
  90 + * 审核时间
  91 + */
  92 + private LocalDateTime auditTime;
  93 + /**
  94 + * 备注
  95 + */
  96 + private String remark;
  97 +
  98 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -224,6 +224,10 @@ public class TradeOrderDO extends BaseDO { @@ -224,6 +224,10 @@ public class TradeOrderDO extends BaseDO {
224 * 关联 {@link DeliveryPickUpStoreDO#getId()} 224 * 关联 {@link DeliveryPickUpStoreDO#getId()}
225 */ 225 */
226 private Long pickUpStoreId; 226 private Long pickUpStoreId;
  227 + /**
  228 + * 自提核销码
  229 + */
  230 + private String pickUpVerifyCode;
227 231
228 // ========== 售后基本信息 ========== 232 // ========== 售后基本信息 ==========
229 /** 233 /**
@@ -251,12 +255,19 @@ public class TradeOrderDO extends BaseDO { @@ -251,12 +255,19 @@ public class TradeOrderDO extends BaseDO {
251 * 对应 taobao 的 trade.coupon_fee 字段 255 * 对应 taobao 的 trade.coupon_fee 字段
252 */ 256 */
253 private Integer couponPrice; 257 private Integer couponPrice;
254 - // TODO 芋艿:需要记录使用的积分; 258 + /**
  259 + * 使用的积分
  260 + */
  261 + private Integer usePoint;
255 /** 262 /**
256 * 积分抵扣的金额,单位:分 263 * 积分抵扣的金额,单位:分
257 * 264 *
258 * 对应 taobao 的 trade.point_fee 字段 265 * 对应 taobao 的 trade.point_fee 字段
259 */ 266 */
260 private Integer pointPrice; 267 private Integer pointPrice;
  268 +// /**
  269 +// * 奖励的积分 TODO 疯狂:可以使用这个字段哈;
  270 +// */
  271 +// private Integer rewardPoint;
261 272
262 } 273 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
@@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; @@ -5,7 +5,6 @@ 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.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; 6 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
8 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
9 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; 8 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
10 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
11 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
@@ -24,14 +23,12 @@ import java.util.List; @@ -24,14 +23,12 @@ import java.util.List;
24 public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { 23 public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
25 24
26 default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) { 25 default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
27 - boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&  
28 - !BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());  
29 // 分页查询 26 // 分页查询
30 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>() 27 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
31 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) 28 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
32 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) 29 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
33 .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) 30 .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
34 - .eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType()) 31 + .eqIfPresent(BrokerageRecordDO::getSourceUserLevel, reqVO.getSourceUserLevel())
35 .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) 32 .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
36 .orderByDesc(BrokerageRecordDO::getId)); 33 .orderByDesc(BrokerageRecordDO::getId));
37 } 34 }
@@ -59,4 +56,5 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; { @@ -59,4 +56,5 @@ public interface BrokerageRecordMapper extends BaseMapperX&lt;BrokerageRecordDO&gt; {
59 UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, 56 UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
60 @Param("bizType") Integer bizType, 57 @Param("bizType") Integer bizType,
61 @Param("status") Integer status); 58 @Param("status") Integer status);
  59 +
62 } 60 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
1 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user; 1 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 -import cn.hutool.core.util.StrUtil;  
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
7 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
8 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 7 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
9 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 8 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
10 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
11 -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;  
12 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
13 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
14 -import org.apache.ibatis.annotations.Select; 11 +
  12 +import java.util.List;
15 13
16 /** 14 /**
17 * 分销用户 Mapper 15 * 分销用户 Mapper
@@ -21,35 +19,16 @@ import org.apache.ibatis.annotations.Select; @@ -21,35 +19,16 @@ import org.apache.ibatis.annotations.Select;
21 @Mapper 19 @Mapper
22 public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> { 20 public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
23 21
24 - default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) { 22 + default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Integer> levels) {
25 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>() 23 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
26 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) 24 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
27 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) 25 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
28 .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime()) 26 .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
29 - .and(reqVO.getBindUserId() != null, w -> buildBindUserCondition(reqVO, w)) 27 + .findInSetIfPresent(BrokerageUserDO::getPath, reqVO.getBindUserId())
  28 + .inIfPresent(BrokerageUserDO::getLevel, levels)
30 .orderByDesc(BrokerageUserDO::getId)); 29 .orderByDesc(BrokerageUserDO::getId));
31 } 30 }
32 31
33 - static void buildBindUserCondition(BrokerageUserPageReqVO reqVO, LambdaQueryWrapper<BrokerageUserDO> wrapper) {  
34 - if (BrokerageUserTypeEnum.FIRST.getType().equals(reqVO.getUserType())) {  
35 - buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);  
36 - } else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {  
37 - buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);  
38 - } else {  
39 - // TODO @疯狂:要不要把这个逻辑,挪到 Service 里,算出子用户有哪些,然后 IN?  
40 - buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);  
41 - buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); // 通过 or 实现多个条件  
42 - }  
43 - }  
44 -  
45 - static void buildFirstBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {  
46 - wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);  
47 - }  
48 -  
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));  
51 - }  
52 -  
53 /** 32 /**
54 * 更新用户可用佣金(增加) 33 * 更新用户可用佣金(增加)
55 * 34 *
@@ -128,7 +107,8 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; { @@ -128,7 +107,8 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
128 default void updateBindUserIdAndBindUserTimeToNull(Long id) { 107 default void updateBindUserIdAndBindUserTimeToNull(Long id) {
129 update(null, new LambdaUpdateWrapper<BrokerageUserDO>() 108 update(null, new LambdaUpdateWrapper<BrokerageUserDO>()
130 .eq(BrokerageUserDO::getId, id) 109 .eq(BrokerageUserDO::getId, id)
131 - .set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null)); 110 + .set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null)
  111 + .set(BrokerageUserDO::getLevel, 1).set(BrokerageUserDO::getPath, ""));
132 } 112 }
133 113
134 default void updateEnabledFalseAndBrokerageTimeToNull(Long id) { 114 default void updateEnabledFalseAndBrokerageTimeToNull(Long id) {
@@ -137,11 +117,10 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; { @@ -137,11 +117,10 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
137 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); 117 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
138 } 118 }
139 119
140 - default Long selectCountByBindUserId(Long bindUserId) {  
141 - return selectCount(BrokerageUserDO::getBindUserId, bindUserId); 120 + default Long selectCountByBindUserIdAndLevelIn(Long bindUserId, List<Integer> levels) {
  121 + return selectCount(new LambdaQueryWrapperX<BrokerageUserDO>()
  122 + .findInSetIfPresent(BrokerageUserDO::getPath, bindUserId)
  123 + .inIfPresent(BrokerageUserDO::getLevel, levels));
142 } 124 }
143 125
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})")  
145 - Long selectCountByBindUserIdInBindUserId(Long bindUserId);  
146 -  
147 } 126 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/withdraw/BrokerageWithdrawMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +/**
  12 + * 佣金提现 Mapper
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Mapper
  17 +public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO> {
  18 +
  19 + default PageResult<BrokerageWithdrawDO> selectPage(BrokerageWithdrawPageReqVO reqVO) {
  20 + return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageWithdrawDO>()
  21 + .eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId())
  22 + .eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType())
  23 + .likeIfPresent(BrokerageWithdrawDO::getName, reqVO.getName())
  24 + .eqIfPresent(BrokerageWithdrawDO::getAccountNo, reqVO.getAccountNo())
  25 + .likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName())
  26 + .eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus())
  27 + .betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime())
  28 + .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId));
  29 + }
  30 +
  31 + default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) {
  32 + return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>()
  33 + .eq(BrokerageWithdrawDO::getId, id)
  34 + .eq(BrokerageWithdrawDO::getStatus, status));
  35 + }
  36 +
  37 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
@@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
15 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper; 15 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper;
16 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 16 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
17 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; 17 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
18 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
19 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; 18 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
20 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; 19 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
21 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; 20 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@@ -29,6 +28,7 @@ import javax.annotation.Resource; @@ -29,6 +28,7 @@ import javax.annotation.Resource;
29 import java.time.LocalDateTime; 28 import java.time.LocalDateTime;
30 import java.util.ArrayList; 29 import java.util.ArrayList;
31 import java.util.List; 30 import java.util.List;
  31 +import java.util.Objects;
32 32
33 /** 33 /**
34 * 佣金记录 Service 实现类 34 * 佣金记录 Service 实现类
@@ -74,7 +74,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -74,7 +74,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
74 } 74 }
75 // 1.2 计算一级分佣 75 // 1.2 计算一级分佣
76 addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), 76 addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(),
77 - bizType, BrokerageUserTypeEnum.FIRST); 77 + bizType, 1);
78 78
79 // 2.1 获得二级推广员 79 // 2.1 获得二级推广员
80 if (firstUser.getBindUserId() == null) { 80 if (firstUser.getBindUserId() == null) {
@@ -86,7 +86,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -86,7 +86,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
86 } 86 }
87 // 2.2 计算二级分佣 87 // 2.2 计算二级分佣
88 addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), 88 addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(),
89 - bizType, BrokerageUserTypeEnum.SECOND); 89 + bizType, 2);
90 } 90 }
91 91
92 @Override 92 @Override
@@ -142,10 +142,10 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -142,10 +142,10 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
142 * @param brokerageFrozenDays 冻结天数 142 * @param brokerageFrozenDays 冻结天数
143 * @param brokeragePercent 佣金比例 143 * @param brokeragePercent 佣金比例
144 * @param bizType 业务类型 144 * @param bizType 业务类型
145 - * @param sourceUserType 来源用户类型 145 + * @param sourceUserLevel 来源用户等级
146 */ 146 */
147 private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays, 147 private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
148 - Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) { 148 + Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, Integer sourceUserLevel) {
149 // 1.1 处理冻结时间 149 // 1.1 处理冻结时间
150 LocalDateTime unfreezeTime = null; 150 LocalDateTime unfreezeTime = null;
151 if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { 151 if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
@@ -157,12 +157,12 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -157,12 +157,12 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
157 for (BrokerageAddReqBO item : list) { 157 for (BrokerageAddReqBO item : list) {
158 // 计算金额 158 // 计算金额
159 Integer fixedPrice; 159 Integer fixedPrice;
160 - if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) { 160 + if (Objects.equals(sourceUserLevel, 1)) {
161 fixedPrice = item.getFirstFixedPrice(); 161 fixedPrice = item.getFirstFixedPrice();
162 - } else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) { 162 + } else if (Objects.equals(sourceUserLevel, 2)) {
163 fixedPrice = item.getSecondFixedPrice(); 163 fixedPrice = item.getSecondFixedPrice();
164 } else { 164 } else {
165 - throw new IllegalArgumentException(StrUtil.format("来源用户({}) 不合法", sourceUserType)); 165 + throw new IllegalArgumentException(StrUtil.format("用户等级({}) 不合法", sourceUserLevel));
166 } 166 }
167 int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice); 167 int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
168 if (brokeragePrice <= 0) { 168 if (brokeragePrice <= 0) {
@@ -172,7 +172,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -172,7 +172,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
172 // 创建记录实体 172 // 创建记录实体
173 records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), 173 records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
174 brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(), 174 brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(),
175 - item.getSourceUserId(), sourceUserType.getType())); 175 + item.getSourceUserId(), sourceUserLevel));
176 } 176 }
177 if (CollUtil.isEmpty(records)) { 177 if (CollUtil.isEmpty(records)) {
178 return; 178 return;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
1 package cn.iocoder.yudao.module.trade.service.brokerage.user; 1 package cn.iocoder.yudao.module.trade.service.brokerage.user;
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.framework.common.util.date.LocalDateTimeUtils;
4 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 5 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
5 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 6 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
6 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
7 7
  8 +import javax.validation.constraints.NotNull;
  9 +import java.time.LocalDateTime;
8 import java.util.Collection; 10 import java.util.Collection;
9 import java.util.List; 11 import java.util.List;
10 12
@@ -91,10 +93,24 @@ public interface BrokerageUserService { @@ -91,10 +93,24 @@ public interface BrokerageUserService {
91 * 获得推广用户数量 93 * 获得推广用户数量
92 * 94 *
93 * @param bindUserId 绑定的推广员编号 95 * @param bindUserId 绑定的推广员编号
94 - * @param userType 用户类型 96 + * @param level 推广用户等级
95 * @return 推广用户数量 97 * @return 推广用户数量
96 */ 98 */
97 - Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType); 99 + Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level);
  100 +
  101 + /**
  102 + * 【会员】绑定推广员
  103 + *
  104 + * @param userId 用户编号
  105 + * @param bindUserId 推广员编号
  106 + * @param registerTime 用户注册时间
  107 + * @return 是否绑定
  108 + */
  109 + default boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
  110 + // 注册时间在30秒内的,都算新用户
  111 + boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
  112 + return bindBrokerageUser(userId, bindUserId, isNewUser);
  113 + }
98 114
99 /** 115 /**
100 * 【会员】绑定推广员 116 * 【会员】绑定推广员
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
1 package cn.iocoder.yudao.module.trade.service.brokerage.user; 1 package cn.iocoder.yudao.module.trade.service.brokerage.user;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.BooleanUtil; 5 import cn.hutool.core.util.BooleanUtil;
  6 +import cn.hutool.core.util.ObjectUtil;
  7 +import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 9 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 10 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
@@ -9,17 +12,13 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; @@ -9,17 +12,13 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
9 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper; 12 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper;
10 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; 13 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
11 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; 14 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
12 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;  
13 import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; 15 import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
14 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
15 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
16 18
17 import javax.annotation.Resource; 19 import javax.annotation.Resource;
18 import java.time.LocalDateTime; 20 import java.time.LocalDateTime;
19 -import java.util.Collection;  
20 -import java.util.List;  
21 -import java.util.Objects;  
22 -import java.util.Optional; 21 +import java.util.*;
23 22
24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 24 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@@ -51,7 +50,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -51,7 +50,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
51 50
52 @Override 51 @Override
53 public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) { 52 public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
54 - return brokerageUserMapper.selectPage(pageReqVO); 53 + List<Integer> levels = buildUserQueryLevels(pageReqVO.getBindUserId(), pageReqVO.getLevel());
  54 + return brokerageUserMapper.selectPage(pageReqVO, levels);
55 } 55 }
56 56
57 @Override 57 @Override
@@ -66,10 +66,15 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -66,10 +66,15 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
66 return; 66 return;
67 } 67 }
68 68
  69 + // 绑定关系未发生变化
  70 + // TODO @疯狂:这个放到“情况一”之前,貌似也没关系?
  71 + if (Objects.equals(brokerageUser.getBindUserId(), bindUserId)) {
  72 + return;
  73 + }
  74 +
69 // 情况二:修改推广员 75 // 情况二:修改推广员
70 validateCanBindUser(brokerageUser, bindUserId); 76 validateCanBindUser(brokerageUser, bindUserId);
71 - brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)  
72 - .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); 77 + brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(id)));
73 } 78 }
74 79
75 @Override 80 @Override
@@ -132,19 +137,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -132,19 +137,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
132 } 137 }
133 138
134 @Override 139 @Override
135 - public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {  
136 - switch (userType) {  
137 - case ALL: // TODO @疯狂:ALL 是不是不用搞个枚举,默认为空就是不过滤哈~  
138 - Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);  
139 - Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);  
140 - return firstCount + secondCount;  
141 - case FIRST:  
142 - return brokerageUserMapper.selectCountByBindUserId(bindUserId);  
143 - case SECOND:  
144 - return brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);  
145 - default:  
146 - return 0L; 140 + public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) {
  141 + List<Integer> levels = buildUserQueryLevels(bindUserId, level);
  142 + if (CollUtil.isEmpty(levels)) {
  143 + return 0L;
147 } 144 }
  145 + return brokerageUserMapper.selectCountByBindUserIdAndLevelIn(bindUserId, levels);
148 } 146 }
149 147
150 @Override 148 @Override
@@ -171,14 +169,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -171,14 +169,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
171 brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now()); 169 brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now());
172 } 170 }
173 brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()); 171 brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
174 - brokerageUserMapper.insert(brokerageUser); 172 + brokerageUserMapper.insert(fillBindUserData(bindUserId, brokerageUser));
175 } else { 173 } else {
176 - brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)  
177 - .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); 174 + brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(userId)));
178 } 175 }
179 return true; 176 return true;
180 } 177 }
181 178
  179 + private BrokerageUserDO fillBindUserData(Long bindUserId, BrokerageUserDO brokerageUser) {
  180 + BrokerageUserDO bindUser = getBrokerageUser(bindUserId);
  181 +
  182 + Integer bindUserLevel = 0;
  183 + String bindUserPath = "";
  184 + if (bindUser != null) {
  185 + bindUserLevel = ObjectUtil.defaultIfNull(bindUser.getLevel(), 0);
  186 + bindUserPath = bindUser.getPath();
  187 + }
  188 +
  189 + String path = StrUtil.isEmpty(bindUserPath)
  190 + ? String.valueOf(bindUserId)
  191 + : String.format("%s,%s", bindUserPath, bindUserId);
  192 + return brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())
  193 + .setLevel(bindUserLevel + 1).setPath(path);
  194 + }
  195 +
182 @Override 196 @Override
183 public Boolean getUserBrokerageEnabled(Long userId) { 197 public Boolean getUserBrokerageEnabled(Long userId) {
184 // 全局分销功能是否开启 198 // 全局分销功能是否开启
@@ -231,11 +245,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -231,11 +245,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
231 throw exception(BROKERAGE_BIND_SELF); 245 throw exception(BROKERAGE_BIND_SELF);
232 } 246 }
233 247
234 - // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈  
235 - // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!!  
236 - if (Objects.equals(user.getId(), bindUser.getBindUserId())) { 248 + // 下级不能绑定自己的上级
  249 + if (StrUtil.split(bindUser.getPath(), ",").contains(String.valueOf(user.getId()))) {
237 throw exception(BROKERAGE_BIND_LOOP); 250 throw exception(BROKERAGE_BIND_LOOP);
238 } 251 }
239 } 252 }
240 253
  254 + // TODO @芋艿:这个层级,要微信讨论下;
  255 + private List<Integer> buildUserQueryLevels(Long bindUserId, Integer level) {
  256 + List<Integer> levels = new ArrayList<>(2);
  257 +
  258 + BrokerageUserDO bindUser = getBrokerageUser(bindUserId);
  259 + if (bindUser == null) {
  260 + return levels;
  261 + }
  262 +
  263 + if (level == null) {
  264 + // 默认查两层
  265 + levels.add(bindUser.getLevel() + 1);
  266 + levels.add(bindUser.getLevel() + 2);
  267 + } else {
  268 + levels.add(bindUser.getLevel() + level);
  269 + }
  270 + return levels;
  271 +
  272 + }
  273 +
241 } 274 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/withdraw/BrokerageWithdrawService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  6 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
  7 +
  8 +/**
  9 + * 佣金提现 Service 接口
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public interface BrokerageWithdrawService {
  14 +
  15 + /**
  16 + * 审核佣金提现
  17 + *
  18 + * @param id 佣金编号
  19 + * @param status 审核状态
  20 + * @param auditReason 驳回原因
  21 + */
  22 +
  23 + void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason);
  24 +
  25 + /**
  26 + * 获得佣金提现
  27 + *
  28 + * @param id 编号
  29 + * @return 佣金提现
  30 + */
  31 + BrokerageWithdrawDO getBrokerageWithdraw(Integer id);
  32 +
  33 + /**
  34 + * 获得佣金提现分页
  35 + *
  36 + * @param pageReqVO 分页查询
  37 + * @return 佣金提现分页
  38 + */
  39 + PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO);
  40 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/withdraw/BrokerageWithdrawServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
  2 +
  3 +import cn.hutool.core.date.LocalDateTimeUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
  8 +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
  9 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
  10 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  11 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw.BrokerageWithdrawMapper;
  12 +import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants;
  13 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
  14 +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
  15 +import org.springframework.stereotype.Service;
  16 +import org.springframework.transaction.annotation.Transactional;
  17 +import org.springframework.validation.annotation.Validated;
  18 +
  19 +import javax.annotation.Resource;
  20 +import java.time.LocalDateTime;
  21 +import java.util.Map;
  22 +
  23 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  24 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_NOT_EXISTS;
  25 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING;
  26 +
  27 +/**
  28 + * 佣金提现 Service 实现类
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Service
  33 +@Validated
  34 +public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
  35 +
  36 + @Resource
  37 + private BrokerageWithdrawMapper brokerageWithdrawMapper;
  38 +
  39 + @Resource
  40 + private BrokerageRecordService brokerageRecordService;
  41 +
  42 + @Resource
  43 + private NotifyMessageSendApi notifyMessageSendApi;
  44 +
  45 + @Override
  46 + @Transactional(rollbackFor = Exception.class)
  47 + public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason) {
  48 + // 1.1 校验存在
  49 + BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
  50 + // 1.2 校验状态为审核中
  51 + if (ObjectUtil.notEqual(BrokerageWithdrawStatusEnum.AUDITING.getStatus(), withdraw.getStatus())) {
  52 + throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
  53 + }
  54 +
  55 + // 2. 更新
  56 + BrokerageWithdrawDO updateObj = new BrokerageWithdrawDO()
  57 + .setStatus(status.getStatus())
  58 + .setAuditReason(auditReason)
  59 + .setAuditTime(LocalDateTime.now());
  60 + int rows = brokerageWithdrawMapper.updateByIdAndStatus(id, BrokerageWithdrawStatusEnum.AUDITING.getStatus(), updateObj);
  61 + if (rows == 0) {
  62 + throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
  63 + }
  64 +
  65 + // 3. 驳回时需要退还用户佣金
  66 + String templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE;
  67 + if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
  68 + templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT;
  69 +
  70 + // todo @owen
  71 +// brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW, withdraw.getPrice(), "");
  72 + }
  73 +
  74 + // 4. 通知用户
  75 + Map<String, Object> templateParams = MapUtil.<String, Object>builder()
  76 + .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime()))
  77 + .put("price", String.format("%.2f", withdraw.getPrice() / 100d))
  78 + .put("reason", withdraw.getAuditReason())
  79 + .build();
  80 + NotifySendSingleToUserReqDTO reqDTO = new NotifySendSingleToUserReqDTO()
  81 + .setUserId(withdraw.getUserId())
  82 + .setTemplateCode(templateCode).setTemplateParams(templateParams);
  83 + notifyMessageSendApi.sendSingleMessageToMember(reqDTO);
  84 + }
  85 +
  86 + private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) {
  87 + BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id);
  88 + if (withdraw == null) {
  89 + throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS);
  90 + }
  91 + return withdraw;
  92 + }
  93 +
  94 + @Override
  95 + public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) {
  96 + return brokerageWithdrawMapper.selectById(id);
  97 + }
  98 +
  99 + @Override
  100 + public PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO) {
  101 + return brokerageWithdrawMapper.selectPage(pageReqVO);
  102 + }
  103 +
  104 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.order; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.order;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.ObjectUtil; 5 import cn.hutool.core.util.ObjectUtil;
  6 +import cn.hutool.core.util.RandomUtil;
6 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
7 import cn.hutool.extra.spring.SpringUtil; 8 import cn.hutool.extra.spring.SpringUtil;
8 import cn.iocoder.yudao.framework.common.core.KeyValue; 9 import cn.iocoder.yudao.framework.common.core.KeyValue;
@@ -12,6 +13,8 @@ import cn.iocoder.yudao.module.member.api.address.AddressApi; @@ -12,6 +13,8 @@ import cn.iocoder.yudao.module.member.api.address.AddressApi;
12 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 13 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
13 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; 14 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
14 import cn.iocoder.yudao.module.member.api.point.MemberPointApi; 15 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;
15 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; 18 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
16 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; 19 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
17 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 20 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@@ -40,11 +43,11 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; @@ -40,11 +43,11 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
40 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; 43 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
41 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 44 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
42 import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO; 45 import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
43 -import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;  
44 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 46 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
45 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 47 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
46 import cn.iocoder.yudao.module.trade.enums.order.*; 48 import cn.iocoder.yudao.module.trade.enums.order.*;
47 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 49 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  50 +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
48 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; 51 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
49 import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; 52 import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
50 import cn.iocoder.yudao.module.trade.service.cart.CartService; 53 import cn.iocoder.yudao.module.trade.service.cart.CartService;
@@ -115,6 +118,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -115,6 +118,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
115 @Resource 118 @Resource
116 private BargainRecordApi bargainRecordApi; 119 private BargainRecordApi bargainRecordApi;
117 @Resource 120 @Resource
  121 + private MemberUserApi memberUserApi;
  122 + @Resource
118 private MemberLevelApi memberLevelApi; 123 private MemberLevelApi memberLevelApi;
119 @Resource 124 @Resource
120 private MemberPointApi memberPointApi; 125 private MemberPointApi memberPointApi;
@@ -178,140 +183,127 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -178,140 +183,127 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
178 183
179 @Override 184 @Override
180 @Transactional(rollbackFor = Exception.class) 185 @Transactional(rollbackFor = Exception.class)
  186 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
181 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { 187 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
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. 价格计算 188 + // 0. 价格计算
191 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); 189 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
192 190
  191 + // 1. 订单创建前的逻辑
  192 + beforeCreateTradeOrder(userId, createReqVO, calculateRespBO);
  193 +
193 // 2.1 插入 TradeOrderDO 订单 194 // 2.1 插入 TradeOrderDO 订单
194 TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO); 195 TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO);
195 // 2.2 插入 TradeOrderItemDO 订单项 196 // 2.2 插入 TradeOrderItemDO 订单项
196 List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO); 197 List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO);
197 198
198 - // 3. 订单创建完后的逻辑 199 + // 3. 订单创建后的逻辑
199 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO); 200 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
200 -  
201 - // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!  
202 return order; 201 return order;
203 } 202 }
204 203
205 -  
206 // TODO @puhui999:订单超时,自动取消; 204 // TODO @puhui999:订单超时,自动取消;
207 205
208 - /**  
209 - * 校验收件地址是否存在  
210 - *  
211 - * @param userId 用户编号  
212 - * @param addressId 收件地址编号  
213 - * @return 收件地址  
214 - */  
215 - private AddressRespDTO validateAddress(Long userId, Long addressId) {  
216 - AddressRespDTO address = addressApi.getAddress(addressId, userId);  
217 - if (address == null) {  
218 - throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND);  
219 - }  
220 - return address;  
221 - }  
222 -  
223 private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, 206 private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
224 TradePriceCalculateRespBO calculateRespBO) { 207 TradePriceCalculateRespBO calculateRespBO) {
225 - // 用户选择物流配送的时候才需要填写收货地址  
226 - AddressRespDTO address = new AddressRespDTO();  
227 - if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) {  
228 - // 用户收件地址的校验  
229 - address = validateAddress(userId, createReqVO.getAddressId());  
230 - }  
231 - TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);  
232 - String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);  
233 - order.setType(validateActivity(createReqVO));  
234 - order.setNo(no); 208 + TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO);
  209 + order.setType(calculateRespBO.getType());
  210 + order.setNo(orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX));
235 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); 211 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
236 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); 212 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
237 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); 213 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
238 order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? 214 order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
239 - // 支付信息 215 + // 支付 + 退款信息
240 order.setAdjustPrice(0).setPayStatus(false); 216 order.setAdjustPrice(0).setPayStatus(false);
  217 + order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
241 // 物流信息 218 // 物流信息
242 order.setDeliveryType(createReqVO.getDeliveryType()); 219 order.setDeliveryType(createReqVO.getDeliveryType());
243 - // 退款信息  
244 - order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); 220 + if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
  221 + AddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
  222 + Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算
  223 + order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile())
  224 + .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress());
  225 + } else if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.PICK_UP.getType())) {
  226 + order.setReceiverName(createReqVO.getReceiverName()).setReceiverMobile(createReqVO.getReceiverMobile());
  227 + order.setPickUpVerifyCode(RandomUtil.randomNumbers(8)); // 随机一个核销码,长度为 8 位
  228 + }
245 tradeOrderMapper.insert(order); 229 tradeOrderMapper.insert(order);
246 - // TODO @puhui999:如果是门店订单,则需要生成核销码;  
247 return order; 230 return order;
248 } 231 }
249 232
  233 + private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO,
  234 + TradePriceCalculateRespBO calculateRespBO) {
  235 + List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO);
  236 + tradeOrderItemMapper.insertBatch(orderItems);
  237 + return orderItems;
  238 + }
  239 +
250 /** 240 /**
251 - * 校验活动,并返回订单类型 241 + * 订单创建前,执行前置逻辑
252 * 242 *
253 - * @param createReqVO 请求参数  
254 - * @return 订单类型 243 + * @param userId 用户编号
  244 + * @param createReqVO 创建订单请求
  245 + * @param calculateRespBO 订单价格计算结果
255 */ 246 */
256 - private Integer validateActivity(AppTradeOrderCreateReqVO createReqVO) {  
257 - if (createReqVO.getSeckillActivityId() != null) {  
258 - return TradeOrderTypeEnum.SECKILL.getType();  
259 - }  
260 - if (createReqVO.getCombinationActivityId() != null) {  
261 - return TradeOrderTypeEnum.COMBINATION.getType();  
262 - }  
263 - // TODO 砍价敬请期待  
264 - return TradeOrderTypeEnum.NORMAL.getType();  
265 - } 247 + private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
  248 + TradePriceCalculateRespBO calculateRespBO) {
  249 + // 1. 执行订单创建前置处理器
  250 + TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
  251 + beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
  252 + beforeOrderCreateReqBO.setUserId(userId);
  253 + beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
  254 + // TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
  255 + tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
266 256
267 - private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {  
268 - List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO);  
269 - tradeOrderItemMapper.insertBatch(orderItems);  
270 - return orderItems; 257 + // 2. 下单时扣减商品库存
  258 + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
271 } 259 }
272 260
273 /** 261 /**
274 - * 执行创建完创建完订单后的逻辑 262 + * 订单创建后,执行后置逻辑
275 * 263 *
276 * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等 264 * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等
277 * 265 *
278 * @param userId 用户编号 266 * @param userId 用户编号
279 * @param createReqVO 创建订单请求 267 * @param createReqVO 创建订单请求
280 - * @param tradeOrderDO 交易订单 268 + * @param order 交易订单
281 * @param calculateRespBO 订单价格计算结果 269 * @param calculateRespBO 订单价格计算结果
282 */ 270 */
283 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, 271 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
284 - TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, 272 + TradeOrderDO order, List<TradeOrderItemDO> orderItems,
285 TradePriceCalculateRespBO calculateRespBO) { 273 TradePriceCalculateRespBO calculateRespBO) {
286 - // 执行订单创建后置处理器  
287 - tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));  
288 -  
289 - // 扣减积分 TODO 芋艿:待实现,需要前置;  
290 - // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 274 + // 1. 执行订单创建后置处理器
  275 + // TODO @puhui999:从通用性来说,应该不用 orderItems.get(0)
  276 + tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
  277 + TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
291 278
292 - // 有使用优惠券时更新 TODO 芋艿:需要前置; 279 + // 2. 有使用优惠券时更新
  280 + // 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
293 if (createReqVO.getCouponId() != null) { 281 if (createReqVO.getCouponId() != null) {
294 couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId) 282 couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId)
295 - .setOrderId(tradeOrderDO.getId())); 283 + .setOrderId(order.getId()));
296 } 284 }
297 285
298 - // 下单时扣减商品库存  
299 - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); 286 + // 3. 扣减积分
  287 + // 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务
  288 + if (order.getUsePoint() != null && order.getUsePoint() > 0) {
  289 + memberPointApi.reducePoint(userId, calculateRespBO.getUsePoint(),
  290 + MemberPointBizTypeEnum.ORDER_USE.getType(), String.valueOf(order.getId()));
  291 + }
300 292
301 - // 删除购物车商品 293 + // 4. 删除购物车商品
302 Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); 294 Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
303 if (CollUtil.isNotEmpty(cartIds)) { 295 if (CollUtil.isNotEmpty(cartIds)) {
304 cartService.deleteCart(userId, cartIds); 296 cartService.deleteCart(userId, cartIds);
305 } 297 }
306 298
307 - // 生成预支付  
308 - createPayOrder(tradeOrderDO, orderItems, calculateRespBO); 299 + // 5. 生成预支付
  300 + createPayOrder(order, orderItems, calculateRespBO);
309 301
310 - // 增加订单日志 TODO 芋艿:待实现 302 + // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
311 } 303 }
312 304
313 -  
314 - private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) { 305 + private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
  306 + TradePriceCalculateRespBO calculateRespBO) {
315 // 创建支付单,用于后续的支付 307 // 创建支付单,用于后续的支付
316 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( 308 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
317 order, orderItems, calculateRespBO, tradeOrderProperties); 309 order, orderItems, calculateRespBO, tradeOrderProperties);
@@ -339,6 +331,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -339,6 +331,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
339 } 331 }
340 // 校验活动 332 // 校验活动
341 // 1、拼团活动 333 // 1、拼团活动
  334 + // TODO @puhui999:这块也抽象到 handler 里
342 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { 335 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
343 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 336 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
344 combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); 337 combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
@@ -416,7 +409,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -416,7 +409,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
416 // 1.1 校验并获得交易订单(可发货) 409 // 1.1 校验并获得交易订单(可发货)
417 TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId()); 410 TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
418 // 1.2 校验 deliveryType 是否为快递,是快递才可以发货 411 // 1.2 校验 deliveryType 是否为快递,是快递才可以发货
419 - if (ObjectUtil.notEqual(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) { 412 + if (ObjectUtil.notEqual(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
420 throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS); 413 throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS);
421 } 414 }
422 415
@@ -726,7 +719,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -726,7 +719,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
726 } 719 }
727 720
728 // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来 721 // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
729 - tradeOrderHandlers.forEach(handler -> handler.rollbackStock()); 722 + tradeOrderHandlers.forEach(handler -> handler.rollback());
730 723
731 // 2.回滚库存 724 // 2.回滚库存
732 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); 725 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
@@ -736,6 +729,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -736,6 +729,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
736 couponApi.returnUsedCoupon(order.getCouponId()); 729 couponApi.returnUsedCoupon(order.getCouponId());
737 730
738 // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择; 731 // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择;
  732 + // TODO @疯狂:有赞是可配置(支付 or 确认收货),我们按照支付好列;然后这里的退积分,指的是下单时的积分抵扣。
739 733
740 // TODO 芋艿:OrderLog 734 // TODO 芋艿:OrderLog
741 735
@@ -768,22 +762,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -768,22 +762,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
768 762
769 @Async 763 @Async
770 protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) { 764 protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) {
771 - int bizType = MemberPointBizTypeEnum.ORDER_BUY.getType(); 765 + // TODO @疯狂:具体多少积分,需要分成 2 不分:1. 支付金额;2. 商品金额
  766 + int bizType = MemberPointBizTypeEnum.ORDER_REWARD.getType();
772 memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId)); 767 memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId));
773 } 768 }
774 769
775 @Async 770 @Async
776 protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) { 771 protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) {
  772 + // TODO @疯狂:退款时,按照金额比例,退还积分;https://help.youzan.com/displaylist/detail_4_4-1-49185
777 int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType(); 773 int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType();
778 memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); 774 memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
779 } 775 }
780 776
781 -  
782 @Async 777 @Async
783 protected void addBrokerageAsync(Long userId, Long orderId) { 778 protected void addBrokerageAsync(Long userId, Long orderId) {
  779 + MemberUserRespDTO user = memberUserApi.getUser(userId);
  780 + Assert.notNull(user);
  781 +
784 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId); 782 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
785 List<BrokerageAddReqBO> list = convertList(orderItems, 783 List<BrokerageAddReqBO> list = convertList(orderItems,
786 - item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId()))); 784 + item -> TradeOrderConvert.INSTANCE.convert(user, item, productSkuApi.getSku(item.getSkuId())));
787 brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list); 785 brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list);
788 } 786 }
789 787
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.bo; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.bo;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -import javax.validation.Valid;  
7 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
8 7
9 // TODO 芋艿:在想想这些参数的定义 8 // TODO 芋艿:在想想这些参数的定义
@@ -15,6 +14,8 @@ import javax.validation.constraints.NotNull; @@ -15,6 +14,8 @@ import javax.validation.constraints.NotNull;
15 @Data 14 @Data
16 public class TradeBeforeOrderCreateReqBO { 15 public class TradeBeforeOrderCreateReqBO {
17 16
  17 + // TODO @puhui999:注释也写下哈;bo 还是写注释噢
  18 +
18 @NotNull(message = "订单类型不能为空") 19 @NotNull(message = "订单类型不能为空")
19 private Integer orderType; 20 private Integer orderType;
20 21
@@ -34,25 +35,16 @@ public class TradeBeforeOrderCreateReqBO { @@ -34,25 +35,16 @@ public class TradeBeforeOrderCreateReqBO {
34 @Schema(description = "砍价活动编号", example = "123") 35 @Schema(description = "砍价活动编号", example = "123")
35 private Long bargainActivityId; 36 private Long bargainActivityId;
36 37
37 - @NotNull(message = "购买数量不能为空")  
38 - private Integer count;  
39 -  
40 - @NotNull(message = "活动商品不能为空")  
41 - private Item item; 38 + @NotNull(message = "SPU 编号不能为空")
  39 + private Long spuId;
42 40
43 - @Data  
44 - @Valid  
45 - public static class Item { 41 + @NotNull(message = "SKU 编号活动商品不能为空")
  42 + private Long skuId;
46 43
47 - @NotNull(message = "SPU 编号不能为空")  
48 - private Long spuId; 44 + @NotNull(message = "用户编号不能为空")
  45 + private Long userId;
49 46
50 - @NotNull(message = "SKU 编号活动商品不能为空")  
51 - private Long skuId;  
52 -  
53 - @NotNull(message = "购买数量不能为空")  
54 - private Integer count;  
55 -  
56 - } 47 + @NotNull(message = "购买数量不能为空")
  48 + private Integer count;
57 49
58 } 50 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java
@@ -22,7 +22,7 @@ public class TradeBargainHandler implements TradeOrderHandler { @@ -22,7 +22,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
22 22
23 @Override 23 @Override
24 public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) { 24 public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
25 - // 如果是秒杀订单 25 + // 如果是砍价订单
26 if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) { 26 if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
27 return; 27 return;
28 } 28 }
@@ -37,7 +37,7 @@ public class TradeBargainHandler implements TradeOrderHandler { @@ -37,7 +37,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
37 } 37 }
38 38
39 @Override 39 @Override
40 - public void rollbackStock() { 40 + public void rollback() {
41 41
42 } 42 }
43 43
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
1 package cn.iocoder.yudao.module.trade.service.order.handler; 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 -import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi; 4 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
5 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; 5 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
6 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; 6 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
7 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 7 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
@@ -20,7 +20,7 @@ import javax.annotation.Resource; @@ -20,7 +20,7 @@ import javax.annotation.Resource;
20 public class TradeCombinationHandler implements TradeOrderHandler { 20 public class TradeCombinationHandler implements TradeOrderHandler {
21 21
22 @Resource 22 @Resource
23 - private CombinationApi combinationApi; 23 + private CombinationActivityApi combinationActivityApi;
24 @Resource 24 @Resource
25 private CombinationRecordApi combinationRecordApi; 25 private CombinationRecordApi combinationRecordApi;
26 26
@@ -32,17 +32,22 @@ public class TradeCombinationHandler implements TradeOrderHandler { @@ -32,17 +32,22 @@ public class TradeCombinationHandler implements TradeOrderHandler {
32 } 32 }
33 33
34 // 校验是否满足拼团活动相关限制 34 // 校验是否满足拼团活动相关限制
35 - combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO)); 35 + combinationActivityApi.validateCombination(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
36 } 36 }
37 37
38 @Override 38 @Override
39 public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) { 39 public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  40 + // TODO @puhui999:需要判断下;
  41 + if (true) {
  42 + return;
  43 + }
  44 +
40 // 创建砍价记录 45 // 创建砍价记录
41 combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO)); 46 combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
42 } 47 }
43 48
44 @Override 49 @Override
45 - public void rollbackStock() { 50 + public void rollback() {
46 51
47 } 52 }
48 53
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
@@ -25,8 +25,8 @@ public interface TradeOrderHandler { @@ -25,8 +25,8 @@ public interface TradeOrderHandler {
25 void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO); 25 void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
26 26
27 /** 27 /**
28 - * 回滚活动相关库存 28 + * 回滚
29 */ 29 */
30 - void rollbackStock(); 30 + void rollback();
31 31
32 } 32 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
2 2
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; 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; 5 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
7 import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO; 6 import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
8 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO; 7 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
@@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler { @@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
28 return; 27 return;
29 } 28 }
30 29
31 - seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO)); 30 + seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
32 } 31 }
33 32
34 @Override 33 @Override
@@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler { @@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
37 } 36 }
38 37
39 @Override 38 @Override
40 - public void rollbackStock() { 39 + public void rollback() {
41 40
42 } 41 }
43 42
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
1 package cn.iocoder.yudao.module.trade.service.price.bo; 1 package cn.iocoder.yudao.module.trade.service.price.bo;
2 2
3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
4 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;  
5 import lombok.Data; 4 import lombok.Data;
6 5
7 import javax.validation.Valid; 6 import javax.validation.Valid;
@@ -18,13 +17,6 @@ import java.util.List; @@ -18,13 +17,6 @@ import java.util.List;
18 public class TradePriceCalculateReqBO { 17 public class TradePriceCalculateReqBO {
19 18
20 /** 19 /**
21 - * 订单类型  
22 - *  
23 - * 枚举 {@link TradeOrderTypeEnum}  
24 - */  
25 - private Integer type;  
26 -  
27 - /**  
28 * 用户编号 20 * 用户编号
29 * 21 *
30 * 对应 MemberUserDO 的 id 编号 22 * 对应 MemberUserDO 的 id 编号
@@ -37,20 +29,31 @@ public class TradePriceCalculateReqBO { @@ -37,20 +29,31 @@ public class TradePriceCalculateReqBO {
37 * 对应 CouponDO 的 id 编号 29 * 对应 CouponDO 的 id 编号
38 */ 30 */
39 private Long couponId; 31 private Long couponId;
  32 + // TODO @疯狂:需要增加一个 PriceCalculator 实现积分扣减的计算;写回到 TradePriceCalculateRespBO 的 usePoint
  33 + /**
  34 + * 是否使用积分
  35 + */
  36 + @NotNull(message = "是否使用积分不能为空")
  37 + private Boolean pointStatus;
40 38
41 /** 39 /**
  40 + * 配送方式
  41 + *
  42 + * 枚举 {@link DeliveryTypeEnum}
  43 + */
  44 + private Integer deliveryType;
  45 + /**
42 * 收货地址编号 46 * 收货地址编号
43 * 47 *
44 * 对应 MemberAddressDO 的 id 编号 48 * 对应 MemberAddressDO 的 id 编号
45 */ 49 */
46 private Long addressId; 50 private Long addressId;
47 -  
48 /** 51 /**
49 - * 配送方式 52 + * 自提门店编号
50 * 53 *
51 - * 枚举 {@link DeliveryTypeEnum} 54 + * 对应 PickUpStoreDO 的 id 编号
52 */ 55 */
53 - private Integer deliveryType; 56 + private Long pickUpStoreId;
54 57
55 /** 58 /**
56 * 商品 SKU 数组 59 * 商品 SKU 数组
@@ -58,6 +61,30 @@ public class TradePriceCalculateReqBO { @@ -58,6 +61,30 @@ public class TradePriceCalculateReqBO {
58 @NotNull(message = "商品数组不能为空") 61 @NotNull(message = "商品数组不能为空")
59 private List<Item> items; 62 private List<Item> items;
60 63
  64 + // ========== 秒杀活动相关字段 ==========
  65 + /**
  66 + * 秒杀活动编号
  67 + */
  68 + private Long seckillActivityId;
  69 +
  70 + // ========== 拼团活动相关字段 ==========
  71 + // TODO @puhui999:是不是拼团记录的编号哈?
  72 + /**
  73 + * 拼团活动编号
  74 + */
  75 + private Long combinationActivityId;
  76 +
  77 + /**
  78 + * 拼团团长编号
  79 + */
  80 + private Long combinationHeadId;
  81 +
  82 + // ========== 砍价活动相关字段 ==========
  83 + /**
  84 + * 砍价活动编号
  85 + */
  86 + private Long bargainActivityId;
  87 +
61 /** 88 /**
62 * 商品 SKU 89 * 商品 SKU
63 */ 90 */
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
@@ -49,6 +49,11 @@ public class TradePriceCalculateRespBO { @@ -49,6 +49,11 @@ public class TradePriceCalculateRespBO {
49 private Long couponId; 49 private Long couponId;
50 50
51 /** 51 /**
  52 + * 使用的积分
  53 + */
  54 + private Integer usePoint;
  55 +
  56 + /**
52 * 订单价格 57 * 订单价格
53 */ 58 */
54 @Data 59 @Data
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
@@ -2,11 +2,14 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; @@ -2,11 +2,14 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.module.member.api.address.AddressApi; 6 import cn.iocoder.yudao.module.member.api.address.AddressApi;
6 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 7 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
7 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 10 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
9 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; 11 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
  12 +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
10 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; 13 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 14 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
12 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 15 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -22,8 +25,7 @@ import java.util.Set; @@ -22,8 +25,7 @@ import java.util.Set;
22 25
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
25 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY;  
26 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND; 28 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
27 29
28 /** 30 /**
29 * 运费的 {@link TradePriceCalculator} 实现类 31 * 运费的 {@link TradePriceCalculator} 实现类
@@ -37,20 +39,41 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -37,20 +39,41 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
37 39
38 @Resource 40 @Resource
39 private AddressApi addressApi; 41 private AddressApi addressApi;
  42 +
  43 + @Resource
  44 + private DeliveryPickUpStoreService deliveryPickUpStoreService;
40 @Resource 45 @Resource
41 private DeliveryExpressTemplateService deliveryExpressTemplateService; 46 private DeliveryExpressTemplateService deliveryExpressTemplateService;
42 47
43 @Override 48 @Override
44 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { 49 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
45 - // TODO @芋艿:如果门店自提,需要校验是否开启;  
46 - // 1.1 判断配送方式  
47 - if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { 50 + if (param.getDeliveryType() == null) {
48 return; 51 return;
49 } 52 }
  53 + if (DeliveryTypeEnum.PICK_UP.getType().equals(param.getDeliveryType())) {
  54 + calculateByPickUp(param, result);
  55 + } else if (DeliveryTypeEnum.EXPRESS.getType().equals(param.getDeliveryType())) {
  56 + calculateExpress(param, result);
  57 + }
  58 + }
  59 +
  60 + private void calculateByPickUp(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  61 + if (param.getPickUpStoreId() == null) {
  62 + throw exception(PRICE_CALCULATE_DELIVERY_PRICE_PICK_UP_STORE_IS_EMPTY);
  63 + }
  64 + DeliveryPickUpStoreDO pickUpStore = deliveryPickUpStoreService.getDeliveryPickUpStore(param.getPickUpStoreId());
  65 + if (pickUpStore == null || CommonStatusEnum.DISABLE.getStatus().equals(pickUpStore.getStatus())) {
  66 + throw exception(PICK_UP_STORE_NOT_EXISTS);
  67 + }
  68 + }
  69 +
  70 + // ========= 快递发货 ==========
  71 +
  72 + private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  73 + // 1. 得到收件地址区域
50 if (param.getAddressId() == null) { 74 if (param.getAddressId() == null) {
51 - throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY); 75 + throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
52 } 76 }
53 - // 1.2 得到收件地址区域  
54 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); 77 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
55 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); 78 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
56 79
@@ -89,8 +112,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -89,8 +112,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
89 for (OrderItem orderItem : orderItems) { 112 for (OrderItem orderItem : orderItems) {
90 totalCount += orderItem.getCount(); 113 totalCount += orderItem.getCount();
91 totalPrice += orderItem.getPayPrice(); 114 totalPrice += orderItem.getPayPrice();
92 - totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount();  
93 - totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount(); 115 + if (orderItem.getWeight() != null) {
  116 + totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount();
  117 + }
  118 + if (orderItem.getVolume() != null) {
  119 + totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount();
  120 + }
94 } 121 }
95 // 优先判断是否包邮. 如果包邮不计算快递运费 122 // 优先判断是否包邮. 如果包邮不计算快递运费
96 if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, 123 if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.price.calculator;
  2 +
  3 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  4 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.core.annotation.Order;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +/**
  10 + * 使用积分的 {@link TradePriceCalculator} 实现类
  11 + *
  12 + * @author owen
  13 + */
  14 +@Component
  15 +@Order(TradePriceCalculator.ORDER_POINT_USE)
  16 +@Slf4j
  17 +public class TradePointUsePriceCalculator implements TradePriceCalculator {
  18 +
  19 + @Override
  20 + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  21 + // TODO 疯狂:待实现,嘿嘿;
  22 + if (param.getPointStatus()) {
  23 + result.setUsePoint(10);
  24 + } else {
  25 + result.setUsePoint(0);
  26 + }
  27 + }
  28 +
  29 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
@@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; @@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
6 /** 6 /**
7 * 价格计算的计算器接口 7 * 价格计算的计算器接口
8 * 8 *
  9 + * 优惠计算顺序:
  10 + * 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-53316">积分抵现、会员价、优惠券、粉丝专享价、满减送哪个优先计算?</>
  11 + *
9 * @author 芋道源码 12 * @author 芋道源码
10 */ 13 */
11 public interface TradePriceCalculator { 14 public interface TradePriceCalculator {
@@ -13,12 +16,13 @@ public interface TradePriceCalculator { @@ -13,12 +16,13 @@ public interface TradePriceCalculator {
13 int ORDER_DISCOUNT_ACTIVITY = 10; 16 int ORDER_DISCOUNT_ACTIVITY = 10;
14 int ORDER_REWARD_ACTIVITY = 20; 17 int ORDER_REWARD_ACTIVITY = 20;
15 int ORDER_COUPON = 30; 18 int ORDER_COUPON = 30;
  19 + int ORDER_POINT_USE = 40;
16 /** 20 /**
17 * 快递运费的计算 21 * 快递运费的计算
18 * 22 *
19 * 放在各种营销活动、优惠劵后面 TODO 23 * 放在各种营销活动、优惠劵后面 TODO
20 */ 24 */
21 - int ORDER_DELIVERY = 40; 25 + int ORDER_DELIVERY = 50;
22 26
23 void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); 27 void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result);
24 28
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -4,6 +4,7 @@ import cn.hutool.core.lang.Assert; @@ -4,6 +4,7 @@ import cn.hutool.core.lang.Assert;
4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  7 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
7 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 8 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
8 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 9 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
9 10
@@ -28,7 +29,7 @@ public class TradePriceCalculatorHelper { @@ -28,7 +29,7 @@ public class TradePriceCalculatorHelper {
28 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { 29 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
29 // 创建 PriceCalculateRespDTO 对象 30 // 创建 PriceCalculateRespDTO 对象
30 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); 31 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
31 - result.setType(param.getType()); 32 + result.setType(getOrderType(param));
32 result.setPromotions(new ArrayList<>()); 33 result.setPromotions(new ArrayList<>());
33 34
34 // 创建它的 OrderItem 属性 35 // 创建它的 OrderItem 属性
@@ -70,6 +71,23 @@ public class TradePriceCalculatorHelper { @@ -70,6 +71,23 @@ public class TradePriceCalculatorHelper {
70 } 71 }
71 72
72 /** 73 /**
  74 + * 计算订单类型
  75 + *
  76 + * @param param 计算参数
  77 + * @return 订单类型
  78 + */
  79 + private static Integer getOrderType(TradePriceCalculateReqBO param) {
  80 + if (param.getSeckillActivityId() != null) {
  81 + return TradeOrderTypeEnum.SECKILL.getType();
  82 + }
  83 + if (param.getCombinationActivityId() != null) {
  84 + return TradeOrderTypeEnum.COMBINATION.getType();
  85 + }
  86 + // TODO 砍价敬请期待
  87 + return TradeOrderTypeEnum.NORMAL.getType();
  88 + }
  89 +
  90 + /**
73 * 基于订单项,重新计算 price 总价 91 * 基于订单项,重新计算 price 总价
74 * 92 *
75 * @param result 计算结果 93 * @param result 计算结果
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImplTest.java
@@ -45,7 +45,7 @@ public class TradePriceServiceImplTest extends BaseMockitoUnitTest { @@ -45,7 +45,7 @@ public class TradePriceServiceImplTest extends BaseMockitoUnitTest {
45 public void testCalculatePrice() { 45 public void testCalculatePrice() {
46 // 准备参数 46 // 准备参数
47 TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO() 47 TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO()
48 - .setType(TradeOrderTypeEnum.NORMAL.getType()).setUserId(10L) 48 + .setUserId(10L)
49 .setCouponId(20L).setAddressId(30L) 49 .setCouponId(20L).setAddressId(30L)
50 .setItems(Arrays.asList( 50 .setItems(Arrays.asList(
51 new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true), 51 new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true),
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java
@@ -50,7 +50,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -50,7 +50,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
50 public void init(){ 50 public void init(){
51 // 准备参数 51 // 准备参数
52 reqBO = new TradePriceCalculateReqBO() 52 reqBO = new TradePriceCalculateReqBO()
53 - .setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode()) 53 + .setDeliveryType(DeliveryTypeEnum.EXPRESS.getType())
54 .setAddressId(10L) 54 .setAddressId(10L)
55 .setUserId(1L) 55 .setUserId(1L)
56 .setItems(asList( 56 .setItems(asList(
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/withdraw/BrokerageWithdrawServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.withdraw;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
  7 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw.BrokerageWithdrawMapper;
  8 +import cn.iocoder.yudao.module.trade.service.brokerage.withdraw.BrokerageWithdrawServiceImpl;
  9 +import org.junit.jupiter.api.Disabled;
  10 +import org.junit.jupiter.api.Test;
  11 +import org.springframework.context.annotation.Import;
  12 +
  13 +import javax.annotation.Resource;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  16 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  17 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  18 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  19 +import static org.junit.jupiter.api.Assertions.assertEquals;
  20 +
  21 +// TODO 芋艿:后续 review
  22 +/**
  23 + * {@link BrokerageWithdrawServiceImpl} 的单元测试类
  24 + *
  25 + * @author 芋道源码
  26 + */
  27 +@Import(BrokerageWithdrawServiceImpl.class)
  28 +public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest {
  29 +
  30 + @Resource
  31 + private BrokerageWithdrawServiceImpl brokerageWithdrawService;
  32 +
  33 + @Resource
  34 + private BrokerageWithdrawMapper brokerageWithdrawMapper;
  35 +
  36 + @Test
  37 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  38 + public void testGetBrokerageWithdrawPage() {
  39 + // mock 数据
  40 + BrokerageWithdrawDO dbBrokerageWithdraw = randomPojo(BrokerageWithdrawDO.class, o -> { // 等会查询到
  41 + o.setUserId(null);
  42 + o.setType(null);
  43 + o.setName(null);
  44 + o.setAccountNo(null);
  45 + o.setBankName(null);
  46 + o.setStatus(null);
  47 + o.setCreateTime(null);
  48 + });
  49 + brokerageWithdrawMapper.insert(dbBrokerageWithdraw);
  50 + // 测试 userId 不匹配
  51 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setUserId(null)));
  52 + // 测试 type 不匹配
  53 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setType(null)));
  54 + // 测试 name 不匹配
  55 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setName(null)));
  56 + // 测试 accountNo 不匹配
  57 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAccountNo(null)));
  58 + // 测试 bankName 不匹配
  59 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setBankName(null)));
  60 + // 测试 status 不匹配
  61 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setStatus(null)));
  62 + // 测试 auditReason 不匹配
  63 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditReason(null)));
  64 + // 测试 auditTime 不匹配
  65 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditTime(null)));
  66 + // 测试 remark 不匹配
  67 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setRemark(null)));
  68 + // 测试 createTime 不匹配
  69 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setCreateTime(null)));
  70 + // 准备参数
  71 + BrokerageWithdrawPageReqVO reqVO = new BrokerageWithdrawPageReqVO();
  72 + reqVO.setUserId(null);
  73 + reqVO.setType(null);
  74 + reqVO.setName(null);
  75 + reqVO.setAccountNo(null);
  76 + reqVO.setBankName(null);
  77 + reqVO.setStatus(null);
  78 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  79 +
  80 + // 调用
  81 + PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(reqVO);
  82 + // 断言
  83 + assertEquals(1, pageResult.getTotal());
  84 + assertEquals(1, pageResult.getList().size());
  85 + assertPojoEquals(dbBrokerageWithdraw, pageResult.getList().get(0));
  86 + }
  87 +
  88 +}
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
@@ -4,3 +4,4 @@ DELETE FROM trade_after_sale; @@ -4,3 +4,4 @@ DELETE FROM trade_after_sale;
4 DELETE FROM trade_after_sale_log; 4 DELETE FROM trade_after_sale_log;
5 DELETE FROM trade_brokerage_user; 5 DELETE FROM trade_brokerage_user;
6 DELETE FROM trade_brokerage_record; 6 DELETE FROM trade_brokerage_record;
  7 +DELETE FROM "trade_brokerage_withdraw";
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
@@ -163,4 +163,29 @@ CREATE TABLE IF NOT EXISTS &quot;trade_brokerage_record&quot; @@ -163,4 +163,29 @@ CREATE TABLE IF NOT EXISTS &quot;trade_brokerage_record&quot;
163 "deleted" bit NOT NULL DEFAULT FALSE, 163 "deleted" bit NOT NULL DEFAULT FALSE,
164 "tenant_id" bigint not null default '0', 164 "tenant_id" bigint not null default '0',
165 PRIMARY KEY ("id") 165 PRIMARY KEY ("id")
166 -) COMMENT '佣金记录';  
167 \ No newline at end of file 166 \ No newline at end of file
  167 +) COMMENT '佣金记录';
  168 +CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw"
  169 +(
  170 + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  171 + "user_id" bigint NOT NULL,
  172 + "price" int NOT NULL,
  173 + "fee_price" int NOT NULL,
  174 + "total_price" int NOT NULL,
  175 + "type" varchar NOT NULL,
  176 + "name" varchar,
  177 + "account_no" varchar,
  178 + "bank_name" varchar,
  179 + "bank_address" varchar,
  180 + "account_qr_code_url" varchar,
  181 + "status" varchar NOT NULL,
  182 + "audit_reason" varchar,
  183 + "audit_time" varchar,
  184 + "remark" varchar,
  185 + "creator" varchar DEFAULT '',
  186 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  187 + "updater" varchar DEFAULT '',
  188 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  189 + "deleted" bit NOT NULL DEFAULT FALSE,
  190 + "tenant_id" bigint not null default '0',目
  191 + PRIMARY KEY ("id")
  192 +) COMMENT '佣金提现';
168 \ No newline at end of file 193 \ No newline at end of file
yudao-module-member/yudao-module-member-api/pom.xml
@@ -21,6 +21,13 @@ @@ -21,6 +21,13 @@
21 <groupId>cn.iocoder.boot</groupId> 21 <groupId>cn.iocoder.boot</groupId>
22 <artifactId>yudao-common</artifactId> 22 <artifactId>yudao-common</artifactId>
23 </dependency> 23 </dependency>
  24 +
  25 + <!-- 参数校验 -->
  26 + <dependency>
  27 + <groupId>org.springframework.boot</groupId>
  28 + <artifactId>spring-boot-starter-validation</artifactId>
  29 + <optional>true</optional>
  30 + </dependency>
24 </dependencies> 31 </dependencies>
25 32
26 </project> 33 </project>
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.member.api.point; @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.member.api.point;
2 2
3 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; 3 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
4 4
  5 +import javax.validation.constraints.Min;
  6 +
5 /** 7 /**
6 * 用户积分的 API 接口 8 * 用户积分的 API 接口
7 * 9 *
@@ -17,6 +19,18 @@ public interface MemberPointApi { @@ -17,6 +19,18 @@ public interface MemberPointApi {
17 * @param bizType 业务类型 {@link MemberPointBizTypeEnum} 19 * @param bizType 业务类型 {@link MemberPointBizTypeEnum}
18 * @param bizId 业务编号 20 * @param bizId 业务编号
19 */ 21 */
20 - void addPoint(Long userId, Integer point, Integer bizType, String bizId); 22 + void addPoint(Long userId, @Min(value = 1L, message = "积分必须是正数") Integer point,
  23 + Integer bizType, String bizId);
  24 +
  25 + /**
  26 + * 减少用户积分
  27 + *
  28 + * @param userId 用户编号
  29 + * @param point 积分
  30 + * @param bizType 业务类型 {@link MemberPointBizTypeEnum}
  31 + * @param bizId 业务编号
  32 + */
  33 + void reducePoint(Long userId, @Min(value = 1L, message = "积分必须是正数") Integer point,
  34 + Integer bizType, String bizId);
21 35
22 } 36 }
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
@@ -39,7 +39,7 @@ public interface ErrorCodeConstants { @@ -39,7 +39,7 @@ public interface ErrorCodeConstants {
39 ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1004009001, "签到天数规则已存在"); 39 ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1004009001, "签到天数规则已存在");
40 40
41 //========== 签到配置 1004010000 ========== 41 //========== 签到配置 1004010000 ==========
42 - 42 + ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1004010000,"今日已签到,请勿重复签到");
43 43
44 //========== 用户等级 1004011000 ========== 44 //========== 用户等级 1004011000 ==========
45 ErrorCode LEVEL_NOT_EXISTS = new ErrorCode(1004011000, "用户等级不存在"); 45 ErrorCode LEVEL_NOT_EXISTS = new ErrorCode(1004011000, "用户等级不存在");
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
@@ -17,8 +17,10 @@ import java.util.Objects; @@ -17,8 +17,10 @@ import java.util.Objects;
17 public enum MemberPointBizTypeEnum implements IntArrayValuable { 17 public enum MemberPointBizTypeEnum implements IntArrayValuable {
18 18
19 SIGN(1, "签到", "签到获得 {} 积分", true), 19 SIGN(1, "签到", "签到获得 {} 积分", true),
20 - ORDER_BUY(10, "订单消费", "下单获得 {} 积分", true),  
21 - ORDER_CANCEL(11, "订单取消", "退单获得 {} 积分", false); // 退回积分 20 + ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true),
  21 + ORDER_CANCEL(11, "订单取消", "退单获得 {} 积分", false), // 退回积分
  22 + ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分
  23 + ;
22 24
23 /** 25 /**
24 * 类型 26 * 类型
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java
@@ -31,4 +31,13 @@ public class MemberPointApiImpl implements MemberPointApi { @@ -31,4 +31,13 @@ public class MemberPointApiImpl implements MemberPointApi {
31 memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId); 31 memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId);
32 } 32 }
33 33
  34 + @Override
  35 + public void reducePoint(Long userId, Integer point, Integer bizType, String bizId) {
  36 + MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType);
  37 + if (bizTypeEnum == null) {
  38 + throw exception(POINT_RECORD_BIZ_NOT_SUPPORT);
  39 + }
  40 + memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId);
  41 + }
  42 +
34 } 43 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.signin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  6 +import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService;
  7 +import io.swagger.v3.oas.annotations.Operation;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import org.springframework.web.bind.annotation.GetMapping;
  10 +import org.springframework.web.bind.annotation.PostMapping;
  11 +import org.springframework.web.bind.annotation.RequestMapping;
  12 +import org.springframework.web.bind.annotation.RestController;
  13 +
  14 +import javax.annotation.Resource;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  17 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  18 +
  19 +// TODO @xiaqing:sign-in
  20 +@Tag(name = "签到APP - 签到")
  21 +@RestController
  22 +@RequestMapping("/member/signin")
  23 +public class AppMemberSignInController {
  24 +
  25 + @Resource
  26 + private MemberSignInRecordService signInRecordService;
  27 +
  28 + // TODO @xiaqing:泛型:
  29 + // TODO @xiaqing:合并到 AppMemberSignInRecordController 的 getSignInRecordSummary 里哈。
  30 + @Operation(summary = "个人签到信息")
  31 + @GetMapping("/get-summary")
  32 + public CommonResult getUserSummary(){
  33 + return success(signInRecordService.getSignInRecordSummary(getLoginUserId()));
  34 + }
  35 +
  36 + // TODO @xiaqing:泛型:
  37 + // TODO @xiaqing:合并到 AppMemberSignInRecordController 的 createSignInRecord 里哈。
  38 + @Operation(summary = "会员签到")
  39 + @PostMapping("/create")
  40 + public CommonResult create(){
  41 + MemberSignInRecordDO recordDO = signInRecordService.createSignRecord(getLoginUserId());
  42 + return success(MemberSignInRecordConvert.INSTANCE.coverRecordToAppRecordVo(recordDO));
  43 + }
  44 +
  45 +}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInRecordRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.signin.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "用户签到积分 Response VO")
  9 +@Data
  10 +public class AppMemberSignInRecordRespVO {
  11 +
  12 + @Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Integer day;
  14 +
  15 + @Schema(description = "签到的分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  16 + private Integer point;
  17 +
  18 + @Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED)
  19 + private LocalDateTime createTime;
  20 +
  21 +}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInSummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.signin.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "用户签到统计信息 Response VO")
  9 +@Data
  10 +public class AppMemberSignInSummaryRespVO {
  11 +
  12 + @Schema(description = "持续签到天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
  13 + private Integer continuousDay;
  14 +
  15 + @Schema(description = "总签到天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  16 + private Integer totalDay;
  17 +
  18 + @Schema(description = "当天是否签到", requiredMode = Schema.RequiredMode.REQUIRED,example = "true")
  19 + private Boolean todaySignIn ;
  20 +
  21 +}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java
@@ -36,4 +36,6 @@ public interface MemberSignInRecordConvert { @@ -36,4 +36,6 @@ public interface MemberSignInRecordConvert {
36 36
37 PageResult<AppMemberSignInRecordRespVO> convertPage02(PageResult<MemberSignInRecordDO> pageResult); 37 PageResult<AppMemberSignInRecordRespVO> convertPage02(PageResult<MemberSignInRecordDO> pageResult);
38 38
  39 + AppMemberSignInRecordRespVO coverRecordToAppRecordVo(MemberSignInRecordDO memberSignInRecordDO);
  40 +
39 } 41 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInConfigMapper.java
@@ -18,7 +18,7 @@ public interface MemberSignInConfigMapper extends BaseMapperX&lt;MemberSignInConfig @@ -18,7 +18,7 @@ public interface MemberSignInConfigMapper extends BaseMapperX&lt;MemberSignInConfig
18 return selectOne(MemberSignInConfigDO::getDay, day); 18 return selectOne(MemberSignInConfigDO::getDay, day);
19 } 19 }
20 20
21 - default List<MemberSignInConfigDO> selectListByStatus(Integer status) { 21 + default List <MemberSignInConfigDO> selectListByStatus(Integer status) {
22 return selectList(MemberSignInConfigDO::getStatus, status); 22 return selectList(MemberSignInConfigDO::getStatus, status);
23 } 23 }
24 } 24 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSi @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSi
8 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 8 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
9 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
10 10
  11 +import java.util.List;
11 import java.util.Set; 12 import java.util.Set;
12 13
13 /** 14 /**
@@ -33,4 +34,12 @@ public interface MemberSignInRecordMapper extends BaseMapperX&lt;MemberSignInRecord @@ -33,4 +34,12 @@ public interface MemberSignInRecordMapper extends BaseMapperX&lt;MemberSignInRecord
33 .orderByDesc(MemberSignInRecordDO::getId)); 34 .orderByDesc(MemberSignInRecordDO::getId));
34 } 35 }
35 36
  37 +
  38 + //获取用户的签到记录列表信息,根据签到时间倒序
  39 + default List<MemberSignInRecordDO> selectListByUserId(Long userId){
  40 + return selectList(new LambdaQueryWrapperX <MemberSignInRecordDO>()
  41 + .eq(MemberSignInRecordDO::getUserId, userId)
  42 + .orderByDesc(MemberSignInRecordDO::getCreateTime));
  43 + }
  44 +
36 } 45 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.member.service.signin; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.member.service.signin;
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; 5 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
  6 +import cn.iocoder.yudao.module.member.controller.app.signin.vo.AppMemberSignInSummaryRespVO;
6 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 7 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
7 8
8 /** 9 /**
@@ -29,4 +30,21 @@ public interface MemberSignInRecordService { @@ -29,4 +30,21 @@ public interface MemberSignInRecordService {
29 */ 30 */
30 PageResult<MemberSignInRecordDO> getSignRecordPage(Long userId, PageParam pageParam); 31 PageResult<MemberSignInRecordDO> getSignRecordPage(Long userId, PageParam pageParam);
31 32
  33 + /**
  34 + * 创建签到记录
  35 + *
  36 + * @param userId 用户编号
  37 + * @return 签到记录
  38 + */
  39 + MemberSignInRecordDO createSignRecord(Long userId);
  40 +
  41 + /**
  42 + * 根据用户编号,获得个人签到统计信息
  43 + *
  44 + * @param userId 用户编号
  45 + * @return 个人签到统计信息
  46 + */
  47 + AppMemberSignInSummaryRespVO getSignInRecordSummary(Long userId);
  48 +
  49 +
32 } 50 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java
1 package cn.iocoder.yudao.module.member.service.signin; 1 package cn.iocoder.yudao.module.member.service.signin;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 4 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
6 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
7 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; 9 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
  10 +import cn.iocoder.yudao.module.member.controller.app.signin.vo.AppMemberSignInSummaryRespVO;
  11 +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO;
8 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 12 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  13 +import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInConfigMapper;
9 import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper; 14 import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper;
  15 +import cn.iocoder.yudao.module.member.enums.ErrorCodeConstants;
10 import org.apache.commons.lang3.StringUtils; 16 import org.apache.commons.lang3.StringUtils;
11 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
12 import org.springframework.util.CollectionUtils; 18 import org.springframework.util.CollectionUtils;
13 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
14 20
15 import javax.annotation.Resource; 21 import javax.annotation.Resource;
  22 +import java.time.LocalDate;
  23 +import java.time.temporal.ChronoUnit;
16 import java.util.List; 24 import java.util.List;
17 import java.util.Set; 25 import java.util.Set;
18 26
  27 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 28 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
20 29
21 /** 30 /**
@@ -28,17 +37,66 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -28,17 +37,66 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
28 public class MemberSignInRecordServiceImpl implements MemberSignInRecordService { 37 public class MemberSignInRecordServiceImpl implements MemberSignInRecordService {
29 38
30 @Resource 39 @Resource
31 - private MemberSignInRecordMapper memberSignInRecordMapper; 40 + private MemberSignInRecordMapper signInRecordMapper;
  41 + @Resource
  42 + private MemberSignInConfigMapper signInConfigMapper;
32 43
33 @Resource 44 @Resource
34 private MemberUserApi memberUserApi; 45 private MemberUserApi memberUserApi;
35 46
36 @Override 47 @Override
37 - public PageResult<MemberSignInRecordDO> getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO) {  
38 - // 根据用户昵称查询出用户 ids  
39 - Set<Long> userIds = null; 48 + public AppMemberSignInSummaryRespVO getSignInRecordSummary(Long userId) {
  49 + AppMemberSignInSummaryRespVO vo = new AppMemberSignInSummaryRespVO();
  50 + vo.setTotalDay(0);
  51 + vo.setContinuousDay(0);
  52 + vo.setTodaySignIn(false);
  53 + //获取用户签到的记录,按照天数倒序获取
  54 + List <MemberSignInRecordDO> signInRecordDOList = signInRecordMapper.selectListByUserId(userId);
  55 + // TODO @xiaqing:if 空的时候,直接 return;这样括号少,逻辑更简洁;
  56 + if(!CollectionUtils.isEmpty(signInRecordDOList)){
  57 + //设置总签到天数
  58 + vo.setTotalDay(signInRecordDOList.size()); // TODO @xiaqing:是不是不用读取 signInRecordDOList 所有的,而是 count下,然后另外再读取一条最后一条;
  59 + //判断当天是否有签到复用校验方法
  60 + // TODO @xiaqing:不要用异常实现逻辑;还是判断哈;
  61 + try {
  62 + validSignDay(signInRecordDOList.get(0));
  63 + vo.setTodaySignIn(false);
  64 + }catch (Exception e){
  65 + vo.setTodaySignIn(true);
  66 + }
  67 + //如果当天签到了则说明连续签到天数有意义,否则直接用默认值0
  68 + if(vo.getTodaySignIn()){
  69 + //下方计算连续签到从2天开始,此处直接设置一天连续签到
  70 + vo.setContinuousDay(1);
  71 + //判断连续签到天数
  72 + // TODO @xiaqing:这里逻辑,想想怎么在简化下,可读性可以在提升下哈;
  73 + for (int i = 1; i < signInRecordDOList.size(); i++) {
  74 + //前一天减1等于当前天数则说明连续,继续循环
  75 + LocalDate cur = signInRecordDOList.get(i).getCreateTime().toLocalDate();
  76 + LocalDate pre = signInRecordDOList.get(i-1).getCreateTime().toLocalDate();
  77 + if(1==daysBetween(cur,pre)){
  78 + vo.setContinuousDay(i+1);
  79 + }else{
  80 + break;
  81 + }
  82 + }
  83 + }
  84 +
  85 +
  86 + }
  87 + return vo;
  88 + }
  89 +
  90 + private long daysBetween(LocalDate date1,LocalDate date2){
  91 + return ChronoUnit.DAYS.between(date1, date2);
  92 + }
  93 +
  94 + @Override
  95 + public PageResult <MemberSignInRecordDO> getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO) {
  96 + // 根据用户昵称查询出用户ids
  97 + Set <Long> userIds = null;
40 if (StringUtils.isNotBlank(pageReqVO.getNickname())) { 98 if (StringUtils.isNotBlank(pageReqVO.getNickname())) {
41 - List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname()); 99 + List <MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
42 // 如果查询用户结果为空直接返回无需继续查询 100 // 如果查询用户结果为空直接返回无需继续查询
43 if (CollectionUtils.isEmpty(users)) { 101 if (CollectionUtils.isEmpty(users)) {
44 return PageResult.empty(); 102 return PageResult.empty();
@@ -46,12 +104,72 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService @@ -46,12 +104,72 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
46 userIds = convertSet(users, MemberUserRespDTO::getId); 104 userIds = convertSet(users, MemberUserRespDTO::getId);
47 } 105 }
48 // 分页查询 106 // 分页查询
49 - return memberSignInRecordMapper.selectPage(pageReqVO, userIds); 107 + return signInRecordMapper.selectPage(pageReqVO, userIds);
50 } 108 }
51 109
52 @Override 110 @Override
53 public PageResult<MemberSignInRecordDO> getSignRecordPage(Long userId, PageParam pageParam) { 111 public PageResult<MemberSignInRecordDO> getSignRecordPage(Long userId, PageParam pageParam) {
54 - return memberSignInRecordMapper.selectPage(userId, pageParam); 112 + return signInRecordMapper.selectPage(userId, pageParam);
  113 + }
  114 +
  115 + @Override
  116 + public MemberSignInRecordDO createSignRecord(Long userId) {
  117 + // 获取当前用户签到的最大天数
  118 + // TODO @xiaqing:db 操作,dou封装到 mapper 中;
  119 + // TODO @xiaqing:maxSignDay,是不是变量叫 lastRecord 会更容易理解哈;
  120 + MemberSignInRecordDO maxSignDay = signInRecordMapper.selectOne(new LambdaQueryWrapperX <MemberSignInRecordDO>()
  121 + .eq(MemberSignInRecordDO::getUserId, userId)
  122 + .orderByDesc(MemberSignInRecordDO::getDay)
  123 + .last("limit 1"));
  124 + // 判断是否重复签到
  125 + validSignDay(maxSignDay);
  126 +
  127 + // TODO @xiaqing:可以使用 // 进行注释
  128 + /**1.查询出当前签到的天数**/
  129 + MemberSignInRecordDO sign = new MemberSignInRecordDO().setUserId(userId); // TODO @xiaqing:应该使用 record 变量,会更合适
  130 + sign.setDay(1); // 设置签到初始化天数
  131 + sign.setPoint(0); // 设置签到分数默认为 0
  132 + // 如果不为空则修改当前签到对应的天数
  133 + // TODO @xiaqing:应该是要判断连续哈,就是昨天;
  134 + if (maxSignDay != null) {
  135 + sign.setDay(maxSignDay.getDay() + 1);
  136 + }
  137 + /**2.获取签到对应的分数**/
  138 + // 获取所有的签到规则,按照天数排序,只获取启用的 TODO @xiaqing:不要使用 signInConfigMapper 直接查询,而是要通过 SigninConfigService;
  139 + List <MemberSignInConfigDO> configDOList = signInConfigMapper.selectList(new LambdaQueryWrapperX <MemberSignInConfigDO>()
  140 + .eq(MemberSignInConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
  141 + .orderByAsc(MemberSignInConfigDO::getDay));
  142 + // 如果签到的天数大于最大启用的规则天数,直接给最大签到的分数
  143 + // TODO @xiaqing:超过最大配置的天数,应该直接重置到第一天哈;
  144 + MemberSignInConfigDO lastConfig = configDOList.get(configDOList.size() - 1);
  145 + if (sign.getDay() > lastConfig.getDay()) {
  146 + sign.setPoint(lastConfig.getPoint());
  147 + } else {
  148 + configDOList.forEach(el -> {
  149 + // 循环匹配对应天数,设置对应分数
  150 + // TODO @xiaqing:使用 equals;另外,这种不应该去遍历比较,从可读性来说,应该 CollUtil.findOne()
  151 + if (el.getDay() == sign.getDay()) {
  152 + sign.setPoint(el.getPoint());
  153 + }
  154 +
  155 + });
  156 + }
  157 +
  158 + // 3. 插入当前签到获取的分数
  159 + signInRecordMapper.insert(sign);
  160 + return sign;
  161 + }
  162 +
  163 + // TODO @xiaqing:校验使用 validate 动词哈;可以改成 validateSigned
  164 + private void validSignDay(MemberSignInRecordDO signInRecordDO) {
  165 + // TODO @xiaqing:代码格式:if () {} 要有括号哈
  166 + if (signInRecordDO == null)
  167 + return;
  168 + // TODO @xiaqing:可以直接使用 DateUtils.isToday()
  169 + LocalDate today = LocalDate.now();
  170 + if (today.equals(signInRecordDO.getCreateTime().toLocalDate())) {
  171 + throw exception(ErrorCodeConstants.SIGN_IN_RECORD_TODAY_EXISTS);
  172 + }
55 } 173 }
56 174
57 } 175 }
yudao-server/src/main/resources/application-local.yaml
@@ -56,7 +56,7 @@ spring: @@ -56,7 +56,7 @@ spring:
56 # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W 56 # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
57 slave: # 模拟从库,可根据自己需要修改 57 slave: # 模拟从库,可根据自己需要修改
58 name: ruoyi-vue-pro 58 name: ruoyi-vue-pro
59 - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 59 + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
60 # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 60 # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
61 # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 61 # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
62 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 62 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例