Commit 8b50cd9661113189dff6386276308fe7285d47ef
Merge branch 'feature/mall_product' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
Conflicts: yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
Showing
153 changed files
with
4835 additions
and
645 deletions
pom.xml
| @@ -16,11 +16,11 @@ | @@ -16,11 +16,11 @@ | ||
| 16 | <module>yudao-module-member</module> | 16 | <module>yudao-module-member</module> |
| 17 | <module>yudao-module-system</module> | 17 | <module>yudao-module-system</module> |
| 18 | <module>yudao-module-infra</module> | 18 | <module>yudao-module-infra</module> |
| 19 | -<!-- <module>yudao-module-pay</module>--> | ||
| 20 | -<!-- <module>yudao-module-bpm</module>--> | 19 | + <!-- <module>yudao-module-bpm</module>--> |
| 21 | <!-- <module>yudao-module-report</module>--> | 20 | <!-- <module>yudao-module-report</module>--> |
| 22 | <!-- <module>yudao-module-mp</module>--> | 21 | <!-- <module>yudao-module-mp</module>--> |
| 23 | -<!-- <module>yudao-module-mall</module>--> | 22 | + <module>yudao-module-pay</module> |
| 23 | + <module>yudao-module-mall</module> | ||
| 24 | <!-- 示例项目 --> | 24 | <!-- 示例项目 --> |
| 25 | <module>yudao-example</module> | 25 | <module>yudao-example</module> |
| 26 | </modules> | 26 | </modules> |
sql/mysql/brokerage.sql
0 → 100644
| 1 | +-- 增加配置表 | ||
| 2 | +create table trade_config | ||
| 3 | +( | ||
| 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 '租户编号' | ||
| 21 | +) comment '交易中心配置'; | ||
| 22 | + | ||
| 23 | +-- 增加分销用户扩展表 | ||
| 24 | +create table trade_brokerage_user | ||
| 25 | +( | ||
| 26 | + 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 '分销用户'; | ||
| 40 | + | ||
| 41 | +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 '是否成为推广员'; | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +create table trade_brokerage_record | ||
| 46 | +( | ||
| 47 | + id int auto_increment comment '编号' | ||
| 48 | + 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 '业务类型:0-订单,1-提现', | ||
| 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 | + creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者', | ||
| 60 | + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', | ||
| 61 | + updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者', | ||
| 62 | + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', | ||
| 63 | + deleted bit default b'0' not null comment '是否删除', | ||
| 64 | + tenant_id bigint default 0 not null comment '租户编号' | ||
| 65 | +) | ||
| 66 | + comment '佣金记录'; | ||
| 67 | + | ||
| 68 | +create index idx_user_id on trade_brokerage_record (user_id) comment '用户编号'; | ||
| 69 | +create index idx_biz on trade_brokerage_record (biz_type, biz_id) comment '业务'; | ||
| 70 | +create index idx_status on trade_brokerage_record (status) comment '状态'; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | +create table trade_brokerage_withdraw | ||
| 74 | +( | ||
| 75 | + id int auto_increment comment '编号' | ||
| 76 | + primary key, | ||
| 77 | + user_id bigint not null comment '用户编号', | ||
| 78 | + price int default 0 not null comment '提现金额', | ||
| 79 | + fee_price int default 0 not null comment '提现手续费', | ||
| 80 | + total_price int default 0 not null comment '当前总佣金', | ||
| 81 | + type tinyint default 0 not null comment '提现类型:1-钱包;2-银行卡;3-微信;4-支付宝', | ||
| 82 | + name varchar(64) null comment '真实姓名', | ||
| 83 | + account_no varchar(64) null comment '账号', | ||
| 84 | + bank_name varchar(100) null comment '银行名称', | ||
| 85 | + bank_address varchar(200) null comment '开户地址', | ||
| 86 | + account_qr_code_url varchar(512) null comment '收款码', | ||
| 87 | + status tinyint(2) default 0 not null comment '状态:0-审核中,10-审核通过 20-审核不通过;预留:11 - 提现成功;21-提现失败', | ||
| 88 | + audit_reason varchar(128) null comment '审核驳回原因', | ||
| 89 | + audit_time datetime null comment '审核时间', | ||
| 90 | + remark varchar(500) null comment '备注', | ||
| 91 | + creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者', | ||
| 92 | + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', | ||
| 93 | + updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者', | ||
| 94 | + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', | ||
| 95 | + deleted bit default b'0' not null comment '是否删除', | ||
| 96 | + tenant_id bigint default 0 not null comment '租户编号' | ||
| 97 | +) | ||
| 98 | + comment '佣金提现'; | ||
| 99 | + | ||
| 100 | +create index idx_user_id on trade_brokerage_withdraw (user_id) comment '用户编号'; | ||
| 101 | +create index idx_audit_status on trade_brokerage_withdraw (status) comment '状态'; | ||
| 102 | + | ||
| 103 | +-- 增加字典 | ||
| 104 | +insert into system_dict_type(type, name) | ||
| 105 | +values ('brokerage_enabled_condition', '分佣模式'); | ||
| 106 | +insert into system_dict_data(dict_type, label, value, sort, remark) | ||
| 107 | +values ('brokerage_enabled_condition', '人人分销', 1, 1, '所有用户都可以分销'), | ||
| 108 | + ('brokerage_enabled_condition', '指定分销', 2, 2, '仅可后台手动设置推广员'); | ||
| 109 | + | ||
| 110 | +insert into system_dict_type(type, name) | ||
| 111 | +values ('brokerage_bind_mode', '分销关系绑定模式'); | ||
| 112 | +insert into system_dict_data(dict_type, label, value, sort, remark) | ||
| 113 | +values ('brokerage_bind_mode', '没有推广人', 1, 1, '只要用户没有推广人,随时都可以绑定推广关系'), | ||
| 114 | + ('brokerage_bind_mode', '新用户', 2, 2, '仅新用户注册时才能绑定推广关系'), | ||
| 115 | + ('brokerage_bind_mode', '扫码覆盖', 3, 3, '如果用户已经有推广人,推广人会被变更'); | ||
| 116 | + | ||
| 117 | +insert into system_dict_type(type, name) | ||
| 118 | +values ('brokerage_withdraw_type', '佣金提现类型'); | ||
| 119 | +insert into system_dict_data(dict_type, label, value, sort) | ||
| 120 | +values ('brokerage_withdraw_type', '钱包', 1, 1), | ||
| 121 | + ('brokerage_withdraw_type', '银行卡', 2, 2), | ||
| 122 | + ('brokerage_withdraw_type', '微信', 3, 3), | ||
| 123 | + ('brokerage_withdraw_type', '支付宝', 4, 4); | ||
| 124 | + | ||
| 125 | +insert into system_dict_type(type, name) | ||
| 126 | +values ('brokerage_record_biz_type', '佣金记录业务类型'); | ||
| 127 | +insert into system_dict_data(dict_type, label, value, sort) | ||
| 128 | +values ('brokerage_record_biz_type', '订单返佣', 1, 1), | ||
| 129 | + ('brokerage_record_biz_type', '申请提现', 2, 2); | ||
| 130 | + | ||
| 131 | +insert into system_dict_type(type, name) | ||
| 132 | +values ('brokerage_record_status', '佣金记录状态'); | ||
| 133 | +insert into system_dict_data(dict_type, label, value, sort) | ||
| 134 | +values ('brokerage_record_status', '待结算', 0, 0), | ||
| 135 | + ('brokerage_record_status', '已结算', 1, 1), | ||
| 136 | + ('brokerage_record_status', '已取消', 2, 2); | ||
| 137 | + | ||
| 138 | +insert into system_dict_type(type, name) | ||
| 139 | +values ('brokerage_withdraw_status', '佣金提现状态'); | ||
| 140 | +insert into system_dict_data(dict_type, label, value, sort) | ||
| 141 | +values ('brokerage_withdraw_status', '审核中', 0, 0), | ||
| 142 | + ('brokerage_withdraw_status', '审核通过', 10, 10), | ||
| 143 | + ('brokerage_withdraw_status', '提现成功', 11, 11), | ||
| 144 | + ('brokerage_withdraw_status', '审核不通过', 20, 20), | ||
| 145 | + ('brokerage_withdraw_status', '提现失败', 21, 21); | ||
| 146 | + | ||
| 147 | +insert into system_dict_type(type, name) | ||
| 148 | +values ('brokerage_bank_name', '佣金提现银行'); | ||
| 149 | +insert into system_dict_data(dict_type, label, value, sort) | ||
| 150 | +values ('brokerage_bank_name', '工商银行', 0, 0), | ||
| 151 | + ('brokerage_bank_name', '建设银行', 1, 1), | ||
| 152 | + ('brokerage_bank_name', '农业银行', 2, 2), | ||
| 153 | + ('brokerage_bank_name', '中国银行', 3, 3), | ||
| 154 | + ('brokerage_bank_name', '交通银行', 4, 4), | ||
| 155 | + ('brokerage_bank_name', '招商银行', 5, 5); | ||
| 156 | + | ||
| 157 | + | ||
| 158 | +-- 交易中心配置:菜单 SQL | ||
| 159 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) | ||
| 160 | +VALUES ('交易中心配置', '', 2, 0, 2072, 'config', 'ep:setting', 'trade/config/index', 0, 'TradeConfig'); | ||
| 161 | +-- 按钮父菜单ID | ||
| 162 | +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 | ||
| 163 | +SELECT @parentId := LAST_INSERT_ID(); | ||
| 164 | +-- 按钮 SQL | ||
| 165 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 166 | +VALUES ('交易中心配置查询', 'trade:config:query', 3, 1, @parentId, '', '', '', 0); | ||
| 167 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 168 | +VALUES ('交易中心配置保存', 'trade:config:save', 3, 2, @parentId, '', '', '', 0); | ||
| 169 | + | ||
| 170 | + | ||
| 171 | +-- 增加菜单:分销 | ||
| 172 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) | ||
| 173 | +VALUES ('分销', '', 1, 5, 2072, 'brokerage', 'fa-solid:project-diagram', '', 0, ''); | ||
| 174 | +-- 按钮父菜单ID | ||
| 175 | +SELECT @brokerageMenuId := LAST_INSERT_ID(); | ||
| 176 | + | ||
| 177 | +-- 增加菜单:分销员 | ||
| 178 | +-- 菜单 SQL | ||
| 179 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) | ||
| 180 | +VALUES ('分销用户', '', 2, 0, @brokerageMenuId, 'brokerage-user', 'fa-solid:user-tie', 'trade/brokerage/user/index', 0, | ||
| 181 | + 'TradeBrokerageUser'); | ||
| 182 | +-- 按钮父菜单ID | ||
| 183 | +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 | ||
| 184 | +SELECT @parentId := LAST_INSERT_ID(); | ||
| 185 | +-- 按钮 SQL | ||
| 186 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 187 | +VALUES ('分销用户查询', 'trade:brokerage-user:query', 3, 1, @parentId, '', '', '', 0); | ||
| 188 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 189 | +VALUES ('分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, @parentId, '', '', '', 0); | ||
| 190 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 191 | +VALUES ('分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, @parentId, '', '', '', 0); | ||
| 192 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 193 | +VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0); | ||
| 194 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 195 | +VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-brokerage-user', 3, 5, @parentId, '', '', '', 0); | ||
| 196 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 197 | +VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-brokerage-user', 3, 6, @parentId, '', '', '', 0); | ||
| 198 | + | ||
| 199 | +-- 增加菜单:佣金记录 | ||
| 200 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) | ||
| 201 | +VALUES ('佣金记录', '', 2, 1, @brokerageMenuId, 'brokerage-record', 'fa:money', 'trade/brokerage/record/index', 0, | ||
| 202 | + 'TradeBrokerageRecord'); | ||
| 203 | +-- 按钮父菜单ID | ||
| 204 | +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 | ||
| 205 | +SELECT @parentId := LAST_INSERT_ID(); | ||
| 206 | +-- 按钮 SQL | ||
| 207 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 208 | +VALUES ('佣金记录查询', 'trade:brokerage-record:query', 3, 1, @parentId, '', '', '', 0); | ||
| 209 | + | ||
| 210 | +-- 增加菜单:佣金提现 | ||
| 211 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) | ||
| 212 | +VALUES ('佣金提现', '', 2, 2, @brokerageMenuId, 'brokerage-withdraw', 'fa:credit-card', | ||
| 213 | + 'trade/brokerage/withdraw/index', 0, 'TradeBrokerageWithdraw'); | ||
| 214 | +-- 按钮父菜单ID | ||
| 215 | +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 | ||
| 216 | +SELECT @parentId := LAST_INSERT_ID(); | ||
| 217 | +-- 按钮 SQL | ||
| 218 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 219 | +VALUES ('佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0); | ||
| 220 | +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) | ||
| 221 | +VALUES ('佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0); | ||
| 0 | \ No newline at end of file | 222 | \ No newline at end of file |
sql/mysql/pay_wallet.sql
| 1 | -- ---------------------------- | 1 | -- ---------------------------- |
| 2 | --- 支付-钱包表 | 2 | +-- 会员钱包表 |
| 3 | -- ---------------------------- | 3 | -- ---------------------------- |
| 4 | DROP TABLE IF EXISTS `pay_wallet`; | 4 | DROP TABLE IF EXISTS `pay_wallet`; |
| 5 | CREATE TABLE `pay_wallet` | 5 | CREATE TABLE `pay_wallet` |
| @@ -8,8 +8,8 @@ CREATE TABLE `pay_wallet` | @@ -8,8 +8,8 @@ CREATE TABLE `pay_wallet` | ||
| 8 | `user_id` bigint NOT NULL COMMENT '用户编号', | 8 | `user_id` bigint NOT NULL COMMENT '用户编号', |
| 9 | `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', | 9 | `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', |
| 10 | `balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分', | 10 | `balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分', |
| 11 | - `total_expense` bigint NOT NULL DEFAULT 0 COMMENT '累计支出,单位分', | ||
| 12 | - `total_recharge` bigint NOT NULL DEFAULT 0 COMMENT '累计充值,单位分', | 11 | + `total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分', |
| 12 | + `total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分', | ||
| 13 | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', | 13 | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', |
| 14 | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | 14 | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', |
| 15 | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | 15 | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', |
| @@ -17,28 +17,27 @@ CREATE TABLE `pay_wallet` | @@ -17,28 +17,27 @@ CREATE TABLE `pay_wallet` | ||
| 17 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | 17 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 18 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | 18 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 19 | PRIMARY KEY (`id`) USING BTREE | 19 | PRIMARY KEY (`id`) USING BTREE |
| 20 | -) ENGINE=InnoDB COMMENT='支付钱包表'; | 20 | +) ENGINE=InnoDB COMMENT='会员钱包表'; |
| 21 | 21 | ||
| 22 | -- ---------------------------- | 22 | -- ---------------------------- |
| 23 | --- 支付- 钱包余额明细表 | 23 | +-- 会员钱包流水表 |
| 24 | -- ---------------------------- | 24 | -- ---------------------------- |
| 25 | DROP TABLE IF EXISTS `pay_wallet_transaction`; | 25 | DROP TABLE IF EXISTS `pay_wallet_transaction`; |
| 26 | CREATE TABLE `pay_wallet_transaction` | 26 | CREATE TABLE `pay_wallet_transaction` |
| 27 | ( | 27 | ( |
| 28 | - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', | ||
| 29 | - `wallet_id` bigint NOT NULL COMMENT '会员钱包 id', | ||
| 30 | - `biz_type` tinyint NOT NULL COMMENT '关联类型', | ||
| 31 | - `biz_id` bigint NOT NULL COMMENT '关联业务编号', | ||
| 32 | - `no` varchar(64) NOT NULL COMMENT '流水号', | ||
| 33 | - `description` varchar(255) COMMENT '操作说明', | ||
| 34 | - `amount` int NOT NULL COMMENT '交易金额, 单位分', | ||
| 35 | - `balance` int NOT NULL COMMENT '余额, 单位分', | ||
| 36 | - `transaction_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '交易时间', | ||
| 37 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', | ||
| 38 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | ||
| 39 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | ||
| 40 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | ||
| 41 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | ||
| 42 | - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | 28 | + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', |
| 29 | + `wallet_id` bigint NOT NULL COMMENT '会员钱包 id', | ||
| 30 | + `biz_type` tinyint NOT NULL COMMENT '关联类型', | ||
| 31 | + `biz_id` varchar(64) NOT NULL COMMENT '关联业务编号', | ||
| 32 | + `no` varchar(64) NOT NULL COMMENT '流水号', | ||
| 33 | + `title` varchar(128) NOT NULL COMMENT '流水标题', | ||
| 34 | + `price` int NOT NULL COMMENT '交易金额, 单位分', | ||
| 35 | + `balance` int NOT NULL COMMENT '余额, 单位分', | ||
| 36 | + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', | ||
| 37 | + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | ||
| 38 | + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | ||
| 39 | + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | ||
| 40 | + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | ||
| 41 | + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | ||
| 43 | PRIMARY KEY (`id`) USING BTREE | 42 | PRIMARY KEY (`id`) USING BTREE |
| 44 | -) ENGINE=InnoDB COMMENT='支付钱包余额明细表'; | 43 | +) ENGINE=InnoDB COMMENT='会员钱包流水表'; |
yudao-dependencies/pom.xml
| @@ -27,7 +27,7 @@ | @@ -27,7 +27,7 @@ | ||
| 27 | <mybatis-plus.version>3.5.3.2</mybatis-plus.version> | 27 | <mybatis-plus.version>3.5.3.2</mybatis-plus.version> |
| 28 | <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version> | 28 | <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version> |
| 29 | <dynamic-datasource.version>3.6.1</dynamic-datasource.version> | 29 | <dynamic-datasource.version>3.6.1</dynamic-datasource.version> |
| 30 | - <mybatis-plus-join-boot-starter.version>1.4.5</mybatis-plus-join-boot-starter.version> | 30 | + <mybatis-plus-join.version>1.4.6</mybatis-plus-join.version> |
| 31 | <redisson.version>3.18.0</redisson.version> | 31 | <redisson.version>3.18.0</redisson.version> |
| 32 | <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version> | 32 | <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version> |
| 33 | <!-- 服务保障相关 --> | 33 | <!-- 服务保障相关 --> |
| @@ -220,7 +220,7 @@ | @@ -220,7 +220,7 @@ | ||
| 220 | <dependency> | 220 | <dependency> |
| 221 | <groupId>com.github.yulichang</groupId> | 221 | <groupId>com.github.yulichang</groupId> |
| 222 | <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> | 222 | <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> |
| 223 | - <version>${mybatis-plus-join-boot-starter.version}</version> | 223 | + <version>${mybatis-plus-join.version}</version> |
| 224 | </dependency> | 224 | </dependency> |
| 225 | 225 | ||
| 226 | <dependency> | 226 | <dependency> |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java
| @@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable { | @@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable { | ||
| 41 | * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 | 41 | * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 |
| 42 | * | 42 | * |
| 43 | * @param result 传入的 result 对象 | 43 | * @param result 传入的 result 对象 |
| 44 | - * @param <T> 返回的泛型 | 44 | + * @param <T> 返回的泛型 |
| 45 | * @return 新的 CommonResult 对象 | 45 | * @return 新的 CommonResult 对象 |
| 46 | */ | 46 | */ |
| 47 | public static <T> CommonResult<T> error(CommonResult<?> result) { | 47 | public static <T> CommonResult<T> error(CommonResult<?> result) { |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortingField.java
| 1 | package cn.iocoder.yudao.framework.common.pojo; | 1 | package cn.iocoder.yudao.framework.common.pojo; |
| 2 | 2 | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 3 | import java.io.Serializable; | 7 | import java.io.Serializable; |
| 4 | 8 | ||
| 5 | /** | 9 | /** |
| @@ -7,6 +11,9 @@ import java.io.Serializable; | @@ -7,6 +11,9 @@ import java.io.Serializable; | ||
| 7 | * | 11 | * |
| 8 | * 类名加了 ing 的原因是,避免和 ES SortField 重名。 | 12 | * 类名加了 ing 的原因是,避免和 ES SortField 重名。 |
| 9 | */ | 13 | */ |
| 14 | +@Data | ||
| 15 | +@NoArgsConstructor | ||
| 16 | +@AllArgsConstructor | ||
| 10 | public class SortingField implements Serializable { | 17 | public class SortingField implements Serializable { |
| 11 | 18 | ||
| 12 | /** | 19 | /** |
| @@ -27,30 +34,4 @@ public class SortingField implements Serializable { | @@ -27,30 +34,4 @@ public class SortingField implements Serializable { | ||
| 27 | */ | 34 | */ |
| 28 | private String order; | 35 | private String order; |
| 29 | 36 | ||
| 30 | - // 空构造方法,解决反序列化 | ||
| 31 | - public SortingField() { | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | - public SortingField(String field, String order) { | ||
| 35 | - this.field = field; | ||
| 36 | - this.order = order; | ||
| 37 | - } | ||
| 38 | - | ||
| 39 | - public String getField() { | ||
| 40 | - return field; | ||
| 41 | - } | ||
| 42 | - | ||
| 43 | - public SortingField setField(String field) { | ||
| 44 | - this.field = field; | ||
| 45 | - return this; | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - public String getOrder() { | ||
| 49 | - return order; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - public SortingField setOrder(String order) { | ||
| 53 | - this.order = order; | ||
| 54 | - return this; | ||
| 55 | - } | ||
| 56 | } | 37 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/util/MoneyUtils.java renamed to yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java
| 1 | -package cn.iocoder.yudao.module.pay.util; | 1 | +package cn.iocoder.yudao.framework.common.util.number; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.NumberUtil; | 3 | import cn.hutool.core.util.NumberUtil; |
| 4 | 4 | ||
| @@ -23,6 +23,17 @@ public class MoneyUtils { | @@ -23,6 +23,17 @@ public class MoneyUtils { | ||
| 23 | return calculateRatePrice(price, rate, 0, RoundingMode.HALF_UP).intValue(); | 23 | return calculateRatePrice(price, rate, 0, RoundingMode.HALF_UP).intValue(); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | + /** | ||
| 27 | + * 计算百分比金额,向下传入 | ||
| 28 | + * | ||
| 29 | + * @param price 金额 | ||
| 30 | + * @param rate 百分比,例如说 56.77% 则传入 56.77 | ||
| 31 | + * @return 百分比金额 | ||
| 32 | + */ | ||
| 33 | + public static Integer calculateRatePriceFloor(Integer price, Double rate) { | ||
| 34 | + return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue(); | ||
| 35 | + } | ||
| 36 | + | ||
| 26 | /** | 37 | /** |
| 27 | * 计算百分比金额 | 38 | * 计算百分比金额 |
| 28 | * | 39 | * |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/delegate/DelegatePayClient.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.impl.delegate; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | ||
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | ||
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | ||
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | ||
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; | ||
| 8 | -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||
| 9 | - | ||
| 10 | -import java.util.Map; | ||
| 11 | - | ||
| 12 | -// TODO @jason:其它模块,主要是无法 pay client 初始化存在问题,所以我感觉,是不是可以搞个 PayClientInitializer 接口。这样,PayClientFactory 去 get 这个支付模式对应的 PayClientInitializer,通过它来创建。具体注入的地方,可以在 PayChannel init 方法那; | ||
| 13 | -/** | ||
| 14 | - * 代理支付 Client 的抽象类。 | ||
| 15 | - * | ||
| 16 | - * 用于支付 Client 由其它模块实现,例如钱包支付 | ||
| 17 | - * | ||
| 18 | - * @author jason | ||
| 19 | - */ | ||
| 20 | -public abstract class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> { | ||
| 21 | - | ||
| 22 | - private final DelegatePayClient<Config> delegate; | ||
| 23 | - | ||
| 24 | - public DelegatePayClient(Long channelId, String channelCode, PayClientConfig config) { | ||
| 25 | - super(channelId, channelCode, config); | ||
| 26 | - delegate = this; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - @Override | ||
| 30 | - protected void doInit() { | ||
| 31 | - delegate.doInit(); | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | - @Override | ||
| 35 | - protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | ||
| 36 | - return delegate.doUnifiedOrder(reqDTO); | ||
| 37 | - } | ||
| 38 | - | ||
| 39 | - @Override | ||
| 40 | - protected PayOrderRespDTO doGetOrder(String outTradeNo) { | ||
| 41 | - return delegate.doGetOrder(outTradeNo); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - @Override | ||
| 45 | - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | ||
| 46 | - return delegate.doUnifiedRefund(reqDTO); | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - @Override | ||
| 50 | - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { | ||
| 51 | - return delegate.doGetRefund(outTradeNo, outRefundNo); | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - @Override | ||
| 55 | - protected PayRefundRespDTO doParseRefundNotify(Map<String,String> params, String body) { | ||
| 56 | - return delegate.doParseRefundNotify(params, body); | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - @Override | ||
| 60 | - protected PayOrderRespDTO doParseOrderNotify(Map<String,String> params, String body) { | ||
| 61 | - return delegate.doParseOrderNotify(params, body); | ||
| 62 | - } | ||
| 63 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
| @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDT | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDT | ||
| 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 7 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | 7 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | ||
| 8 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | 9 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 9 | 10 | ||
| 10 | import java.time.LocalDateTime; | 11 | import java.time.LocalDateTime; |
| @@ -17,11 +18,11 @@ import java.util.Map; | @@ -17,11 +18,11 @@ import java.util.Map; | ||
| 17 | * | 18 | * |
| 18 | * @author jason | 19 | * @author jason |
| 19 | */ | 20 | */ |
| 20 | -public class MockPayClient extends AbstractPayClient<MockPayClientConfig> { | 21 | +public class MockPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 21 | 22 | ||
| 22 | private static final String MOCK_RESP_SUCCESS_DATA = "MOCK_SUCCESS"; | 23 | private static final String MOCK_RESP_SUCCESS_DATA = "MOCK_SUCCESS"; |
| 23 | 24 | ||
| 24 | - public MockPayClient(Long channelId, MockPayClientConfig config) { | 25 | + public MockPayClient(Long channelId, NonePayClientConfig config) { |
| 25 | super(channelId, PayChannelEnum.MOCK.getCode(), config); | 26 | super(channelId, PayChannelEnum.MOCK.getCode(), config); |
| 26 | } | 27 | } |
| 27 | 28 |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClientConfig.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.impl.mock; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import javax.validation.Validator; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * 模拟支付的 PayClientConfig 实现类 | ||
| 10 | - * | ||
| 11 | - * @author jason | ||
| 12 | - */ | ||
| 13 | -@Data | ||
| 14 | -public class MockPayClientConfig implements PayClientConfig { | ||
| 15 | - | ||
| 16 | - /** | ||
| 17 | - * 配置名称 | ||
| 18 | - * | ||
| 19 | - * 如果不加任何属性,JsonUtils.parseObject2 解析会报错,所以暂时加个名称 | ||
| 20 | - */ | ||
| 21 | - private String name; | ||
| 22 | - | ||
| 23 | - @Override | ||
| 24 | - public void validate(Validator validator) { | ||
| 25 | - // 模拟支付配置无需校验 | ||
| 26 | - } | ||
| 27 | - | ||
| 28 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java
| @@ -4,7 +4,6 @@ import cn.hutool.core.util.ArrayUtil; | @@ -4,7 +4,6 @@ import cn.hutool.core.util.ArrayUtil; | ||
| 4 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | 4 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; |
| 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; | 6 | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; |
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.impl.mock.MockPayClientConfig; | ||
| 8 | import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; | 7 | import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; |
| 9 | import lombok.AllArgsConstructor; | 8 | import lombok.AllArgsConstructor; |
| 10 | import lombok.Getter; | 9 | import lombok.Getter; |
| @@ -30,7 +29,7 @@ public enum PayChannelEnum { | @@ -30,7 +29,7 @@ public enum PayChannelEnum { | ||
| 30 | ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), | 29 | ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), |
| 31 | ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), | 30 | ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), |
| 32 | 31 | ||
| 33 | - MOCK("mock", "模拟支付", MockPayClientConfig.class), | 32 | + MOCK("mock", "模拟支付", NonePayClientConfig.class), |
| 34 | 33 | ||
| 35 | WALLET("wallet", "钱包支付", NonePayClientConfig.class); | 34 | WALLET("wallet", "钱包支付", NonePayClientConfig.class); |
| 36 | 35 |
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java
| @@ -4,6 +4,7 @@ import cn.hutool.core.util.EnumUtil; | @@ -4,6 +4,7 @@ import cn.hutool.core.util.EnumUtil; | ||
| 4 | import cn.hutool.core.util.ReflectUtil; | 4 | import cn.hutool.core.util.ReflectUtil; |
| 5 | import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource; | 5 | import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource; |
| 6 | import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMiniAppRequest; | 6 | import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMiniAppRequest; |
| 7 | +import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMpRequest; | ||
| 7 | import com.xingyuv.jushauth.cache.AuthStateCache; | 8 | import com.xingyuv.jushauth.cache.AuthStateCache; |
| 8 | import com.xingyuv.jushauth.config.AuthConfig; | 9 | import com.xingyuv.jushauth.config.AuthConfig; |
| 9 | import com.xingyuv.jushauth.config.AuthSource; | 10 | import com.xingyuv.jushauth.config.AuthSource; |
| @@ -13,6 +14,8 @@ import com.xingyuv.justauth.autoconfigure.JustAuthProperties; | @@ -13,6 +14,8 @@ import com.xingyuv.justauth.autoconfigure.JustAuthProperties; | ||
| 13 | 14 | ||
| 14 | import java.lang.reflect.Method; | 15 | import java.lang.reflect.Method; |
| 15 | 16 | ||
| 17 | +import static com.xingyuv.jushauth.config.AuthDefaultSource.WECHAT_MP; | ||
| 18 | + | ||
| 16 | /** | 19 | /** |
| 17 | * 第三方授权拓展 request 工厂类 | 20 | * 第三方授权拓展 request 工厂类 |
| 18 | * 为使得拓展配置 {@link AuthConfig} 和默认配置齐平,所以自定义本工厂类 | 21 | * 为使得拓展配置 {@link AuthConfig} 和默认配置齐平,所以自定义本工厂类 |
| @@ -55,6 +58,12 @@ public class YudaoAuthRequestFactory extends AuthRequestFactory { | @@ -55,6 +58,12 @@ public class YudaoAuthRequestFactory extends AuthRequestFactory { | ||
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | protected AuthRequest getExtendRequest(String source) { | 60 | protected AuthRequest getExtendRequest(String source) { |
| 61 | + // TODO 芋艿:临时兼容 justauth 迁移的类型不对问题; | ||
| 62 | + if (WECHAT_MP.name().equalsIgnoreCase(source)) { | ||
| 63 | + AuthConfig config = properties.getType().get(WECHAT_MP.name()); | ||
| 64 | + return new AuthWeChatMpRequest(config, authStateCache); | ||
| 65 | + } | ||
| 66 | + | ||
| 58 | AuthExtendSource authExtendSource; | 67 | AuthExtendSource authExtendSource; |
| 59 | try { | 68 | try { |
| 60 | authExtendSource = EnumUtil.fromString(AuthExtendSource.class, source.toUpperCase()); | 69 | authExtendSource = EnumUtil.fromString(AuthExtendSource.class, source.toUpperCase()); |
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMpRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.social.core.request; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson.JSONObject; | ||
| 4 | +import com.xingyuv.jushauth.cache.AuthStateCache; | ||
| 5 | +import com.xingyuv.jushauth.config.AuthConfig; | ||
| 6 | +import com.xingyuv.jushauth.config.AuthDefaultSource; | ||
| 7 | +import com.xingyuv.jushauth.enums.AuthResponseStatus; | ||
| 8 | +import com.xingyuv.jushauth.enums.AuthUserGender; | ||
| 9 | +import com.xingyuv.jushauth.enums.scope.AuthWechatMpScope; | ||
| 10 | +import com.xingyuv.jushauth.exception.AuthException; | ||
| 11 | +import com.xingyuv.jushauth.model.AuthCallback; | ||
| 12 | +import com.xingyuv.jushauth.model.AuthResponse; | ||
| 13 | +import com.xingyuv.jushauth.model.AuthToken; | ||
| 14 | +import com.xingyuv.jushauth.model.AuthUser; | ||
| 15 | +import com.xingyuv.jushauth.request.AuthDefaultRequest; | ||
| 16 | +import com.xingyuv.jushauth.utils.AuthScopeUtils; | ||
| 17 | +import com.xingyuv.jushauth.utils.GlobalAuthUtils; | ||
| 18 | +import com.xingyuv.jushauth.utils.HttpUtils; | ||
| 19 | +import com.xingyuv.jushauth.utils.UrlBuilder; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * 微信公众平台登录 | ||
| 23 | + * | ||
| 24 | + * @author yangkai.shen (https://xkcoding.com) | ||
| 25 | + * @since 1.1.0 | ||
| 26 | + */ | ||
| 27 | +public class AuthWeChatMpRequest extends AuthDefaultRequest { | ||
| 28 | + public AuthWeChatMpRequest(AuthConfig config) { | ||
| 29 | + super(config, AuthDefaultSource.WECHAT_MP); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public AuthWeChatMpRequest(AuthConfig config, AuthStateCache authStateCache) { | ||
| 33 | + super(config, AuthDefaultSource.WECHAT_MP, authStateCache); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 微信的特殊性,此时返回的信息同时包含 openid 和 access_token | ||
| 38 | + * | ||
| 39 | + * @param authCallback 回调返回的参数 | ||
| 40 | + * @return 所有信息 | ||
| 41 | + */ | ||
| 42 | + @Override | ||
| 43 | + protected AuthToken getAccessToken(AuthCallback authCallback) { | ||
| 44 | + return this.getToken(accessTokenUrl(authCallback.getCode())); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + protected AuthUser getUserInfo(AuthToken authToken) { | ||
| 49 | + String openId = authToken.getOpenId(); | ||
| 50 | + | ||
| 51 | + String response = doGetUserInfo(authToken); | ||
| 52 | + JSONObject object = JSONObject.parseObject(response); | ||
| 53 | + | ||
| 54 | + this.checkResponse(object); | ||
| 55 | + | ||
| 56 | + String location = String.format("%s-%s-%s", object.getString("country"), object.getString("province"), object.getString("city")); | ||
| 57 | + | ||
| 58 | + if (object.containsKey("unionid")) { | ||
| 59 | + authToken.setUnionId(object.getString("unionid")); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + return AuthUser.builder() | ||
| 63 | + .rawUserInfo(object) | ||
| 64 | + .username(object.getString("nickname")) | ||
| 65 | + .nickname(object.getString("nickname")) | ||
| 66 | + .avatar(object.getString("headimgurl")) | ||
| 67 | + .location(location) | ||
| 68 | + .uuid(openId) | ||
| 69 | + .gender(AuthUserGender.getWechatRealGender(object.getString("sex"))) | ||
| 70 | + .token(authToken) | ||
| 71 | + .source(source.toString()) | ||
| 72 | + .build(); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public AuthResponse refresh(AuthToken oldToken) { | ||
| 77 | + return AuthResponse.builder() | ||
| 78 | + .code(AuthResponseStatus.SUCCESS.getCode()) | ||
| 79 | + .data(this.getToken(refreshTokenUrl(oldToken.getRefreshToken()))) | ||
| 80 | + .build(); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * 检查响应内容是否正确 | ||
| 85 | + * | ||
| 86 | + * @param object 请求响应内容 | ||
| 87 | + */ | ||
| 88 | + private void checkResponse(JSONObject object) { | ||
| 89 | + if (object.containsKey("errcode")) { | ||
| 90 | + throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg")); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * 获取token,适用于获取access_token和刷新token | ||
| 96 | + * | ||
| 97 | + * @param accessTokenUrl 实际请求token的地址 | ||
| 98 | + * @return token对象 | ||
| 99 | + */ | ||
| 100 | + private AuthToken getToken(String accessTokenUrl) { | ||
| 101 | + String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl).getBody(); | ||
| 102 | + JSONObject accessTokenObject = JSONObject.parseObject(response); | ||
| 103 | + | ||
| 104 | + this.checkResponse(accessTokenObject); | ||
| 105 | + | ||
| 106 | + return AuthToken.builder() | ||
| 107 | + .accessToken(accessTokenObject.getString("access_token")) | ||
| 108 | + .refreshToken(accessTokenObject.getString("refresh_token")) | ||
| 109 | + .expireIn(accessTokenObject.getIntValue("expires_in")) | ||
| 110 | + .openId(accessTokenObject.getString("openid")) | ||
| 111 | + .scope(accessTokenObject.getString("scope")) | ||
| 112 | + .build(); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state} | ||
| 117 | + * | ||
| 118 | + * @param state state 验证授权流程的参数,可以防止csrf | ||
| 119 | + * @return 返回授权地址 | ||
| 120 | + * @since 1.9.3 | ||
| 121 | + */ | ||
| 122 | + @Override | ||
| 123 | + public String authorize(String state) { | ||
| 124 | + return UrlBuilder.fromBaseUrl(source.authorize()) | ||
| 125 | + .queryParam("appid", config.getClientId()) | ||
| 126 | + .queryParam("redirect_uri", GlobalAuthUtils.urlEncode(config.getRedirectUri())) | ||
| 127 | + .queryParam("response_type", "code") | ||
| 128 | + .queryParam("scope", this.getScopes(",", false, AuthScopeUtils.getDefaultScopes(AuthWechatMpScope.values()))) | ||
| 129 | + .queryParam("state", getRealState(state).concat("#wechat_redirect")) | ||
| 130 | + .build(); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + /** | ||
| 134 | + * 返回获取accessToken的url | ||
| 135 | + * | ||
| 136 | + * @param code 授权码 | ||
| 137 | + * @return 返回获取accessToken的url | ||
| 138 | + */ | ||
| 139 | + @Override | ||
| 140 | + protected String accessTokenUrl(String code) { | ||
| 141 | + return UrlBuilder.fromBaseUrl(source.accessToken()) | ||
| 142 | + .queryParam("appid", config.getClientId()) | ||
| 143 | + .queryParam("secret", config.getClientSecret()) | ||
| 144 | + .queryParam("code", code) | ||
| 145 | + .queryParam("grant_type", "authorization_code") | ||
| 146 | + .build(); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * 返回获取userInfo的url | ||
| 151 | + * | ||
| 152 | + * @param authToken 用户授权后的token | ||
| 153 | + * @return 返回获取userInfo的url | ||
| 154 | + */ | ||
| 155 | + @Override | ||
| 156 | + protected String userInfoUrl(AuthToken authToken) { | ||
| 157 | + return UrlBuilder.fromBaseUrl(source.userInfo()) | ||
| 158 | + .queryParam("access_token", authToken.getAccessToken()) | ||
| 159 | + .queryParam("openid", authToken.getOpenId()) | ||
| 160 | + .queryParam("lang", "zh_CN") | ||
| 161 | + .build(); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + /** | ||
| 165 | + * 返回获取userInfo的url | ||
| 166 | + * | ||
| 167 | + * @param refreshToken getAccessToken方法返回的refreshToken | ||
| 168 | + * @return 返回获取userInfo的url | ||
| 169 | + */ | ||
| 170 | + @Override | ||
| 171 | + protected String refreshTokenUrl(String refreshToken) { | ||
| 172 | + return UrlBuilder.fromBaseUrl(source.refresh()) | ||
| 173 | + .queryParam("appid", config.getClientId()) | ||
| 174 | + .queryParam("grant_type", "refresh_token") | ||
| 175 | + .queryParam("refresh_token", refreshToken) | ||
| 176 | + .build(); | ||
| 177 | + } | ||
| 178 | +} |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| @@ -18,6 +18,9 @@ import java.util.List; | @@ -18,6 +18,9 @@ import java.util.List; | ||
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 | 20 | * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 |
| 21 | + * | ||
| 22 | + * 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力 | ||
| 23 | + * 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力 | ||
| 21 | */ | 24 | */ |
| 22 | public interface BaseMapperX<T> extends MPJBaseMapper<T> { | 25 | public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 23 | 26 |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
| @@ -60,4 +60,14 @@ public class ProductSkuRespDTO { | @@ -60,4 +60,14 @@ public class ProductSkuRespDTO { | ||
| 60 | */ | 60 | */ |
| 61 | private Double volume; | 61 | private Double volume; |
| 62 | 62 | ||
| 63 | + // TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致; | ||
| 64 | + /** | ||
| 65 | + * 一级分销的佣金,单位:分 | ||
| 66 | + */ | ||
| 67 | + private Integer subCommissionFirstPrice; | ||
| 68 | + /** | ||
| 69 | + * 二级分销的佣金,单位:分 | ||
| 70 | + */ | ||
| 71 | + private Integer subCommissionSecondPrice; | ||
| 72 | + | ||
| 63 | } | 73 | } |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.bargain; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 砍价活动 Api 接口 | ||
| 5 | + * | ||
| 6 | + * @author HUIHUI | ||
| 7 | + */ | ||
| 8 | +public interface BargainActivityApi { | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 更新砍价活动库存 | ||
| 12 | + * | ||
| 13 | + * @param activityId 砍价活动编号 | ||
| 14 | + * @param count 购买数量 | ||
| 15 | + */ | ||
| 16 | + void updateBargainActivityStock(Long activityId, Integer count); | ||
| 17 | + | ||
| 18 | +} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainRecordCreateReqDTO.java
| @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto; | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto; | ||
| 2 | 2 | ||
| 3 | import lombok.Data; | 3 | import lombok.Data; |
| 4 | 4 | ||
| 5 | -import javax.validation.constraints.NotEmpty; | ||
| 6 | import javax.validation.constraints.NotNull; | 5 | import javax.validation.constraints.NotNull; |
| 7 | 6 | ||
| 8 | // TODO @芋艿:这块要在看看 | 7 | // TODO @芋艿:这块要在看看 |
| @@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO { | @@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO { | ||
| 40 | */ | 39 | */ |
| 41 | @NotNull(message = "订单编号不能为空") | 40 | @NotNull(message = "订单编号不能为空") |
| 42 | private Long orderId; | 41 | private Long orderId; |
| 43 | - // TODO @puhui999:spuName、picUrl、 之类字段不用传递; | ||
| 44 | - /** | ||
| 45 | - * 商品名字 | ||
| 46 | - */ | ||
| 47 | - @NotEmpty(message = "商品名字不能为空") | ||
| 48 | - private String spuName; | ||
| 49 | - /** | ||
| 50 | - * 商品图片 | ||
| 51 | - */ | ||
| 52 | - @NotEmpty(message = "商品图片不能为空") | ||
| 53 | - private String picUrl; | 42 | + |
| 54 | /** | 43 | /** |
| 55 | * 砍价商品单价 | 44 | * 砍价商品单价 |
| 56 | */ | 45 | */ |
| @@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO { | @@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO { | ||
| 61 | */ | 50 | */ |
| 62 | @NotNull(message = "商品原价不能为空") | 51 | @NotNull(message = "商品原价不能为空") |
| 63 | private Integer price; | 52 | private Integer price; |
| 64 | - // TODO @puhui999:nickname、avatar 不用传递,去查询; | ||
| 65 | - /** | ||
| 66 | - * 用户昵称 | ||
| 67 | - */ | ||
| 68 | - @NotEmpty(message = "用户昵称不能为空") | ||
| 69 | - private String nickname; | ||
| 70 | - /** | ||
| 71 | - * 用户头像 | ||
| 72 | - */ | ||
| 73 | - @NotEmpty(message = "用户头像不能为空") | ||
| 74 | - private String avatar; | 53 | + |
| 75 | /** | 54 | /** |
| 76 | * 开团状态:进行中 砍价成功 砍价失败 | 55 | * 开团状态:进行中 砍价成功 砍价失败 |
| 77 | */ | 56 | */ |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
| @@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.promotion.api.combination; | @@ -2,9 +2,9 @@ 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; | 4 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 5 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | ||
| 6 | 5 | ||
| 7 | import javax.validation.Valid; | 6 | import javax.validation.Valid; |
| 7 | +import java.time.LocalDateTime; | ||
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | 9 | ||
| 10 | // TODO @芋艿:后面也再撸撸这几个接口 | 10 | // TODO @芋艿:后面也再撸撸这几个接口 |
| @@ -51,13 +51,29 @@ public interface CombinationRecordApi { | @@ -51,13 +51,29 @@ public interface CombinationRecordApi { | ||
| 51 | */ | 51 | */ |
| 52 | void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount); | 52 | void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount); |
| 53 | 53 | ||
| 54 | - // TODO @puhui999:是不是搞成具体的方法,拼团成功,拼团失败,这种方法; | 54 | + /** |
| 55 | + * 更新拼团状态为成功 | ||
| 56 | + * | ||
| 57 | + * @param userId 用户编号 | ||
| 58 | + * @param orderId 订单编号 | ||
| 59 | + */ | ||
| 60 | + void updateRecordStatusToSuccess(Long userId, Long orderId); | ||
| 55 | 61 | ||
| 56 | /** | 62 | /** |
| 57 | - * 更新开团记录状态 | 63 | + * 更新拼团状态为失败 |
| 58 | * | 64 | * |
| 59 | - * @param reqDTO 请求 DTO | 65 | + * @param userId 用户编号 |
| 66 | + * @param orderId 订单编号 | ||
| 67 | + */ | ||
| 68 | + void updateRecordStatusToFailed(Long userId, Long orderId); | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 更新拼团状态为 进行中 | ||
| 72 | + * | ||
| 73 | + * @param userId 用户编号 | ||
| 74 | + * @param orderId 订单编号 | ||
| 75 | + * @param startTime 开始时间 | ||
| 60 | */ | 76 | */ |
| 61 | - void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO); | 77 | + void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime); |
| 62 | 78 | ||
| 63 | } | 79 | } |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordUpdateStatusReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.promotion.api.combination.dto; | ||
| 2 | - | ||
| 3 | -import lombok.Data; | ||
| 4 | - | ||
| 5 | -import javax.validation.constraints.NotNull; | ||
| 6 | -import java.time.LocalDateTime; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * 拼团记录的更新状态 Request DTO | ||
| 10 | - * | ||
| 11 | - * @author HUIHUI | ||
| 12 | - */ | ||
| 13 | -@Data | ||
| 14 | -public class CombinationRecordUpdateStatusReqDTO { | ||
| 15 | - | ||
| 16 | - /** | ||
| 17 | - * 用户编号 | ||
| 18 | - */ | ||
| 19 | - @NotNull(message = "用户编号不能为空") | ||
| 20 | - private Long userId; | ||
| 21 | - | ||
| 22 | - /** | ||
| 23 | - * 订单编号 | ||
| 24 | - */ | ||
| 25 | - @NotNull(message = "订单编号不能为空") | ||
| 26 | - private Long orderId; | ||
| 27 | - | ||
| 28 | - /** | ||
| 29 | - * 开团状态:正在开团 拼团成功 拼团失败 | ||
| 30 | - */ | ||
| 31 | - @NotNull(message = "开团状态不能为空") | ||
| 32 | - private Integer status; | ||
| 33 | - | ||
| 34 | - /** | ||
| 35 | - * 团开始时间 | ||
| 36 | - */ | ||
| 37 | - private LocalDateTime startTime; | ||
| 38 | - | ||
| 39 | -} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 秒杀活动 API 接口 | ||
| 7 | + * | ||
| 8 | + * @author HUIHUI | ||
| 9 | + */ | ||
| 10 | +public interface SeckillActivityApi { | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * 更新秒杀库存 | ||
| 14 | + * | ||
| 15 | + * @param updateStockReqDTO 请求 | ||
| 16 | + */ | ||
| 17 | + void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); | ||
| 18 | + | ||
| 19 | +} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 更新秒杀库存 request DTO | ||
| 9 | + * | ||
| 10 | + * @author HUIHUI | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +public class SeckillActivityUpdateStockReqDTO { | ||
| 14 | + | ||
| 15 | + // TODO @puhui999:参数校验 | ||
| 16 | + | ||
| 17 | + // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 活动编号 | ||
| 21 | + */ | ||
| 22 | + private Long activityId; | ||
| 23 | + /** | ||
| 24 | + * 总购买数量 | ||
| 25 | + */ | ||
| 26 | + private Integer count; | ||
| 27 | + /** | ||
| 28 | + * 活动商品 | ||
| 29 | + */ | ||
| 30 | + private List<Item> items; | ||
| 31 | + | ||
| 32 | + @Data | ||
| 33 | + public static class Item { | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * SPU 编号 | ||
| 37 | + */ | ||
| 38 | + private Long spuId; | ||
| 39 | + /** | ||
| 40 | + * SKU 编号 | ||
| 41 | + */ | ||
| 42 | + private Long skuId; | ||
| 43 | + /** | ||
| 44 | + * 购买数量 | ||
| 45 | + */ | ||
| 46 | + private Integer count; | ||
| 47 | + | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | +} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| @@ -55,6 +55,7 @@ public interface ErrorCodeConstants { | @@ -55,6 +55,7 @@ public interface ErrorCodeConstants { | ||
| 55 | ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_003, "秒杀活动已关闭,不能修改"); | 55 | ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_003, "秒杀活动已关闭,不能修改"); |
| 56 | ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除"); | 56 | ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除"); |
| 57 | ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭"); | 57 | ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭"); |
| 58 | + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足"); | ||
| 58 | 59 | ||
| 59 | // ========== 秒杀时段 1-013-009-000 ========== | 60 | // ========== 秒杀时段 1-013-009-000 ========== |
| 60 | ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1_013_009_000, "秒杀时段不存在"); | 61 | ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1_013_009_000, "秒杀时段不存在"); |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.bargain; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | + | ||
| 8 | +import javax.annotation.Resource; | ||
| 9 | + | ||
| 10 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 11 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 砍价活动 Api 接口实现类 | ||
| 15 | + * | ||
| 16 | + * @author HUIHUI | ||
| 17 | + */ | ||
| 18 | +@Service | ||
| 19 | +public class BargainActivityApiImpl implements BargainActivityApi { | ||
| 20 | + | ||
| 21 | + @Resource | ||
| 22 | + private BargainActivityService bargainActivityService; | ||
| 23 | + | ||
| 24 | + @Override | ||
| 25 | + public void updateBargainActivityStock(Long activityId, Integer count) { | ||
| 26 | + // TODO @puhui999:可以整个实现到 bargainActivityService 中 | ||
| 27 | + // 查询砍价活动 | ||
| 28 | + BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId); | ||
| 29 | + if (activity == null) { | ||
| 30 | + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + // 更新砍价库存 | ||
| 34 | + // TODO @puhui999:考虑下并发更新问题 | ||
| 35 | + BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO(); | ||
| 36 | + reqVO.setId(activityId); | ||
| 37 | + reqVO.setStock(activity.getStock() - count); | ||
| 38 | + bargainActivityService.updateBargainActivity(reqVO); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
| @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.promotion.api.combination; | @@ -2,13 +2,13 @@ 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; | 4 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 5 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | ||
| 6 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; | 5 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; |
| 7 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; | 6 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; |
| 8 | import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; | 7 | import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; |
| 9 | import org.springframework.stereotype.Service; | 8 | import org.springframework.stereotype.Service; |
| 10 | 9 | ||
| 11 | import javax.annotation.Resource; | 10 | import javax.annotation.Resource; |
| 11 | +import java.time.LocalDateTime; | ||
| 12 | import java.util.List; | 12 | import java.util.List; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| @@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { | @@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { | ||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | @Override | 45 | @Override |
| 46 | - public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) { | ||
| 47 | - if (null == reqDTO.getStartTime()) { | ||
| 48 | - recordService.updateCombinationRecordStatusByUserIdAndOrderId(reqDTO); | ||
| 49 | - } else { | ||
| 50 | - recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(reqDTO); | ||
| 51 | - } | 46 | + public void updateRecordStatusToSuccess(Long userId, Long orderId) { |
| 47 | + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Override | ||
| 51 | + public void updateRecordStatusToFailed(Long userId, Long orderId) { | ||
| 52 | + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @Override | ||
| 56 | + public void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime) { | ||
| 57 | + recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), | ||
| 58 | + userId, orderId, startTime); | ||
| 52 | } | 59 | } |
| 53 | 60 | ||
| 54 | } | 61 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; | ||
| 6 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; | ||
| 7 | +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | + | ||
| 10 | +import javax.annotation.Resource; | ||
| 11 | +import java.util.ArrayList; | ||
| 12 | +import java.util.HashMap; | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 17 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 秒杀活动接口 Api 接口实现类 | ||
| 21 | + * | ||
| 22 | + * @author HUIHUI | ||
| 23 | + */ | ||
| 24 | +@Service | ||
| 25 | +public class SeckillActivityApiImpl implements SeckillActivityApi { | ||
| 26 | + | ||
| 27 | + @Resource | ||
| 28 | + private SeckillActivityService activityService; | ||
| 29 | + | ||
| 30 | + // TODO @puhui:建议这块弄到 activityService 实现哈; | ||
| 31 | + // TODO @puhui:这个方法,要考虑事务性 | ||
| 32 | + @Override | ||
| 33 | + public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { | ||
| 34 | + // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈; | ||
| 35 | + SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId()); | ||
| 36 | + if (seckillActivity.getStock() < updateStockReqDTO.getCount()) { | ||
| 37 | + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); | ||
| 38 | + } | ||
| 39 | + // 获取活动商品 | ||
| 40 | + // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈; | ||
| 41 | + List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId()); | ||
| 42 | + // TODO @puhui999:这个是不是搞成 CollectionUtils.convertMultiMap() | ||
| 43 | + List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems(); | ||
| 44 | + Map<Long, List<Long>> map = new HashMap<>(); | ||
| 45 | + items.forEach(item -> { | ||
| 46 | + if (map.containsKey(item.getSpuId())) { | ||
| 47 | + List<Long> skuIds = map.get(item.getSpuId()); | ||
| 48 | + skuIds.add(item.getSkuId()); | ||
| 49 | + map.put(item.getSpuId(), skuIds); | ||
| 50 | + } else { | ||
| 51 | + List<Long> list = new ArrayList<>(); | ||
| 52 | + list.add(item.getSkuId()); | ||
| 53 | + map.put(item.getSpuId(), list); | ||
| 54 | + } | ||
| 55 | + }); | ||
| 56 | + // 过滤出购买的商品 | ||
| 57 | + // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里; | ||
| 58 | + List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId())); | ||
| 59 | + Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p); | ||
| 60 | + // 检查活动商品库存是否充足 | ||
| 61 | + // TODO @puhui999:避免 b 这种无业务含义的变量; | ||
| 62 | + boolean b = CollectionUtils.anyMatch(productDOList, item -> { | ||
| 63 | + SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId()); | ||
| 64 | + return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0; | ||
| 65 | + }); | ||
| 66 | + if (b) { | ||
| 67 | + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); | ||
| 68 | + } | ||
| 69 | + // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起; | ||
| 70 | + List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> { | ||
| 71 | + item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount()); | ||
| 72 | + return item; | ||
| 73 | + }); | ||
| 74 | + | ||
| 75 | + // 更新活动库存 | ||
| 76 | + // TODO @puhui999:考虑下并发更新 | ||
| 77 | + seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount()); | ||
| 78 | + seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount()); | ||
| 79 | + activityService.updateSeckillActivity(seckillActivity); | ||
| 80 | + // 更新活动商品库存 | ||
| 81 | + activityService.updateSeckillActivityProductList(doList); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | +} |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java
| 1 | package cn.iocoder.yudao.module.promotion.controller.app.combination; | 1 | package cn.iocoder.yudao.module.promotion.controller.app.combination; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.framework.common.util.date.DateUtils; | 4 | +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 5 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO; | 5 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO; |
| 6 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO; | 6 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO; |
| 7 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO; | 7 | import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO; |
| @@ -16,8 +16,8 @@ import org.springframework.web.bind.annotation.RestController; | @@ -16,8 +16,8 @@ import org.springframework.web.bind.annotation.RestController; | ||
| 16 | 16 | ||
| 17 | import javax.validation.constraints.Max; | 17 | import javax.validation.constraints.Max; |
| 18 | import java.time.Duration; | 18 | import java.time.Duration; |
| 19 | +import java.time.LocalDateTime; | ||
| 19 | import java.util.ArrayList; | 20 | import java.util.ArrayList; |
| 20 | -import java.util.Date; | ||
| 21 | import java.util.List; | 21 | import java.util.List; |
| 22 | 22 | ||
| 23 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 23 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| @@ -52,14 +52,13 @@ public class AppCombinationRecordController { | @@ -52,14 +52,13 @@ public class AppCombinationRecordController { | ||
| 52 | @RequestParam(value = "activityId", required = false) Long activityId, | 52 | @RequestParam(value = "activityId", required = false) Long activityId, |
| 53 | @RequestParam("status") Integer status, | 53 | @RequestParam("status") Integer status, |
| 54 | @RequestParam(value = "count", defaultValue = "20") @Max(20) Integer count) { | 54 | @RequestParam(value = "count", defaultValue = "20") @Max(20) Integer count) { |
| 55 | - ZoneId zoneId = ZoneId.systemDefault(); | ||
| 56 | List<AppCombinationRecordRespVO> list = new ArrayList<>(); | 55 | List<AppCombinationRecordRespVO> list = new ArrayList<>(); |
| 57 | for (int i = 1; i <= count; i++) { | 56 | for (int i = 1; i <= count; i++) { |
| 58 | AppCombinationRecordRespVO record = new AppCombinationRecordRespVO(); | 57 | AppCombinationRecordRespVO record = new AppCombinationRecordRespVO(); |
| 59 | record.setId((long) i); | 58 | record.setId((long) i); |
| 60 | record.setNickname("用户" + i); | 59 | record.setNickname("用户" + i); |
| 61 | record.setAvatar("头像" + i); | 60 | record.setAvatar("头像" + i); |
| 62 | - record.setExpireTime(LocalDateTime.ofInstant(new Date().toInstant(), zoneId)); | 61 | + record.setExpireTime(LocalDateTime.now()); |
| 63 | record.setUserSize(10); | 62 | record.setUserSize(10); |
| 64 | record.setUserCount(i); | 63 | record.setUserCount(i); |
| 65 | record.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); | 64 | record.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); |
| @@ -74,14 +73,13 @@ public class AppCombinationRecordController { | @@ -74,14 +73,13 @@ public class AppCombinationRecordController { | ||
| 74 | @Operation(summary = "获得拼团记录明细") | 73 | @Operation(summary = "获得拼团记录明细") |
| 75 | @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024") | 74 | @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024") |
| 76 | public CommonResult<AppCombinationRecordDetailRespVO> getCombinationRecordDetail(@RequestParam("id") Long id) { | 75 | public CommonResult<AppCombinationRecordDetailRespVO> getCombinationRecordDetail(@RequestParam("id") Long id) { |
| 77 | - ZoneId zoneId = ZoneId.systemDefault(); | ||
| 78 | AppCombinationRecordDetailRespVO detail = new AppCombinationRecordDetailRespVO(); | 76 | AppCombinationRecordDetailRespVO detail = new AppCombinationRecordDetailRespVO(); |
| 79 | // 团长 | 77 | // 团长 |
| 80 | AppCombinationRecordRespVO headRecord = new AppCombinationRecordRespVO(); | 78 | AppCombinationRecordRespVO headRecord = new AppCombinationRecordRespVO(); |
| 81 | headRecord.setId(1L); | 79 | headRecord.setId(1L); |
| 82 | headRecord.setNickname("用户" + 1); | 80 | headRecord.setNickname("用户" + 1); |
| 83 | headRecord.setAvatar("头像" + 1); | 81 | headRecord.setAvatar("头像" + 1); |
| 84 | - headRecord.setExpireTime((LocalDateTime.ofInstant(DateUtils.addTime(Duration.ofDays(1)).toInstant(), zoneId))); | 82 | + headRecord.setExpireTime(LocalDateTimeUtils.addTime(Duration.ofDays(1))); |
| 85 | headRecord.setUserSize(10); | 83 | headRecord.setUserSize(10); |
| 86 | headRecord.setUserCount(3); | 84 | headRecord.setUserCount(3); |
| 87 | headRecord.setStatus(1); | 85 | headRecord.setStatus(1); |
| @@ -96,7 +94,7 @@ public class AppCombinationRecordController { | @@ -96,7 +94,7 @@ public class AppCombinationRecordController { | ||
| 96 | record.setId((long) i); | 94 | record.setId((long) i); |
| 97 | record.setNickname("用户" + i); | 95 | record.setNickname("用户" + i); |
| 98 | record.setAvatar("头像" + i); | 96 | record.setAvatar("头像" + i); |
| 99 | - record.setExpireTime(LocalDateTime.ofInstant(new Date().toInstant(), zoneId)); | 97 | + record.setExpireTime(LocalDateTime.now()); |
| 100 | record.setUserSize(10); | 98 | record.setUserSize(10); |
| 101 | record.setUserCount(i); | 99 | record.setUserCount(i); |
| 102 | record.setStatus(1); | 100 | record.setStatus(1); |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
| @@ -9,6 +9,7 @@ import lombok.*; | @@ -9,6 +9,7 @@ import lombok.*; | ||
| 9 | 9 | ||
| 10 | import java.time.LocalDateTime; | 10 | import java.time.LocalDateTime; |
| 11 | 11 | ||
| 12 | +// TODO 芋艿:把字段的顺序,和 do 顺序对齐下 | ||
| 12 | /** | 13 | /** |
| 13 | * 拼团记录 DO | 14 | * 拼团记录 DO |
| 14 | * | 15 | * |
| @@ -27,34 +28,28 @@ import java.time.LocalDateTime; | @@ -27,34 +28,28 @@ import java.time.LocalDateTime; | ||
| 27 | @AllArgsConstructor | 28 | @AllArgsConstructor |
| 28 | public class CombinationRecordDO extends BaseDO { | 29 | public class CombinationRecordDO extends BaseDO { |
| 29 | 30 | ||
| 31 | + /** | ||
| 32 | + * 编号,主键自增 | ||
| 33 | + */ | ||
| 30 | @TableId | 34 | @TableId |
| 31 | private Long id; | 35 | private Long id; |
| 36 | + | ||
| 32 | /** | 37 | /** |
| 33 | * 拼团活动编号 | 38 | * 拼团活动编号 |
| 39 | + * | ||
| 40 | + * 关联 {@link CombinationActivityDO#getId()} | ||
| 34 | */ | 41 | */ |
| 35 | private Long activityId; | 42 | private Long activityId; |
| 36 | /** | 43 | /** |
| 37 | - * SPU 编号 | ||
| 38 | - */ | ||
| 39 | - private Long spuId; | ||
| 40 | - /** | ||
| 41 | - * SKU 编号 | ||
| 42 | - */ | ||
| 43 | - private Long skuId; | ||
| 44 | - /** | ||
| 45 | - * 用户编号 | ||
| 46 | - */ | ||
| 47 | - private Long userId; | ||
| 48 | - /** | ||
| 49 | - * 订单编号 | 44 | + * 拼团商品单价 |
| 45 | + * | ||
| 46 | + * 冗余 {@link CombinationProductDO#getCombinationPrice()} | ||
| 50 | */ | 47 | */ |
| 51 | - private Long orderId; | 48 | + private Integer combinationPrice; |
| 52 | /** | 49 | /** |
| 53 | - * 团长编号 | ||
| 54 | - * | ||
| 55 | - * 关联 {@link CombinationRecordDO#getId()} | 50 | + * SPU 编号 |
| 56 | */ | 51 | */ |
| 57 | - private Long headId; | 52 | + private Long spuId; |
| 58 | /** | 53 | /** |
| 59 | * 商品名字 | 54 | * 商品名字 |
| 60 | */ | 55 | */ |
| @@ -64,9 +59,14 @@ public class CombinationRecordDO extends BaseDO { | @@ -64,9 +59,14 @@ public class CombinationRecordDO extends BaseDO { | ||
| 64 | */ | 59 | */ |
| 65 | private String picUrl; | 60 | private String picUrl; |
| 66 | /** | 61 | /** |
| 67 | - * 拼团商品单价 | 62 | + * SKU 编号 |
| 68 | */ | 63 | */ |
| 69 | - private Integer combinationPrice; | 64 | + private Long skuId; |
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * 用户编号 | ||
| 68 | + */ | ||
| 69 | + private Long userId; | ||
| 70 | /** | 70 | /** |
| 71 | * 用户昵称 | 71 | * 用户昵称 |
| 72 | */ | 72 | */ |
| @@ -75,6 +75,13 @@ public class CombinationRecordDO extends BaseDO { | @@ -75,6 +75,13 @@ public class CombinationRecordDO extends BaseDO { | ||
| 75 | * 用户头像 | 75 | * 用户头像 |
| 76 | */ | 76 | */ |
| 77 | private String avatar; | 77 | private String avatar; |
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * 团长编号 | ||
| 81 | + * | ||
| 82 | + * 关联 {@link CombinationRecordDO#getId()} | ||
| 83 | + */ | ||
| 84 | + private Long headId; | ||
| 78 | /** | 85 | /** |
| 79 | * 开团状态 | 86 | * 开团状态 |
| 80 | * | 87 | * |
| @@ -82,15 +89,30 @@ public class CombinationRecordDO extends BaseDO { | @@ -82,15 +89,30 @@ public class CombinationRecordDO extends BaseDO { | ||
| 82 | */ | 89 | */ |
| 83 | private Integer status; | 90 | private Integer status; |
| 84 | /** | 91 | /** |
| 92 | + * 订单编号 | ||
| 93 | + */ | ||
| 94 | + private Long orderId; | ||
| 95 | + /** | ||
| 96 | + * 开团需要人数 | ||
| 97 | + * | ||
| 98 | + * 关联 {@link CombinationActivityDO#getUserSize()} | ||
| 99 | + */ | ||
| 100 | + private Integer userSize; | ||
| 101 | + /** | ||
| 102 | + * 已加入拼团人数 | ||
| 103 | + */ | ||
| 104 | + private Integer userCount; | ||
| 105 | + /** | ||
| 85 | * 是否虚拟成团 | 106 | * 是否虚拟成团 |
| 86 | */ | 107 | */ |
| 87 | private Boolean virtualGroup; | 108 | private Boolean virtualGroup; |
| 109 | + | ||
| 88 | /** | 110 | /** |
| 89 | - * 过期时间,单位:小时 | 111 | + * 过期时间 |
| 90 | * | 112 | * |
| 91 | - * 关联 {@link CombinationActivityDO#getLimitDuration()} | 113 | + * 基于 {@link CombinationRecordDO#getStartTime()} + {@link CombinationActivityDO#getLimitDuration()} 计算 |
| 92 | */ | 114 | */ |
| 93 | - private Integer expireTime; | 115 | + private LocalDateTime expireTime; |
| 94 | /** | 116 | /** |
| 95 | * 开始时间 (订单付款后开始的时间) | 117 | * 开始时间 (订单付款后开始的时间) |
| 96 | */ | 118 | */ |
| @@ -99,15 +121,5 @@ public class CombinationRecordDO extends BaseDO { | @@ -99,15 +121,5 @@ public class CombinationRecordDO extends BaseDO { | ||
| 99 | * 结束时间(成团时间/失败时间) | 121 | * 结束时间(成团时间/失败时间) |
| 100 | */ | 122 | */ |
| 101 | private LocalDateTime endTime; | 123 | private LocalDateTime endTime; |
| 102 | - /** | ||
| 103 | - * 开团需要人数 | ||
| 104 | - * | ||
| 105 | - * 关联 {@link CombinationActivityDO#getUserSize()} | ||
| 106 | - */ | ||
| 107 | - private Integer userSize; | ||
| 108 | - /** | ||
| 109 | - * 已加入拼团人数 | ||
| 110 | - */ | ||
| 111 | - private Integer userCount; | ||
| 112 | 124 | ||
| 113 | } | 125 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.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.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.CombinationRecordUpdateStatusReqDTO; | ||
| 5 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; | 4 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; |
| 6 | 5 | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | import java.util.List; | 7 | import java.util.List; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| @@ -16,9 +16,11 @@ public interface CombinationRecordService { | @@ -16,9 +16,11 @@ public interface CombinationRecordService { | ||
| 16 | /** | 16 | /** |
| 17 | * 更新拼团状态 | 17 | * 更新拼团状态 |
| 18 | * | 18 | * |
| 19 | - * @param reqDTO 请求 DTO | 19 | + * @param status 状态 |
| 20 | + * @param userId 用户编号 | ||
| 21 | + * @param orderId 订单编号 | ||
| 20 | */ | 22 | */ |
| 21 | - void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); | 23 | + void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId); |
| 22 | 24 | ||
| 23 | /** | 25 | /** |
| 24 | * 创建拼团记录 | 26 | * 创建拼团记录 |
| @@ -30,9 +32,12 @@ public interface CombinationRecordService { | @@ -30,9 +32,12 @@ public interface CombinationRecordService { | ||
| 30 | /** | 32 | /** |
| 31 | * 更新拼团状态和开始时间 | 33 | * 更新拼团状态和开始时间 |
| 32 | * | 34 | * |
| 33 | - * @param reqDTO 请求 DTO | 35 | + * @param status 状态 |
| 36 | + * @param userId 用户编号 | ||
| 37 | + * @param orderId 订单编号 | ||
| 38 | + * @param startTime 开始时间 | ||
| 34 | */ | 39 | */ |
| 35 | - void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); | 40 | + void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime); |
| 36 | 41 | ||
| 37 | /** | 42 | /** |
| 38 | * 获得拼团状态 | 43 | * 获得拼团状态 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
| @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination; | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; | 5 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 6 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | ||
| 7 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; | 6 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; |
| 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; | 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; |
| 9 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; |
| @@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | @@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | ||
| 21 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; | 20 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 22 | 21 | ||
| 23 | // TODO 芋艿:等拼团记录做完,完整 review 下 | 22 | // TODO 芋艿:等拼团记录做完,完整 review 下 |
| 23 | + | ||
| 24 | /** | 24 | /** |
| 25 | * 拼团记录 Service 实现类 | 25 | * 拼团记录 Service 实现类 |
| 26 | * | 26 | * |
| @@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { | @@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { | ||
| 38 | 38 | ||
| 39 | @Override | 39 | @Override |
| 40 | @Transactional(rollbackFor = Exception.class) | 40 | @Transactional(rollbackFor = Exception.class) |
| 41 | - public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { | 41 | + public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) { |
| 42 | // 校验拼团是否存在 | 42 | // 校验拼团是否存在 |
| 43 | - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); | 43 | + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); |
| 44 | 44 | ||
| 45 | // 更新状态 | 45 | // 更新状态 |
| 46 | - recordDO.setStatus(reqDTO.getStatus()); | 46 | + recordDO.setStatus(status); |
| 47 | recordMapper.updateById(recordDO); | 47 | recordMapper.updateById(recordDO); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | @Override | 50 | @Override |
| 51 | @Transactional(rollbackFor = Exception.class) | 51 | @Transactional(rollbackFor = Exception.class) |
| 52 | - public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { | ||
| 53 | - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); | 52 | + public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) { |
| 53 | + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); | ||
| 54 | // 更新状态 | 54 | // 更新状态 |
| 55 | - recordDO.setStatus(reqDTO.getStatus()); | 55 | + recordDO.setStatus(status); |
| 56 | // 更新开始时间 | 56 | // 更新开始时间 |
| 57 | - recordDO.setStartTime(reqDTO.getStartTime()); | 57 | + recordDO.setStartTime(startTime); |
| 58 | recordMapper.updateById(recordDO); | 58 | recordMapper.updateById(recordDO); |
| 59 | 59 | ||
| 60 | // 更新拼团参入人数 | 60 | // 更新拼团参入人数 |
| 61 | - List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus()); | 61 | + List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status); |
| 62 | if (CollUtil.isNotEmpty(recordDOs)) { | 62 | if (CollUtil.isNotEmpty(recordDOs)) { |
| 63 | recordDOs.forEach(item -> { | 63 | recordDOs.forEach(item -> { |
| 64 | item.setUserCount(recordDOs.size()); | 64 | item.setUserCount(recordDOs.size()); |
| @@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { | @@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { | ||
| 115 | // 2. 创建拼团记录 | 115 | // 2. 创建拼团记录 |
| 116 | CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); | 116 | CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); |
| 117 | record.setVirtualGroup(false); | 117 | record.setVirtualGroup(false); |
| 118 | - // TODO @puhui999:过期时间,应该是 Date 哈; | ||
| 119 | - record.setExpireTime(activity.getLimitDuration()); | 118 | + record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration())); |
| 120 | record.setUserSize(activity.getUserSize()); | 119 | record.setUserSize(activity.getUserSize()); |
| 121 | recordMapper.insert(record); | 120 | recordMapper.insert(record); |
| 122 | } | 121 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
| @@ -34,6 +34,20 @@ public interface SeckillActivityService { | @@ -34,6 +34,20 @@ public interface SeckillActivityService { | ||
| 34 | void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); | 34 | void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| 37 | + * 更新秒杀活动 | ||
| 38 | + * | ||
| 39 | + * @param activityDO 秒杀活动 | ||
| 40 | + */ | ||
| 41 | + void updateSeckillActivity(SeckillActivityDO activityDO); | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 更新秒杀活动商品 | ||
| 45 | + * | ||
| 46 | + * @param productList 活动商品列表 | ||
| 47 | + */ | ||
| 48 | + void updateSeckillActivityProductList(List<SeckillProductDO> productList); | ||
| 49 | + | ||
| 50 | + /** | ||
| 37 | * 关闭秒杀活动 | 51 | * 关闭秒杀活动 |
| 38 | * | 52 | * |
| 39 | * @param id 编号 | 53 | * @param id 编号 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
| @@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 79 | * 1. 校验秒杀时段是否存在 | 79 | * 1. 校验秒杀时段是否存在 |
| 80 | * 2. 秒杀商品是否参加其它活动 | 80 | * 2. 秒杀商品是否参加其它活动 |
| 81 | * | 81 | * |
| 82 | - * @param configIds 秒杀时段数组 | ||
| 83 | - * @param spuId 商品 SPU 编号 | 82 | + * @param configIds 秒杀时段数组 |
| 83 | + * @param spuId 商品 SPU 编号 | ||
| 84 | * @param activityId 秒杀活动编号 | 84 | * @param activityId 秒杀活动编号 |
| 85 | */ | 85 | */ |
| 86 | private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) { | 86 | private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) { |
| @@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 92 | if (activityId != null) { // 排除自己 | 92 | if (activityId != null) { // 排除自己 |
| 93 | activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); | 93 | activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); |
| 94 | } | 94 | } |
| 95 | - // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠; | ||
| 96 | - // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠 | ||
| 97 | - List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId)); | ||
| 98 | - if (isNotEmpty(activityDOs1)) { | ||
| 99 | - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); | ||
| 100 | - } | ||
| 101 | - // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠 | ||
| 102 | - List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds)); | ||
| 103 | - if (isNotEmpty(activityDOs2)) { | 95 | + // 2.2 过滤出所有 configIds 有交集的活动,判断是否存在重叠 |
| 96 | + List<SeckillActivityDO> conflictActivityList = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds)); | ||
| 97 | + if (isNotEmpty(conflictActivityList)) { | ||
| 104 | throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); | 98 | throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); |
| 105 | } | 99 | } |
| 106 | } | 100 | } |
| @@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 108 | /** | 102 | /** |
| 109 | * 校验秒杀商品是否都存在 | 103 | * 校验秒杀商品是否都存在 |
| 110 | * | 104 | * |
| 111 | - * @param spuId 商品 SPU 编号 | 105 | + * @param spuId 商品 SPU 编号 |
| 112 | * @param products 秒杀商品 | 106 | * @param products 秒杀商品 |
| 113 | */ | 107 | */ |
| 114 | private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) { | 108 | private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) { |
| @@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 150 | updateSeckillProduct(updateObj, updateReqVO.getProducts()); | 144 | updateSeckillProduct(updateObj, updateReqVO.getProducts()); |
| 151 | } | 145 | } |
| 152 | 146 | ||
| 147 | + @Override | ||
| 148 | + public void updateSeckillActivity(SeckillActivityDO activityDO) { | ||
| 149 | + seckillActivityMapper.updateById(activityDO); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + @Override | ||
| 153 | + public void updateSeckillActivityProductList(List<SeckillProductDO> productList) { | ||
| 154 | + seckillProductMapper.updateBatch(productList); | ||
| 155 | + } | ||
| 156 | + | ||
| 153 | /** | 157 | /** |
| 154 | * 更新秒杀商品 | 158 | * 更新秒杀商品 |
| 155 | * | 159 | * |
| 156 | * @param activity 秒杀活动 | 160 | * @param activity 秒杀活动 |
| 157 | - * @param products 该活动的最新商品配置 | 161 | + * @param products 该活动的最新商品配置 |
| 158 | */ | 162 | */ |
| 159 | private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) { | 163 | private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) { |
| 160 | // 第一步,对比新老数据,获得添加、修改、删除的列表 | 164 | // 第一步,对比新老数据,获得添加、修改、删除的列表 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
| 1 | package cn.iocoder.yudao.module.promotion.util; | 1 | package cn.iocoder.yudao.module.promotion.util; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | 4 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 6 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 7 | 5 | ||
| 8 | import java.time.LocalDateTime; | 6 | import java.time.LocalDateTime; |
| 9 | -import java.util.List; | ||
| 10 | -import java.util.Set; | ||
| 11 | -import java.util.function.Function; | ||
| 12 | - | ||
| 13 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 14 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; | ||
| 15 | -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | ||
| 16 | 7 | ||
| 17 | /** | 8 | /** |
| 18 | * 活动工具类 | 9 | * 活动工具类 |
| @@ -31,21 +22,4 @@ public class PromotionUtils { | @@ -31,21 +22,4 @@ public class PromotionUtils { | ||
| 31 | return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); | 22 | return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); |
| 32 | } | 23 | } |
| 33 | 24 | ||
| 34 | - /** | ||
| 35 | - * 校验商品 sku 是否都存在 | ||
| 36 | - * | ||
| 37 | - * @param skus 数据库中的商品 skus | ||
| 38 | - * @param products 需要校验的商品 | ||
| 39 | - * @param func 获取需要校验的商品的 skuId | ||
| 40 | - */ | ||
| 41 | - public static <T> void validateProductSkuAllExists(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) { | ||
| 42 | - // 校验 sku 个数是否一致 | ||
| 43 | - Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func); | ||
| 44 | - Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId); | ||
| 45 | - // 校验 skuId 是否存在 | ||
| 46 | - if (anyMatch(skuIdsSet, s -> !skuIdsSet1.contains(s))) { | ||
| 47 | - throw exception(SKU_NOT_EXISTS); | ||
| 48 | - } | ||
| 49 | - } | ||
| 50 | - | ||
| 51 | } | 25 | } |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.api.brokerage; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 分销 API 接口 | ||
| 7 | + * | ||
| 8 | + * @author owen | ||
| 9 | + */ | ||
| 10 | +public interface BrokerageApi { | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * 获得分销用户 | ||
| 14 | + * | ||
| 15 | + * @param userId 用户编号 | ||
| 16 | + * @return 分销用户信息 | ||
| 17 | + */ | ||
| 18 | + BrokerageUserDTO getBrokerageUser(Long userId); | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 绑定推广员 | ||
| 22 | + * | ||
| 23 | + * @param userId 用户编号 | ||
| 24 | + * @param bindUserId 推广员编号 | ||
| 25 | + * @param isNewUser 是否为新用户 | ||
| 26 | + * @return 是否绑定 | ||
| 27 | + */ | ||
| 28 | + boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); | ||
| 29 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/dto/BrokerageUserDTO.java
0 → 100644
| 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
| @@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; | @@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; | ||
| 11 | */ | 11 | */ |
| 12 | public interface ErrorCodeConstants { | 12 | public interface ErrorCodeConstants { |
| 13 | 13 | ||
| 14 | - // ========== Order 模块 1-011-000-000 ========== | 14 | + // ========== Order 模块 1-011-000-000 ========== |
| 15 | ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1_011_000_001, "商品 SKU 不存在"); | 15 | ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1_011_000_001, "商品 SKU 不存在"); |
| 16 | ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1_011_000_002, "商品 SPU 不可售卖"); | 16 | ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1_011_000_002, "商品 SPU 不可售卖"); |
| 17 | ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1_011_000_004, "商品 SKU 库存不足"); | 17 | ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1_011_000_004, "商品 SKU 库存不足"); |
| @@ -35,7 +35,7 @@ public interface ErrorCodeConstants { | @@ -35,7 +35,7 @@ public interface ErrorCodeConstants { | ||
| 35 | ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1_011_000_024, "交易订单发货失败,发货类型不是快递"); | 35 | ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1_011_000_024, "交易订单发货失败,发货类型不是快递"); |
| 36 | ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1_011_000_025, "交易订单取消失败,订单不是【待支付】状态"); | 36 | ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1_011_000_025, "交易订单取消失败,订单不是【待支付】状态"); |
| 37 | 37 | ||
| 38 | - // ========== After Sale 模块 1-011-000-100 ========== | 38 | + // ========== After Sale 模块 1-011-000-100 ========== |
| 39 | ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1_011_000_100, "售后单不存在"); | 39 | ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1_011_000_100, "售后单不存在"); |
| 40 | ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1_011_000_101, "申请退款金额错误"); | 40 | ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1_011_000_101, "申请退款金额错误"); |
| 41 | ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1_011_000_102, "订单已关闭,无法申请售后"); | 41 | ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1_011_000_102, "订单已关闭,无法申请售后"); |
| @@ -50,7 +50,7 @@ public interface ErrorCodeConstants { | @@ -50,7 +50,7 @@ public interface ErrorCodeConstants { | ||
| 50 | ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY = | 50 | ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY = |
| 51 | new ErrorCode(1_011_000_111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】"); | 51 | new ErrorCode(1_011_000_111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】"); |
| 52 | 52 | ||
| 53 | - // ========== Cart 模块 1-011-002-000 ========== | 53 | + // ========== Cart 模块 1-011-002-000 ========== |
| 54 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1_011_002_000, "购物车项不存在"); | 54 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1_011_002_000, "购物车项不存在"); |
| 55 | 55 | ||
| 56 | // ========== Price 相关 1-011-003-000 ============ | 56 | // ========== Price 相关 1-011-003-000 ============ |
| @@ -58,7 +58,7 @@ public interface ErrorCodeConstants { | @@ -58,7 +58,7 @@ public interface ErrorCodeConstants { | ||
| 58 | ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1_011_003_001, "计算快递运费异常,收件人地址编号为空"); | 58 | ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1_011_003_001, "计算快递运费异常,收件人地址编号为空"); |
| 59 | ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); | 59 | ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); |
| 60 | 60 | ||
| 61 | - // ========== 物流 Express 模块 1-011-004-000 ========== | 61 | + // ========== 物流 Express 模块 1-011-004-000 ========== |
| 62 | ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); | 62 | ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); |
| 63 | ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1_011_004_001, "已经存在该编码的快递公司"); | 63 | ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1_011_004_001, "已经存在该编码的快递公司"); |
| 64 | ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1_011_004_002, "需要接入快递服务商,比如【快递100】"); | 64 | ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1_011_004_002, "需要接入快递服务商,比如【快递100】"); |
| @@ -67,11 +67,21 @@ public interface ErrorCodeConstants { | @@ -67,11 +67,21 @@ public interface ErrorCodeConstants { | ||
| 67 | ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1_011_004_101, "快递查询接口异常"); | 67 | ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1_011_004_101, "快递查询接口异常"); |
| 68 | ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1_011_004_102, "快递查询返回失败,原因:{}"); | 68 | ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1_011_004_102, "快递查询返回失败,原因:{}"); |
| 69 | 69 | ||
| 70 | - // ========== 物流 Template 模块 1-011-005-000 ========== | 70 | + // ========== 物流 Template 模块 1-011-005-000 ========== |
| 71 | ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1_011_005_000, "已经存在该运费模板名"); | 71 | ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1_011_005_000, "已经存在该运费模板名"); |
| 72 | ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_011_005_001, "运费模板不存在"); | 72 | ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_011_005_001, "运费模板不存在"); |
| 73 | 73 | ||
| 74 | // ========== 物流 PICK_UP 模块 1-011-006-000 ========== | 74 | // ========== 物流 PICK_UP 模块 1-011-006-000 ========== |
| 75 | ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1_011_006_000, "自提门店不存在"); | 75 | ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1_011_006_000, "自提门店不存在"); |
| 76 | 76 | ||
| 77 | + // ========== 分销用户 模块 1011007000 ========== | ||
| 78 | + ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在"); | ||
| 79 | + ErrorCode BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH = new ErrorCode(1011007001, "用户冻结佣金({})数量不足"); | ||
| 80 | + ErrorCode BROKERAGE_BIND_SELF = new ErrorCode(1011007002, "不能绑定自己"); | ||
| 81 | + ErrorCode BROKERAGE_BIND_USER_NOT_ENABLED = new ErrorCode(1011007003, "绑定用户没有推广资格"); | ||
| 82 | + ErrorCode BROKERAGE_BIND_CONDITION_ADMIN = new ErrorCode(1011007004, "仅可在后台绑定推广员"); | ||
| 83 | + ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1011007005, "只有在注册时可以绑定"); | ||
| 84 | + ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人"); | ||
| 85 | + ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级"); | ||
| 86 | + | ||
| 77 | } | 87 | } |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 分销关系绑定模式枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageBindModeEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 只要用户没有推广人,随时都可以绑定分销关系 | ||
| 20 | + */ | ||
| 21 | + ANYTIME(1, "没有推广人"), | ||
| 22 | + /** | ||
| 23 | + * 仅新用户注册时才能绑定推广关系 | ||
| 24 | + */ | ||
| 25 | + REGISTER(2, "新用户"), | ||
| 26 | + /** | ||
| 27 | + * 每次扫码都覆盖 | ||
| 28 | + */ | ||
| 29 | + OVERRIDE(3, "扫码覆盖"), | ||
| 30 | + ; | ||
| 31 | + | ||
| 32 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray(); | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 模式 | ||
| 36 | + */ | ||
| 37 | + private final Integer mode; | ||
| 38 | + /** | ||
| 39 | + * 名字 | ||
| 40 | + */ | ||
| 41 | + private final String name; | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public int[] array() { | ||
| 45 | + return ARRAYS; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageEnabledConditionEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 分佣模式枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageEnabledConditionEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 所有用户都可以分销 | ||
| 20 | + */ | ||
| 21 | + ALL(1, "人人分销"), | ||
| 22 | + /** | ||
| 23 | + * 仅可后台手动设置推广员 | ||
| 24 | + */ | ||
| 25 | + ADMIN(2, "指定分销"), | ||
| 26 | + ; | ||
| 27 | + | ||
| 28 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageEnabledConditionEnum::getCondition).toArray(); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 模式 | ||
| 32 | + */ | ||
| 33 | + private final Integer condition; | ||
| 34 | + /** | ||
| 35 | + * 名字 | ||
| 36 | + */ | ||
| 37 | + private final String name; | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public int[] array() { | ||
| 41 | + return ARRAYS; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 佣金记录业务类型枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageRecordBizTypeEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + ORDER(1, "获得推广佣金", "获得推广佣金 {}", true), | ||
| 19 | + WITHDRAW(2, "提现申请", "提现申请扣除佣金 {}", false), | ||
| 20 | + ; | ||
| 21 | + | ||
| 22 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordBizTypeEnum::getType).toArray(); | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 类型 | ||
| 26 | + */ | ||
| 27 | + private final Integer type; | ||
| 28 | + /** | ||
| 29 | + * 标题 | ||
| 30 | + */ | ||
| 31 | + private final String title; | ||
| 32 | + /** | ||
| 33 | + * 描述 | ||
| 34 | + */ | ||
| 35 | + private final String description; | ||
| 36 | + /** | ||
| 37 | + * 是否为增加佣金 | ||
| 38 | + */ | ||
| 39 | + private final boolean add; | ||
| 40 | + | ||
| 41 | + @Override | ||
| 42 | + public int[] array() { | ||
| 43 | + return ARRAYS; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordStatusEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 佣金记录状态枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageRecordStatusEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + WAIT_SETTLEMENT(0, "待结算"), | ||
| 19 | + SETTLEMENT(1, "已结算"), | ||
| 20 | + CANCEL(2, "已取消"), | ||
| 21 | + ; | ||
| 22 | + | ||
| 23 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordStatusEnum::getStatus).toArray(); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 状态 | ||
| 27 | + */ | ||
| 28 | + private final Integer status; | ||
| 29 | + /** | ||
| 30 | + * 名字 | ||
| 31 | + */ | ||
| 32 | + private final String name; | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public int[] array() { | ||
| 36 | + return ARRAYS; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 佣金提现状态枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageWithdrawStatusEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + AUDITING(0, "审核中"), | ||
| 19 | + AUDIT_SUCCESS(10, "审核通过"), | ||
| 20 | + WITHDRAW_SUCCESS(11, "提现成功"), | ||
| 21 | + AUDIT_FAIL(20, "审核不通过"), | ||
| 22 | + WITHDRAW_FAIL(21, "提现失败"), | ||
| 23 | + ; | ||
| 24 | + | ||
| 25 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawStatusEnum::getStatus).toArray(); | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 状态 | ||
| 29 | + */ | ||
| 30 | + private final Integer status; | ||
| 31 | + /** | ||
| 32 | + * 名字 | ||
| 33 | + */ | ||
| 34 | + private final String name; | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public int[] array() { | ||
| 38 | + return ARRAYS; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java
0 → 100644
| 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 | +/** | ||
| 10 | + * 佣金提现类型枚举 | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum BrokerageWithdrawTypeEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + WALLET(1, "钱包"), | ||
| 19 | + BANK(2, "银行卡"), | ||
| 20 | + WECHAT(3, "微信"), | ||
| 21 | + ALIPAY(4, "支付宝"), | ||
| 22 | + ; | ||
| 23 | + | ||
| 24 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawTypeEnum::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-biz/pom.xml
| @@ -56,6 +56,10 @@ | @@ -56,6 +56,10 @@ | ||
| 56 | </dependency> | 56 | </dependency> |
| 57 | <dependency> | 57 | <dependency> |
| 58 | <groupId>cn.iocoder.boot</groupId> | 58 | <groupId>cn.iocoder.boot</groupId> |
| 59 | + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> | ||
| 60 | + </dependency> | ||
| 61 | + <dependency> | ||
| 62 | + <groupId>cn.iocoder.boot</groupId> | ||
| 59 | <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | 63 | <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> |
| 60 | </dependency> | 64 | </dependency> |
| 61 | 65 | ||
| @@ -82,6 +86,11 @@ | @@ -82,6 +86,11 @@ | ||
| 82 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> | 86 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| 83 | </dependency> | 87 | </dependency> |
| 84 | 88 | ||
| 89 | + <dependency> | ||
| 90 | + <groupId>cn.iocoder.boot</groupId> | ||
| 91 | + <artifactId>yudao-spring-boot-starter-redis</artifactId> | ||
| 92 | + </dependency> | ||
| 93 | + | ||
| 85 | <!-- Test 测试相关 --> | 94 | <!-- Test 测试相关 --> |
| 86 | <dependency> | 95 | <dependency> |
| 87 | <groupId>cn.iocoder.boot</groupId> | 96 | <groupId>cn.iocoder.boot</groupId> |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java
0 → 100644
| 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/aftersale/TradeAfterSaleController.java
| @@ -76,6 +76,11 @@ public class TradeAfterSaleController { | @@ -76,6 +76,11 @@ public class TradeAfterSaleController { | ||
| 76 | public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { | 76 | public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { |
| 77 | // 查询订单 | 77 | // 查询订单 |
| 78 | TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); | 78 | TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); |
| 79 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; | ||
| 80 | +// if (afterSale == null) { | ||
| 81 | +// return success(null, AFTER_SALE_NOT_FOUND.getMsg()); | ||
| 82 | +// } | ||
| 83 | + | ||
| 79 | // 查询订单 | 84 | // 查询订单 |
| 80 | TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); | 85 | TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); |
| 81 | // 查询订单项 | 86 | // 查询订单项 |
| @@ -92,7 +97,11 @@ public class TradeAfterSaleController { | @@ -92,7 +97,11 @@ public class TradeAfterSaleController { | ||
| 92 | TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO(); | 97 | TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO(); |
| 93 | respVO.setId((long) i); | 98 | respVO.setId((long) i); |
| 94 | respVO.setUserId((long) i); | 99 | respVO.setUserId((long) i); |
| 95 | - respVO.setUserType(1); | 100 | + respVO.setUserType(i % 2 == 0 ? 2 : 1); |
| 101 | + // 模拟系统操作 | ||
| 102 | + if (i == 2) { | ||
| 103 | + respVO.setUserType(3); | ||
| 104 | + } | ||
| 96 | respVO.setAfterSaleId(id); | 105 | respVO.setAfterSaleId(id); |
| 97 | respVO.setOrderId((long) i); | 106 | respVO.setOrderId((long) i); |
| 98 | respVO.setOrderItemId((long) i); | 107 | respVO.setOrderItemId((long) i); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDetailRespVO.java
| @@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO { | @@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO { | ||
| 35 | /** | 35 | /** |
| 36 | * 售后日志 | 36 | * 售后日志 |
| 37 | */ | 37 | */ |
| 38 | - private List<TradeAfterSaleLogRespVO> afterSaleLog; | 38 | + private List<TradeAfterSaleLogRespVO> logs; |
| 39 | 39 | ||
| 40 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") | 40 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") |
| 41 | @Data | 41 | @Data |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record; | ||
| 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.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; | ||
| 10 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 11 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 12 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 13 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 15 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 18 | +import org.springframework.web.bind.annotation.RestController; | ||
| 19 | + | ||
| 20 | +import javax.annotation.Resource; | ||
| 21 | +import javax.validation.Valid; | ||
| 22 | + | ||
| 23 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 24 | + | ||
| 25 | +@Tag(name = "管理后台 - 佣金记录") | ||
| 26 | +@RestController | ||
| 27 | +@RequestMapping("/trade/brokerage-record") | ||
| 28 | +@Validated | ||
| 29 | +public class BrokerageRecordController { | ||
| 30 | + | ||
| 31 | + @Resource | ||
| 32 | + private BrokerageRecordService brokerageRecordService; | ||
| 33 | + | ||
| 34 | + @GetMapping("/get") | ||
| 35 | + @Operation(summary = "获得佣金记录") | ||
| 36 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 37 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") | ||
| 38 | + public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Integer id) { | ||
| 39 | + BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id); | ||
| 40 | + return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord)); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @GetMapping("/page") | ||
| 44 | + @Operation(summary = "获得佣金记录分页") | ||
| 45 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") | ||
| 46 | + public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) { | ||
| 47 | + PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO); | ||
| 48 | + return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult)); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.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.NotEmpty; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | +import java.time.LocalDateTime; | ||
| 10 | + | ||
| 11 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 佣金记录 Base VO,提供给添加、修改、详细的子 VO 使用 | ||
| 15 | + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 16 | + */ | ||
| 17 | +@Data | ||
| 18 | +public class BrokerageRecordBaseVO { | ||
| 19 | + | ||
| 20 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25973") | ||
| 21 | + @NotNull(message = "用户编号不能为空") | ||
| 22 | + private Long userId; | ||
| 23 | + | ||
| 24 | + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353") | ||
| 25 | + @NotEmpty(message = "业务编号不能为空") | ||
| 26 | + private String bizId; | ||
| 27 | + | ||
| 28 | + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 29 | + @NotNull(message = "业务类型不能为空") | ||
| 30 | + private Integer bizType; | ||
| 31 | + | ||
| 32 | + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 33 | + @NotEmpty(message = "标题不能为空") | ||
| 34 | + private String title; | ||
| 35 | + | ||
| 36 | + @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731") | ||
| 37 | + @NotNull(message = "金额不能为空") | ||
| 38 | + private Integer price; | ||
| 39 | + | ||
| 40 | + @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "13226") | ||
| 41 | + @NotNull(message = "当前总佣金不能为空") | ||
| 42 | + private Integer totalPrice; | ||
| 43 | + | ||
| 44 | + @Schema(description = "说明", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") | ||
| 45 | + @NotNull(message = "说明不能为空") | ||
| 46 | + private String description; | ||
| 47 | + | ||
| 48 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 49 | + @NotNull(message = "状态不能为空") | ||
| 50 | + private Integer status; | ||
| 51 | + | ||
| 52 | + @Schema(description = "冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 53 | + @NotNull(message = "冻结时间(天)不能为空") | ||
| 54 | + private Integer frozenDays; | ||
| 55 | + | ||
| 56 | + @Schema(description = "解冻时间") | ||
| 57 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 58 | + private LocalDateTime unfreezeTime; | ||
| 59 | + | ||
| 60 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | +import lombok.EqualsAndHashCode; | ||
| 7 | +import lombok.ToString; | ||
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 13 | + | ||
| 14 | +@Schema(description = "管理后台 - 佣金记录分页 Request VO") | ||
| 15 | +@Data | ||
| 16 | +@EqualsAndHashCode(callSuper = true) | ||
| 17 | +@ToString(callSuper = true) | ||
| 18 | +public class BrokerageRecordPageReqVO extends PageParam { | ||
| 19 | + | ||
| 20 | + @Schema(description = "用户编号", example = "25973") | ||
| 21 | + private Long userId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "业务类型", example = "1") | ||
| 24 | + private Integer bizType; | ||
| 25 | + | ||
| 26 | + @Schema(description = "状态", example = "1") | ||
| 27 | + private Integer status; | ||
| 28 | + | ||
| 29 | + @Schema(description = "创建时间") | ||
| 30 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 31 | + private LocalDateTime[] createTime; | ||
| 32 | + | ||
| 33 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.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 BrokerageRecordRespVO extends BrokerageRecordBaseVO { | ||
| 15 | + | ||
| 16 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896") | ||
| 17 | + private Integer id; | ||
| 18 | + | ||
| 19 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 20 | + private LocalDateTime createTime; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user; | ||
| 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.user.vo.*; | ||
| 8 | +import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert; | ||
| 9 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 11 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 12 | +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; | ||
| 13 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; | ||
| 14 | +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; | ||
| 15 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 16 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 17 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 18 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 19 | +import org.springframework.validation.annotation.Validated; | ||
| 20 | +import org.springframework.web.bind.annotation.*; | ||
| 21 | + | ||
| 22 | +import javax.annotation.Resource; | ||
| 23 | +import javax.validation.Valid; | ||
| 24 | +import java.util.Map; | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 28 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 30 | + | ||
| 31 | +@Tag(name = "管理后台 - 分销用户") | ||
| 32 | +@RestController | ||
| 33 | +@RequestMapping("/trade/brokerage-user") | ||
| 34 | +@Validated | ||
| 35 | +public class BrokerageUserController { | ||
| 36 | + | ||
| 37 | + @Resource | ||
| 38 | + private BrokerageUserService brokerageUserService; | ||
| 39 | + @Resource | ||
| 40 | + private BrokerageRecordService brokerageRecordService; | ||
| 41 | + | ||
| 42 | + @Resource | ||
| 43 | + private MemberUserApi memberUserApi; | ||
| 44 | + | ||
| 45 | + @PutMapping("/update-brokerage-user") | ||
| 46 | + @Operation(summary = "修改推广员") | ||
| 47 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-user')") | ||
| 48 | + public CommonResult<Boolean> updateBrokerageUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) { | ||
| 49 | + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId()); | ||
| 50 | + return success(true); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @PutMapping("/clear-brokerage-user") | ||
| 54 | + @Operation(summary = "清除推广员") | ||
| 55 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-brokerage-user')") | ||
| 56 | + public CommonResult<Boolean> clearBrokerageUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) { | ||
| 57 | + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null); | ||
| 58 | + return success(true); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @PutMapping("/update-brokerage-enable") | ||
| 62 | + @Operation(summary = "修改推广资格") | ||
| 63 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')") | ||
| 64 | + public CommonResult<Boolean> updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) { | ||
| 65 | + brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled()); | ||
| 66 | + return success(true); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @GetMapping("/get") | ||
| 70 | + @Operation(summary = "获得分销用户") | ||
| 71 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 72 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") | ||
| 73 | + public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) { | ||
| 74 | + BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id); | ||
| 75 | + return success(BrokerageUserConvert.INSTANCE.convert(brokerageUser)); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @GetMapping("/page") | ||
| 79 | + @Operation(summary = "获得分销用户分页") | ||
| 80 | + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") | ||
| 81 | + public CommonResult<PageResult<BrokerageUserRespVO>> getBrokerageUserPage(@Valid BrokerageUserPageReqVO pageVO) { | ||
| 82 | + // 分页查询 | ||
| 83 | + PageResult<BrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(pageVO); | ||
| 84 | + | ||
| 85 | + // 涉及到的用户 | ||
| 86 | + Set<Long> userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId); | ||
| 87 | + // 查询用户信息 | ||
| 88 | + Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds); | ||
| 89 | + // 合计分佣订单 | ||
| 90 | + Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap = convertMap(userIds, | ||
| 91 | + userId -> userId, | ||
| 92 | + userId -> brokerageRecordService.getUserBrokerageSummaryByUserId(userId, | ||
| 93 | + BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus())); | ||
| 94 | + // 合计推广用户数量 | ||
| 95 | + Map<Long, Long> brokerageUserCountMap = convertMap(userIds, | ||
| 96 | + userId -> userId, | ||
| 97 | + userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId)); | ||
| 98 | + | ||
| 99 | + // todo 合计提现 | ||
| 100 | + | ||
| 101 | + return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap, userOrderSummaryMap)); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserBaseVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.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 BrokerageUserBaseVO { | ||
| 18 | + | ||
| 19 | + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587") | ||
| 20 | + @NotNull(message = "推广员编号不能为空") | ||
| 21 | + private Long bindUserId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "推广员绑定时间") | ||
| 24 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 25 | + private LocalDateTime bindUserTime; | ||
| 26 | + | ||
| 27 | + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | + @NotNull(message = "推广资格不能为空") | ||
| 29 | + private Boolean brokerageEnabled; | ||
| 30 | + | ||
| 31 | + @Schema(description = "成为分销员时间") | ||
| 32 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 33 | + private LocalDateTime brokerageTime; | ||
| 34 | + | ||
| 35 | + @Schema(description = "可用佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "11089") | ||
| 36 | + @NotNull(message = "可用佣金不能为空") | ||
| 37 | + private Integer price; | ||
| 38 | + | ||
| 39 | + @Schema(description = "冻结佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "30916") | ||
| 40 | + @NotNull(message = "冻结佣金不能为空") | ||
| 41 | + private Integer frozenPrice; | ||
| 42 | + | ||
| 43 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserClearBrokerageUserReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.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.NotNull; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - 分销用户 - 清除推广员 Request VO") | ||
| 10 | +@Data | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class BrokerageUserClearBrokerageUserReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | ||
| 15 | + @NotNull(message = "用户编号不能为空") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | +import lombok.EqualsAndHashCode; | ||
| 7 | +import lombok.ToString; | ||
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 13 | + | ||
| 14 | +@Schema(description = "管理后台 - 分销用户分页 Request VO") | ||
| 15 | +@Data | ||
| 16 | +@EqualsAndHashCode(callSuper = true) | ||
| 17 | +@ToString(callSuper = true) | ||
| 18 | +public class BrokerageUserPageReqVO extends PageParam { | ||
| 19 | + | ||
| 20 | + @Schema(description = "推广员编号", example = "4587") | ||
| 21 | + private Long bindUserId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "推广资格") | ||
| 24 | + private Boolean brokerageEnabled; | ||
| 25 | + | ||
| 26 | + @Schema(description = "创建时间") | ||
| 27 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 28 | + private LocalDateTime[] createTime; | ||
| 29 | + | ||
| 30 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.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 BrokerageUserRespVO extends BrokerageUserBaseVO { | ||
| 15 | + | ||
| 16 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 20 | + private LocalDateTime createTime; | ||
| 21 | + | ||
| 22 | + // ========== 用户信息 ========== | ||
| 23 | + | ||
| 24 | + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") | ||
| 25 | + private String avatar; | ||
| 26 | + @Schema(description = "用户昵称", example = "李四") | ||
| 27 | + private String nickname; | ||
| 28 | + | ||
| 29 | + // ========== 推广信息 ========== | ||
| 30 | + | ||
| 31 | + @Schema(description = "推广用户数量(一级)", example = "20019") | ||
| 32 | + private Integer brokerageUserCount; | ||
| 33 | + @Schema(description = "推广订单数量", example = "20019") | ||
| 34 | + private Integer brokerageOrderCount; | ||
| 35 | + @Schema(description = "推广订单金额", example = "20019") | ||
| 36 | + private Integer brokerageOrderPrice; | ||
| 37 | + | ||
| 38 | + // ========== 提现信息 ========== | ||
| 39 | + | ||
| 40 | + @Schema(description = "已提现金额", example = "20019") | ||
| 41 | + private Integer withdrawPrice; | ||
| 42 | + @Schema(description = "已提现次数", example = "20019") | ||
| 43 | + private Integer withdrawCount; | ||
| 44 | + | ||
| 45 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserUpdateBrokerageEnabledReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.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.NotNull; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO") | ||
| 10 | +@Data | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class BrokerageUserUpdateBrokerageEnabledReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | ||
| 15 | + @NotNull(message = "用户编号不能为空") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 19 | + @NotNull(message = "推广资格不能为空") | ||
| 20 | + private Boolean enabled; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserUpdateBrokerageUserReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.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.NotNull; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO") | ||
| 10 | +@Data | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class BrokerageUserUpdateBrokerageUserReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | ||
| 15 | + @NotNull(message = "用户编号不能为空") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587") | ||
| 19 | + @NotNull(message = "推广员编号不能为空") | ||
| 20 | + private Long bindUserId; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | ||
| 9 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 10 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 11 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 12 | +import org.springframework.validation.annotation.Validated; | ||
| 13 | +import org.springframework.web.bind.annotation.*; | ||
| 14 | + | ||
| 15 | +import javax.annotation.Resource; | ||
| 16 | +import javax.validation.Valid; | ||
| 17 | + | ||
| 18 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 19 | + | ||
| 20 | +@Tag(name = "管理后台 - 交易中心配置") | ||
| 21 | +@RestController | ||
| 22 | +@RequestMapping("/trade/config") | ||
| 23 | +@Validated | ||
| 24 | +public class TradeConfigController { | ||
| 25 | + | ||
| 26 | + @Resource | ||
| 27 | + private TradeConfigService tradeConfigService; | ||
| 28 | + | ||
| 29 | + @PutMapping("/save") | ||
| 30 | + @Operation(summary = "更新交易中心配置") | ||
| 31 | + @PreAuthorize("@ss.hasPermission('trade:config:save')") | ||
| 32 | + public CommonResult<Boolean> updateConfig(@Valid @RequestBody TradeConfigSaveReqVO updateReqVO) { | ||
| 33 | + tradeConfigService.saveTradeConfig(updateReqVO); | ||
| 34 | + return success(true); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @GetMapping("/get") | ||
| 38 | + @Operation(summary = "获得交易中心配置") | ||
| 39 | + @PreAuthorize("@ss.hasPermission('trade:config:query')") | ||
| 40 | + public CommonResult<TradeConfigRespVO> getConfig() { | ||
| 41 | + TradeConfigDO config = tradeConfigService.getTradeConfig(); | ||
| 42 | + return success(TradeConfigConvert.INSTANCE.convert(config)); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.config.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; | ||
| 5 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; | ||
| 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 org.hibernate.validator.constraints.Range; | ||
| 10 | + | ||
| 11 | +import javax.validation.constraints.NotEmpty; | ||
| 12 | +import javax.validation.constraints.NotNull; | ||
| 13 | +import javax.validation.constraints.PositiveOrZero; | ||
| 14 | +import java.util.List; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * 交易中心配置 Base VO,提供给添加、修改、详细的子 VO 使用 | ||
| 18 | + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 19 | + */ | ||
| 20 | +@Data | ||
| 21 | +public class TradeConfigBaseVO { | ||
| 22 | + | ||
| 23 | + // ========== 分销相关 ========== | ||
| 24 | + | ||
| 25 | + @Schema(description = "是否启用分佣", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 26 | + @NotNull(message = "是否启用分佣不能为空") | ||
| 27 | + private Boolean brokerageEnabled; | ||
| 28 | + | ||
| 29 | + @Schema(description = "分佣模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 30 | + @NotNull(message = "分佣模式不能为空") | ||
| 31 | + @InEnum(value = BrokerageEnabledConditionEnum.class, message = "分佣模式必须是 {value}") | ||
| 32 | + private Integer brokerageEnabledCondition; | ||
| 33 | + | ||
| 34 | + @Schema(description = "分销关系绑定模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 35 | + @NotNull(message = "分销关系绑定模式不能为空") | ||
| 36 | + @InEnum(value = BrokerageBindModeEnum.class, message = "分销关系绑定模式必须是 {value}") | ||
| 37 | + private Integer brokerageBindMode; | ||
| 38 | + | ||
| 39 | + @Schema(description = "分销海报图地址数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/yudao.jpg]") | ||
| 40 | + private List<String> brokeragePostUrls; | ||
| 41 | + | ||
| 42 | + @Schema(description = "一级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") | ||
| 43 | + @NotNull(message = "一级返佣比例不能为空") | ||
| 44 | + @Range(min = 0, max = 100, message = "一级返佣比例必须在 0 - 100 之间") | ||
| 45 | + private Integer brokerageFirstPercent; | ||
| 46 | + | ||
| 47 | + @Schema(description = "二级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") | ||
| 48 | + @NotNull(message = "二级返佣比例不能为空") | ||
| 49 | + @Range(min = 0, max = 100, message = "二级返佣比例必须在 0 - 100 之间") | ||
| 50 | + private Integer brokerageSecondPercent; | ||
| 51 | + | ||
| 52 | + @Schema(description = "用户提现最低金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") | ||
| 53 | + @NotNull(message = "用户提现最低金额不能为空") | ||
| 54 | + @PositiveOrZero(message = "用户提现最低金额不能是负数") | ||
| 55 | + private Integer brokerageWithdrawMinPrice; | ||
| 56 | + | ||
| 57 | + @Schema(description = "提现银行", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") | ||
| 58 | + @NotEmpty(message = "提现银行不能为空") | ||
| 59 | + private List<Integer> brokerageBankNames; | ||
| 60 | + | ||
| 61 | + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "7") | ||
| 62 | + @NotNull(message = "佣金冻结时间(天)不能为空") | ||
| 63 | + @PositiveOrZero(message = "佣金冻结时间不能是负数") | ||
| 64 | + private Integer brokerageFrozenDays; | ||
| 65 | + | ||
| 66 | + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") | ||
| 67 | + @NotNull(message = "提现方式不能为空") | ||
| 68 | + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") | ||
| 69 | + private List<Integer> brokerageWithdrawType; | ||
| 70 | + | ||
| 71 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.config.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 | +@Schema(description = "管理后台 - 交易中心配置 Response VO") | ||
| 9 | +@Data | ||
| 10 | +@EqualsAndHashCode(callSuper = true) | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class TradeConfigRespVO extends TradeConfigBaseVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 15 | + private Long id; | ||
| 16 | + | ||
| 17 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.config.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 | +@Schema(description = "管理后台 - 交易中心配置更新 Request VO") | ||
| 9 | +@Data | ||
| 10 | +@EqualsAndHashCode(callSuper = true) | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class TradeConfigSaveReqVO extends TradeConfigBaseVO { | ||
| 13 | + | ||
| 14 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
| @@ -67,6 +67,11 @@ public class TradeOrderController { | @@ -67,6 +67,11 @@ public class TradeOrderController { | ||
| 67 | public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { | 67 | public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { |
| 68 | // 查询订单 | 68 | // 查询订单 |
| 69 | TradeOrderDO order = tradeOrderQueryService.getOrder(id); | 69 | TradeOrderDO order = tradeOrderQueryService.getOrder(id); |
| 70 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; | ||
| 71 | +// if (order == null) { | ||
| 72 | +// return success(null, ORDER_NOT_FOUND.getMsg()); | ||
| 73 | +// } | ||
| 74 | + | ||
| 70 | // 查询订单项 | 75 | // 查询订单项 |
| 71 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); | 76 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); |
| 72 | // orderLog | 77 | // orderLog |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java
| @@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { | @@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { | ||
| 26 | private MemberUserRespVO user; | 26 | private MemberUserRespVO user; |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | - * TODO 订单操作日志, 先模拟一波;返回 logs,简洁,然后复数哈 | 29 | + * TODO 订单操作日志, 先模拟一波 |
| 30 | */ | 30 | */ |
| 31 | - private List<OrderLog> orderLog; | 31 | + private List<OrderLog> logs; |
| 32 | 32 | ||
| 33 | - // TODO @puhui999:swagger 注解 | 33 | + @Schema(description = "管理后台 - 交易订单的操作日志") |
| 34 | @Data | 34 | @Data |
| 35 | public static class OrderLog { | 35 | public static class OrderLog { |
| 36 | 36 | ||
| 37 | - /** | ||
| 38 | - * 内容 | ||
| 39 | - */ | 37 | + @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货") |
| 40 | private String content; | 38 | private String content; |
| 41 | 39 | ||
| 42 | - /** | ||
| 43 | - * 创建时间 | ||
| 44 | - */ | 40 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20") |
| 45 | private LocalDateTime createTime; | 41 | private LocalDateTime createTime; |
| 46 | 42 | ||
| 43 | + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 44 | + private Integer userType; | ||
| 45 | + | ||
| 47 | } | 46 | } |
| 48 | 47 | ||
| 49 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") | 48 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO; | ||
| 9 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 10 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | +import org.springframework.validation.annotation.Validated; | ||
| 13 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 14 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 16 | +import org.springframework.web.bind.annotation.RestController; | ||
| 17 | + | ||
| 18 | +import javax.validation.Valid; | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 22 | +import static java.util.Arrays.asList; | ||
| 23 | + | ||
| 24 | +@Tag(name = "用户 APP - 分销用户") | ||
| 25 | +@RestController | ||
| 26 | +@RequestMapping("/trade/brokerage-record") | ||
| 27 | +@Validated | ||
| 28 | +@Slf4j | ||
| 29 | +public class AppBrokerageRecordController { | ||
| 30 | + | ||
| 31 | + // TODO 芋艿:临时 mock => | ||
| 32 | + @GetMapping("/page") | ||
| 33 | + @Operation(summary = "获得分销记录分页") | ||
| 34 | + @PreAuthenticated | ||
| 35 | + public CommonResult<PageResult<AppBrokerageRecordRespVO>> getBrokerageRecordPage(@Valid AppBrokerageRecordPageReqVO pageReqVO) { | ||
| 36 | + AppBrokerageRecordRespVO vo1 = new AppBrokerageRecordRespVO() | ||
| 37 | + .setId(1L).setPrice(10).setTitle("收到钱").setCreateTime(LocalDateTime.now()) | ||
| 38 | + .setFinishTime(LocalDateTime.now()); | ||
| 39 | + AppBrokerageRecordRespVO vo2 = new AppBrokerageRecordRespVO() | ||
| 40 | + .setId(2L).setPrice(-20).setTitle("提现钱").setCreateTime(LocalDateTime.now()) | ||
| 41 | + .setFinishTime(LocalDateTime.now()); | ||
| 42 | + return success(new PageResult<>(asList(vo1, vo2), 10L)); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @GetMapping("/get-product-brokerage-price") | ||
| 46 | + @Operation(summary = "获得商品的分销金额") | ||
| 47 | + public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) { | ||
| 48 | + AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO(); | ||
| 49 | + respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销 | ||
| 50 | + respVO.setBrokerageMinPrice(1); | ||
| 51 | + respVO.setBrokerageMaxPrice(2); | ||
| 52 | + return success(respVO); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*; | ||
| 7 | +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; | ||
| 8 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 9 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 10 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 13 | +import org.springframework.validation.annotation.Validated; | ||
| 14 | +import org.springframework.web.bind.annotation.*; | ||
| 15 | + | ||
| 16 | +import javax.annotation.Resource; | ||
| 17 | +import javax.validation.Valid; | ||
| 18 | +import java.time.LocalDateTime; | ||
| 19 | + | ||
| 20 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 21 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 22 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||
| 23 | +import static java.util.Arrays.asList; | ||
| 24 | + | ||
| 25 | +@Tag(name = "用户 APP - 分销用户") | ||
| 26 | +@RestController | ||
| 27 | +@RequestMapping("/trade/brokerage-user") | ||
| 28 | +@Validated | ||
| 29 | +@Slf4j | ||
| 30 | +public class AppBrokerageUserController { | ||
| 31 | + @Resource | ||
| 32 | + private BrokerageUserService brokerageUserService; | ||
| 33 | + | ||
| 34 | + // TODO 芋艿:临时 mock => | ||
| 35 | + @GetMapping("/get") | ||
| 36 | + @Operation(summary = "获得个人分销信息") | ||
| 37 | + @PreAuthenticated | ||
| 38 | + public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() { | ||
| 39 | + AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO() | ||
| 40 | + .setBrokerageEnabled(true) | ||
| 41 | + .setPrice(2000) | ||
| 42 | + .setFrozenPrice(3000); | ||
| 43 | + return success(respVO); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @PutMapping("/bind") | ||
| 47 | + @Operation(summary = "绑定推广员") | ||
| 48 | + @PreAuthenticated | ||
| 49 | + public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) { | ||
| 50 | + return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId(), false)); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + // TODO 芋艿:临时 mock => | ||
| 54 | + @GetMapping("/get-summary") | ||
| 55 | + @Operation(summary = "获得个人分销统计") | ||
| 56 | + @PreAuthenticated | ||
| 57 | + public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() { | ||
| 58 | + AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO() | ||
| 59 | + .setYesterdayPrice(1) | ||
| 60 | + .setBrokeragePrice(2) | ||
| 61 | + .setFrozenPrice(3) | ||
| 62 | + .setWithdrawPrice(4) | ||
| 63 | + .setFirstBrokerageUserCount(166) | ||
| 64 | + .setSecondBrokerageUserCount(233); | ||
| 65 | + return success(respVO); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // TODO 芋艿:临时 mock => | ||
| 69 | + @GetMapping("/rank-page-by-user-count") | ||
| 70 | + @Operation(summary = "获得分销用户排行分页(基于用户量)") | ||
| 71 | + @PreAuthenticated | ||
| 72 | + public CommonResult<PageResult<AppBrokerageUserRankByUserCountRespVO>> getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO) { | ||
| 73 | + AppBrokerageUserRankByUserCountRespVO vo1 = new AppBrokerageUserRankByUserCountRespVO() | ||
| 74 | + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 75 | + .setBrokerageUserCount(10); | ||
| 76 | + AppBrokerageUserRankByUserCountRespVO vo2 = new AppBrokerageUserRankByUserCountRespVO() | ||
| 77 | + .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 78 | + .setBrokerageUserCount(6); | ||
| 79 | + AppBrokerageUserRankByUserCountRespVO vo3 = new AppBrokerageUserRankByUserCountRespVO() | ||
| 80 | + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 81 | + .setBrokerageUserCount(4); | ||
| 82 | + AppBrokerageUserRankByUserCountRespVO vo4 = new AppBrokerageUserRankByUserCountRespVO() | ||
| 83 | + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 84 | + .setBrokerageUserCount(4); | ||
| 85 | + return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L)); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + // TODO 芋艿:临时 mock => | ||
| 89 | + @GetMapping("/rank-page-by-price") | ||
| 90 | + @Operation(summary = "获得分销用户排行分页(基于佣金)") | ||
| 91 | + @PreAuthenticated | ||
| 92 | + public CommonResult<PageResult<AppBrokerageUserRankByPriceRespVO>> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) { | ||
| 93 | + AppBrokerageUserRankByPriceRespVO vo1 = new AppBrokerageUserRankByPriceRespVO() | ||
| 94 | + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 95 | + .setBrokeragePrice(10); | ||
| 96 | + AppBrokerageUserRankByPriceRespVO vo2 = new AppBrokerageUserRankByPriceRespVO() | ||
| 97 | + .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 98 | + .setBrokeragePrice(6); | ||
| 99 | + AppBrokerageUserRankByPriceRespVO vo3 = new AppBrokerageUserRankByPriceRespVO() | ||
| 100 | + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 101 | + .setBrokeragePrice(4); | ||
| 102 | + AppBrokerageUserRankByPriceRespVO vo4 = new AppBrokerageUserRankByPriceRespVO() | ||
| 103 | + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 104 | + .setBrokeragePrice(4); | ||
| 105 | + return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L)); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // TODO 芋艿:临时 mock => | ||
| 109 | + @GetMapping("/child-summary-page") | ||
| 110 | + @Operation(summary = "获得下级分销统计分页") | ||
| 111 | + @PreAuthenticated | ||
| 112 | + public CommonResult<PageResult<AppBrokerageUserChildSummaryRespVO>> getBrokerageUserChildSummaryPage( | ||
| 113 | + AppBrokerageUserChildSummaryPageReqVO pageReqVO) { | ||
| 114 | + AppBrokerageUserChildSummaryRespVO vo1 = new AppBrokerageUserChildSummaryRespVO() | ||
| 115 | + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 116 | + .setBrokeragePrice(10).setBrokeragePrice(20).setBrokerageOrderCount(30) | ||
| 117 | + .setBrokerageTime(LocalDateTime.now()); | ||
| 118 | + AppBrokerageUserChildSummaryRespVO vo2 = new AppBrokerageUserChildSummaryRespVO() | ||
| 119 | + .setId(1L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") | ||
| 120 | + .setBrokeragePrice(20).setBrokeragePrice(30).setBrokerageOrderCount(40) | ||
| 121 | + .setBrokerageTime(LocalDateTime.now()); | ||
| 122 | + return success(new PageResult<>(asList(vo1, vo2), 10L)); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + // TODO 芋艿:临时 mock => | ||
| 126 | + @GetMapping("/get-rank-by-price") | ||
| 127 | + @Operation(summary = "获得分销用户排行(基于佣金)") | ||
| 128 | + @Parameter(name = "times", description = "时间段", required = true) | ||
| 129 | + public CommonResult<Integer> bindBrokerageUser( | ||
| 130 | + @RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) { | ||
| 131 | + return success(1); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageWithdrawController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO; | ||
| 8 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 9 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 10 | +import lombok.extern.slf4j.Slf4j; | ||
| 11 | +import org.springframework.validation.annotation.Validated; | ||
| 12 | +import org.springframework.web.bind.annotation.*; | ||
| 13 | + | ||
| 14 | +import javax.validation.Valid; | ||
| 15 | +import java.time.LocalDateTime; | ||
| 16 | + | ||
| 17 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 18 | +import static java.util.Arrays.asList; | ||
| 19 | + | ||
| 20 | +@Tag(name = "用户 APP - 分销提现") | ||
| 21 | +@RestController | ||
| 22 | +@RequestMapping("/trade/brokerage-withdraw") | ||
| 23 | +@Validated | ||
| 24 | +@Slf4j | ||
| 25 | +public class AppBrokerageWithdrawController { | ||
| 26 | + | ||
| 27 | + // TODO 芋艿:临时 mock => | ||
| 28 | + @GetMapping("/page") | ||
| 29 | + @Operation(summary = "获得分销提现分页") | ||
| 30 | + @PreAuthenticated | ||
| 31 | + public CommonResult<PageResult<AppBrokerageWithdrawRespVO>> getBrokerageWithdrawPage() { | ||
| 32 | + AppBrokerageWithdrawRespVO vo1 = new AppBrokerageWithdrawRespVO() | ||
| 33 | + .setId(1L).setStatus(10).setPrice(10).setStatusName("审批通过").setCreateTime(LocalDateTime.now()); | ||
| 34 | + AppBrokerageWithdrawRespVO vo2 = new AppBrokerageWithdrawRespVO() | ||
| 35 | + .setId(2L).setStatus(0).setPrice(20).setStatusName("审批中").setCreateTime(LocalDateTime.now()); | ||
| 36 | + return success(new PageResult<>(asList(vo1, vo2), 10L)); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + // TODO 芋艿:临时 mock => | ||
| 40 | + @PostMapping("/create") | ||
| 41 | + @Operation(summary = "创建分销提现") | ||
| 42 | + @PreAuthenticated | ||
| 43 | + public CommonResult<Long> createBrokerageWithdraw(@RequestBody @Valid AppBrokerageWithdrawCreateReqVO createReqVO) { | ||
| 44 | + return success(1L); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "用户 App - 商品的分销金额 Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class AppBrokerageProductPriceRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "是否开启", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 11 | + private Boolean enabled; | ||
| 12 | + | ||
| 13 | + @Schema(description = "分销最小金额,单位:分", example = "100") | ||
| 14 | + private Integer brokerageMinPrice; | ||
| 15 | + | ||
| 16 | + @Schema(description = "分销最大金额,单位:分", example = "100") | ||
| 17 | + private Integer brokerageMaxPrice; | ||
| 18 | + | ||
| 19 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; | ||
| 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.BrokerageRecordBizTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 7 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +@Schema(description = "应用 App - 分销记录分页 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppBrokerageRecordPageReqVO extends PageParam { | ||
| 13 | + | ||
| 14 | + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 15 | + @InEnum(value = BrokerageRecordBizTypeEnum.class, message = "业务类型必须是 {value}") | ||
| 16 | + private Integer bizType; | ||
| 17 | + | ||
| 18 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 19 | + @InEnum(value = BrokerageRecordStatusEnum.class, message = "状态必须是 {value}") | ||
| 20 | + private Integer status; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +@Schema(description = "用户 App - 分销记录 Response VO") | ||
| 9 | +@Data | ||
| 10 | +public class AppBrokerageRecordRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "分销标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户下单") | ||
| 16 | + private String title; | ||
| 17 | + | ||
| 18 | + @Schema(description = "分销金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") | ||
| 19 | + private Integer price; | ||
| 20 | + | ||
| 21 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 22 | + private LocalDateTime createTime; | ||
| 23 | + | ||
| 24 | + @Schema(description = "完成时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 25 | + private LocalDateTime finishTime; | ||
| 26 | + | ||
| 27 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotNull; | ||
| 8 | + | ||
| 9 | +@Schema(description = "应用 App - 绑定推广员 Request VO") | ||
| 10 | +@Data | ||
| 11 | +public class AppBrokerageUserBindReqVO extends PageParam { | ||
| 12 | + | ||
| 13 | + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 14 | + @NotNull(message = "推广员编号不能为空") | ||
| 15 | + private Long bindUserId; | ||
| 16 | + | ||
| 17 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.SortingField; | ||
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | +@Schema(description = "用户 App - 下级分销统计分页 Request VO") | ||
| 9 | +@Data | ||
| 10 | +public class AppBrokerageUserChildSummaryPageReqVO extends PageParam { | ||
| 11 | + | ||
| 12 | + public static final String SORT_FIELD_USER_COUNT = "userCount"; | ||
| 13 | + public static final String SORT_FIELD_ORDER_COUNT = "orderCount"; | ||
| 14 | + public static final String SORT_FIELD_PRICE = "price"; | ||
| 15 | + | ||
| 16 | + @Schema(description = "用户昵称", example = "李") // 模糊匹配 | ||
| 17 | + private String nickname; | ||
| 18 | + | ||
| 19 | + @Schema(description = "排序字段", example = "userCount") | ||
| 20 | + private SortingField sortingField; | ||
| 21 | + | ||
| 22 | + @Schema(description = "下级的级别", example = "1") // 1 - 直接下级;2 - 间接下级 | ||
| 23 | + private Integer level; | ||
| 24 | + | ||
| 25 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +@Schema(description = "用户 App - 下级分销统计 Response VO") | ||
| 9 | +@Data | ||
| 10 | +public class AppBrokerageUserChildSummaryRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") | ||
| 16 | + private String nickname; | ||
| 17 | + | ||
| 18 | + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") | ||
| 19 | + private String avatar; | ||
| 20 | + | ||
| 21 | + @Schema(description = "佣金金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 22 | + private Integer brokeragePrice; | ||
| 23 | + | ||
| 24 | + @Schema(description = "分销订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") | ||
| 25 | + private Integer brokerageOrderCount; | ||
| 26 | + | ||
| 27 | + @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") | ||
| 28 | + private Integer brokerageUserCount; | ||
| 29 | + | ||
| 30 | + @Schema(description = "成为分销员时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 31 | + private LocalDateTime brokerageTime; | ||
| 32 | + | ||
| 33 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "用户 App - 个人分销统计 Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class AppBrokerageUserMySummaryRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "昨天的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 11 | + private Integer yesterdayPrice; | ||
| 12 | + | ||
| 13 | + @Schema(description = "提现的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 14 | + private Integer withdrawPrice; | ||
| 15 | + | ||
| 16 | + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") | ||
| 17 | + private Integer brokeragePrice; | ||
| 18 | + | ||
| 19 | + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") | ||
| 20 | + private Integer frozenPrice; | ||
| 21 | + | ||
| 22 | + @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 23 | + private Integer firstBrokerageUserCount; | ||
| 24 | + | ||
| 25 | + @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 26 | + private Integer secondBrokerageUserCount; | ||
| 27 | + | ||
| 28 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class AppBrokerageUserRankByPriceRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 11 | + private Long id; | ||
| 12 | + | ||
| 13 | + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") | ||
| 14 | + private String nickname; | ||
| 15 | + | ||
| 16 | + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") | ||
| 17 | + private String avatar; | ||
| 18 | + | ||
| 19 | + @Schema(description = "佣金金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 20 | + private Integer brokeragePrice; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByUserCountRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class AppBrokerageUserRankByUserCountRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 11 | + private Long id; | ||
| 12 | + | ||
| 13 | + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") | ||
| 14 | + private String nickname; | ||
| 15 | + | ||
| 16 | + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") | ||
| 17 | + private String avatar; | ||
| 18 | + | ||
| 19 | + @Schema(description = "邀请用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 20 | + private Integer brokerageUserCount; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 7 | + | ||
| 8 | +import javax.validation.constraints.NotEmpty; | ||
| 9 | +import java.time.LocalDateTime; | ||
| 10 | + | ||
| 11 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 12 | + | ||
| 13 | +@Schema(description = "应用 App - 分销用户排行 Request VO") | ||
| 14 | +@Data | ||
| 15 | +public class AppBrokerageUserRankPageReqVO extends PageParam { | ||
| 16 | + | ||
| 17 | + @Schema(description = "开始 + 结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 18 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 19 | + @NotEmpty(message = "时间不能为空") | ||
| 20 | + private LocalDateTime[] times; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "用户 App - 分销用户信息 Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class AppBrokerageUserRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "是否有分销资格", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 11 | + private Boolean brokerageEnabled; | ||
| 12 | + | ||
| 13 | + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") | ||
| 14 | + private Integer price; | ||
| 15 | + | ||
| 16 | + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") | ||
| 17 | + private Integer frozenPrice; | ||
| 18 | + | ||
| 19 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | ||
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 5 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; | ||
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.hibernate.validator.constraints.URL; | ||
| 9 | + | ||
| 10 | +import javax.validation.Validator; | ||
| 11 | +import javax.validation.constraints.Min; | ||
| 12 | +import javax.validation.constraints.NotBlank; | ||
| 13 | + | ||
| 14 | +@Schema(description = "用户 App - 分销提现创建 Request VO") | ||
| 15 | +@Data | ||
| 16 | +public class AppBrokerageWithdrawCreateReqVO { | ||
| 17 | + | ||
| 18 | + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 19 | + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") | ||
| 20 | + private Integer type; | ||
| 21 | + | ||
| 22 | + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") | ||
| 23 | + @Min(value = 1, message = "提现金额不能小于 1") | ||
| 24 | + private Integer price; | ||
| 25 | + | ||
| 26 | + // ========== 银行卡、微信、支付宝 提现相关字段 ========== | ||
| 27 | + | ||
| 28 | + @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") | ||
| 29 | + @NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class}) | ||
| 30 | + private String accountNo; | ||
| 31 | + | ||
| 32 | + // ========== 微信、支付宝 提现相关字段 ========== | ||
| 33 | + | ||
| 34 | + @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png") | ||
| 35 | + @URL(message = "收款码的图片,必须是一个 URL") | ||
| 36 | + private String accountQrCodeUrl; | ||
| 37 | + | ||
| 38 | + // ========== 银行卡 提现相关字段 ========== | ||
| 39 | + | ||
| 40 | + @Schema(description = "持卡人姓名", example = "张三") | ||
| 41 | + @NotBlank(message = "持卡人姓名不能为空", groups = {Bank.class}) | ||
| 42 | + private String name; | ||
| 43 | + @Schema(description = "提现银行", example = "1") | ||
| 44 | + @NotBlank(message = "提现银行不能为空", groups = {Bank.class}) | ||
| 45 | + private Integer bankName; | ||
| 46 | + @Schema(description = "开户地址", example = "海淀支行") | ||
| 47 | + private String bankAddress; | ||
| 48 | + | ||
| 49 | + public interface Wallet { | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public interface Bank { | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public interface Wechat { | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public interface Alipay { | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void validate(Validator validator) { | ||
| 62 | + if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(type)) { | ||
| 63 | + ValidationUtils.validate(validator, this, Wallet.class); | ||
| 64 | + } else if (BrokerageWithdrawTypeEnum.BANK.getType().equals(type)) { | ||
| 65 | + ValidationUtils.validate(validator, this, Bank.class); | ||
| 66 | + } else if (BrokerageWithdrawTypeEnum.WECHAT.getType().equals(type)) { | ||
| 67 | + ValidationUtils.validate(validator, this, Wechat.class); | ||
| 68 | + } else if (BrokerageWithdrawTypeEnum.ALIPAY.getType().equals(type)) { | ||
| 69 | + ValidationUtils.validate(validator, this, Alipay.class); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +@Schema(description = "用户 App - 分销提现 Response VO") | ||
| 9 | +@Data | ||
| 10 | +public class AppBrokerageWithdrawRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "提现编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 16 | + private Integer status; | ||
| 17 | + | ||
| 18 | + @Schema(description = "提现状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "审核中") | ||
| 19 | + private String statusName; | ||
| 20 | + | ||
| 21 | + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") | ||
| 22 | + private Integer price; | ||
| 23 | + | ||
| 24 | + @Schema(description = "提现时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 25 | + private LocalDateTime createTime; | ||
| 26 | + | ||
| 27 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/AppTradeConfigController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.app.config.vo.AppTradeConfigRespVO; | ||
| 5 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 6 | +import lombok.RequiredArgsConstructor; | ||
| 7 | +import lombok.extern.slf4j.Slf4j; | ||
| 8 | +import org.springframework.validation.annotation.Validated; | ||
| 9 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 10 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 11 | +import org.springframework.web.bind.annotation.RestController; | ||
| 12 | + | ||
| 13 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 14 | +import static java.util.Arrays.asList; | ||
| 15 | + | ||
| 16 | +@Tag(name = "用户 App - 交易配置") | ||
| 17 | +@RestController | ||
| 18 | +@RequestMapping("/trade/config") | ||
| 19 | +@RequiredArgsConstructor | ||
| 20 | +@Validated | ||
| 21 | +@Slf4j | ||
| 22 | +public class AppTradeConfigController { | ||
| 23 | + | ||
| 24 | + @GetMapping("/get") | ||
| 25 | + public CommonResult<AppTradeConfigRespVO> getTradeConfig() { | ||
| 26 | + AppTradeConfigRespVO respVO = new AppTradeConfigRespVO(); | ||
| 27 | + respVO.setBrokeragePosterUrls(asList( | ||
| 28 | + "https://api.java.crmeb.net/crmebimage/product/2020/08/03/755bf516b1ca4b6db3bfeaa4dd5901cdh71kob20re.jpg", | ||
| 29 | + "https://api.java.crmeb.net/crmebimage/maintain/2021/03/01/406d729b84ed4ec9a2171bfcf6fd0634ughzbz9kfi.jpg", | ||
| 30 | + "https://api.java.crmeb.net/crmebimage/maintain/2021/03/01/efb1e4e7fe604fe1988b4213ce08cb11tdsyijtd2r.jpg" | ||
| 31 | + )); | ||
| 32 | + respVO.setBrokerageFrozenDays(10); | ||
| 33 | + respVO.setBrokerageWithdrawMinPrice(100); | ||
| 34 | + return success(respVO); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/vo/AppTradeConfigRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.config.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +@Schema(description = "用户 App - 交易配置 Response VO") | ||
| 9 | +@Data | ||
| 10 | +public class AppTradeConfigRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "分销海报地址数组", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 13 | + private List<String> brokeragePosterUrls; | ||
| 14 | + | ||
| 15 | + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 16 | + private Integer brokerageFrozenDays; | ||
| 17 | + | ||
| 18 | + @Schema(description = "佣金提现最小金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | ||
| 19 | + private Integer brokerageWithdrawMinPrice; | ||
| 20 | + | ||
| 21 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/config/AppDeliveryConfigRespVO.java
| @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.config; | @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.config; | ||
| 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 | -// TODO 芋艿:后续要实现下,配送配置 | 6 | +// TODO 芋艿:后续要实现下,配送配置;后续融合到 AppTradeConfigRespVO 中 |
| 7 | @Schema(description = "用户 App - 配送配置 Response VO") | 7 | @Schema(description = "用户 App - 配送配置 Response VO") |
| 8 | @Data | 8 | @Data |
| 9 | public class AppDeliveryConfigRespVO { | 9 | public class AppDeliveryConfigRespVO { |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | 5 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; |
| 7 | -import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; | ||
| 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; | 7 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; |
| 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; | 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; |
| 10 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; | 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; |
| @@ -82,9 +81,10 @@ public class AppTradeOrderController { | @@ -82,9 +81,10 @@ public class AppTradeOrderController { | ||
| 82 | public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) { | 81 | public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) { |
| 83 | // 查询订单 | 82 | // 查询订单 |
| 84 | TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); | 83 | TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); |
| 85 | - if (order == null) { | ||
| 86 | - return success(null); | ||
| 87 | - } | 84 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; |
| 85 | +// if (order == null) { | ||
| 86 | +// return success(null, ORDER_NOT_FOUND.getMsg()); | ||
| 87 | +// } | ||
| 88 | 88 | ||
| 89 | // 查询订单项 | 89 | // 查询订单项 |
| 90 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId()); | 90 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId()); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
| @@ -50,12 +50,18 @@ public class AppTradeOrderSettlementReqVO { | @@ -50,12 +50,18 @@ public class AppTradeOrderSettlementReqVO { | ||
| 50 | private Long seckillActivityId; | 50 | private Long seckillActivityId; |
| 51 | 51 | ||
| 52 | // ========== 拼团活动相关字段 ========== | 52 | // ========== 拼团活动相关字段 ========== |
| 53 | + // TODO @puhui999:是不是拼团记录的编号哈? | ||
| 53 | @Schema(description = "拼团活动编号", example = "1024") | 54 | @Schema(description = "拼团活动编号", example = "1024") |
| 54 | private Long combinationActivityId; | 55 | private Long combinationActivityId; |
| 55 | 56 | ||
| 56 | @Schema(description = "拼团团长编号", example = "2048") | 57 | @Schema(description = "拼团团长编号", example = "2048") |
| 57 | private Long combinationHeadId; | 58 | private Long combinationHeadId; |
| 58 | 59 | ||
| 60 | + // ========== 砍价活动相关字段 ========== | ||
| 61 | + // TODO @puhui999:是不是砍价记录的编号哈? | ||
| 62 | + @Schema(description = "砍价活动编号", example = "123") | ||
| 63 | + private Long bargainActivityId; | ||
| 64 | + | ||
| 59 | @Data | 65 | @Data |
| 60 | @Schema(description = "用户 App - 商品项") | 66 | @Schema(description = "用户 App - 商品项") |
| 61 | @Valid | 67 | @Valid |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java
| @@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert { | @@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert { | ||
| 78 | // 处理订单信息 | 78 | // 处理订单信息 |
| 79 | respVO.setOrder(convert(order)); | 79 | respVO.setOrder(convert(order)); |
| 80 | // 处理售后日志 | 80 | // 处理售后日志 |
| 81 | - respVO.setAfterSaleLog(convertList1(logs)); | 81 | + respVO.setLogs(convertList1(logs)); |
| 82 | return respVO; | 82 | return respVO; |
| 83 | } | 83 | } |
| 84 | List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list); | 84 | List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.convert.brokerage.record; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.ObjectUtil; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 10 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 11 | +import org.mapstruct.Mapper; | ||
| 12 | +import org.mapstruct.factory.Mappers; | ||
| 13 | + | ||
| 14 | +import java.time.LocalDateTime; | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 佣金记录 Convert | ||
| 19 | + * | ||
| 20 | + * @author owen | ||
| 21 | + */ | ||
| 22 | +@Mapper | ||
| 23 | +public interface BrokerageRecordConvert { | ||
| 24 | + | ||
| 25 | + BrokerageRecordConvert INSTANCE = Mappers.getMapper(BrokerageRecordConvert.class); | ||
| 26 | + | ||
| 27 | + BrokerageRecordRespVO convert(BrokerageRecordDO bean); | ||
| 28 | + | ||
| 29 | + List<BrokerageRecordRespVO> convertList(List<BrokerageRecordDO> list); | ||
| 30 | + | ||
| 31 | + PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page); | ||
| 32 | + | ||
| 33 | + // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》 | ||
| 34 | + default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, | ||
| 35 | + Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, | ||
| 36 | + String title) { | ||
| 37 | + brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); | ||
| 38 | + // 不冻结时,佣金直接就是结算状态 | ||
| 39 | + Integer status = brokerageFrozenDays > 0 | ||
| 40 | + ? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus() | ||
| 41 | + : BrokerageRecordStatusEnum.SETTLEMENT.getStatus(); | ||
| 42 | + return new BrokerageRecordDO().setUserId(user.getId()) | ||
| 43 | + .setBizType(bizType.getType()).setBizId(bizId) | ||
| 44 | + .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice()) | ||
| 45 | + .setTitle(title) | ||
| 46 | + .setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokeragePrice / 100.0))) | ||
| 47 | + .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.convert.brokerage.user; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.map.MapUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 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; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; | ||
| 10 | +import org.mapstruct.Mapper; | ||
| 11 | +import org.mapstruct.factory.Mappers; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | +import java.util.Optional; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 分销用户 Convert | ||
| 19 | + * | ||
| 20 | + * @author owen | ||
| 21 | + */ | ||
| 22 | +@Mapper | ||
| 23 | +public interface BrokerageUserConvert { | ||
| 24 | + | ||
| 25 | + BrokerageUserConvert INSTANCE = Mappers.getMapper(BrokerageUserConvert.class); | ||
| 26 | + | ||
| 27 | + BrokerageUserRespVO convert(BrokerageUserDO bean); | ||
| 28 | + | ||
| 29 | + List<BrokerageUserRespVO> convertList(List<BrokerageUserDO> list); | ||
| 30 | + | ||
| 31 | + PageResult<BrokerageUserRespVO> convertPage(PageResult<BrokerageUserDO> page); | ||
| 32 | + | ||
| 33 | + default PageResult<BrokerageUserRespVO> convertPage(PageResult<BrokerageUserDO> pageResult, | ||
| 34 | + Map<Long, MemberUserRespDTO> userMap, | ||
| 35 | + Map<Long, Long> brokerageUserCountMap, | ||
| 36 | + Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap) { | ||
| 37 | + PageResult<BrokerageUserRespVO> result = convertPage(pageResult); | ||
| 38 | + for (BrokerageUserRespVO vo : result.getList()) { | ||
| 39 | + // 用户信息 | ||
| 40 | + Optional.ofNullable(userMap.get(vo.getId())).ifPresent( | ||
| 41 | + user -> vo.setNickname(user.getNickname()).setAvatar(user.getAvatar())); | ||
| 42 | + // 推广用户数量(一级) | ||
| 43 | + vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0)); | ||
| 44 | + // 推广订单数量、推广订单金额 | ||
| 45 | + Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId())); | ||
| 46 | + vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0)) | ||
| 47 | + .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0)); | ||
| 48 | + // todo 已提现次数、已提现金额 | ||
| 49 | + vo.setWithdrawCount(0); | ||
| 50 | + vo.setWithdrawPrice(0); | ||
| 51 | + } | ||
| 52 | + return result; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser); | ||
| 56 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/config/TradeConfigConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.convert.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 6 | +import org.mapstruct.Mapper; | ||
| 7 | +import org.mapstruct.factory.Mappers; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 交易中心配置 Convert | ||
| 11 | + * | ||
| 12 | + * @author owen | ||
| 13 | + */ | ||
| 14 | +@Mapper | ||
| 15 | +public interface TradeConfigConvert { | ||
| 16 | + | ||
| 17 | + TradeConfigConvert INSTANCE = Mappers.getMapper(TradeConfigConvert.class); | ||
| 18 | + | ||
| 19 | + TradeConfigDO convert(TradeConfigSaveReqVO bean); | ||
| 20 | + | ||
| 21 | + TradeConfigRespVO convert(TradeConfigDO bean); | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| @@ -7,11 +7,13 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils; | @@ -7,11 +7,13 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils; | ||
| 7 | import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; | 7 | import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; |
| 8 | import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | 8 | import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; |
| 9 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | 9 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 10 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 10 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | 11 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; |
| 11 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | 12 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 12 | import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; | 13 | import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; |
| 13 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; | 14 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; |
| 14 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | 15 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; |
| 16 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 15 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | 17 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; |
| 16 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; | 18 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 17 | import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; | 19 | import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; |
| @@ -93,6 +95,7 @@ public interface TradeOrderConvert { | @@ -93,6 +95,7 @@ public interface TradeOrderConvert { | ||
| 93 | items.forEach(item -> item.setIncrCount(-item.getIncrCount())); | 95 | items.forEach(item -> item.setIncrCount(-item.getIncrCount())); |
| 94 | return new ProductSkuUpdateStockReqDTO(items); | 96 | return new ProductSkuUpdateStockReqDTO(items); |
| 95 | } | 97 | } |
| 98 | + | ||
| 96 | List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); | 99 | List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); |
| 97 | 100 | ||
| 98 | @Mappings({ | 101 | @Mappings({ |
| @@ -151,9 +154,10 @@ public interface TradeOrderConvert { | @@ -151,9 +154,10 @@ public interface TradeOrderConvert { | ||
| 151 | TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog(); | 154 | TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog(); |
| 152 | orderLog.setContent("订单操作" + i); | 155 | orderLog.setContent("订单操作" + i); |
| 153 | orderLog.setCreateTime(LocalDateTime.now()); | 156 | orderLog.setCreateTime(LocalDateTime.now()); |
| 157 | + orderLog.setUserType(i % 2 == 0 ? 2 : 1); | ||
| 154 | orderLogs.add(orderLog); | 158 | orderLogs.add(orderLog); |
| 155 | } | 159 | } |
| 156 | - orderVO.setOrderLog(orderLogs); | 160 | + orderVO.setLogs(orderLogs); |
| 157 | return orderVO; | 161 | return orderVO; |
| 158 | } | 162 | } |
| 159 | 163 | ||
| @@ -273,4 +277,10 @@ public interface TradeOrderConvert { | @@ -273,4 +277,10 @@ public interface TradeOrderConvert { | ||
| 273 | 277 | ||
| 274 | TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); | 278 | TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); |
| 275 | 279 | ||
| 280 | + default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) { | ||
| 281 | + return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())) | ||
| 282 | + .setBasePrice(item.getPayPrice() * item.getCount()) | ||
| 283 | + .setFirstFixedPrice(sku.getSubCommissionFirstPrice()) | ||
| 284 | + .setSecondFixedPrice(sku.getSubCommissionSecondPrice()); | ||
| 285 | + } | ||
| 276 | } | 286 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 5 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 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 owen | ||
| 17 | + */ | ||
| 18 | +@TableName("trade_brokerage_record") | ||
| 19 | +@KeySequence("trade_brokerage_record_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 BrokerageRecordDO extends BaseDO { | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 编号 | ||
| 30 | + */ | ||
| 31 | + @TableId | ||
| 32 | + private Integer id; | ||
| 33 | + /** | ||
| 34 | + * 用户编号 | ||
| 35 | + */ | ||
| 36 | + private Long userId; | ||
| 37 | + /** | ||
| 38 | + * 业务编号 | ||
| 39 | + */ | ||
| 40 | + private String bizId; | ||
| 41 | + /** | ||
| 42 | + * 业务类型 | ||
| 43 | + * <p> | ||
| 44 | + * 枚举 {@link BrokerageRecordBizTypeEnum} | ||
| 45 | + */ | ||
| 46 | + private Integer bizType; | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 标题 | ||
| 50 | + */ | ||
| 51 | + private String title; | ||
| 52 | + /** | ||
| 53 | + * 说明 | ||
| 54 | + */ | ||
| 55 | + private String description; | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 金额 | ||
| 59 | + */ | ||
| 60 | + private Integer price; | ||
| 61 | + /** | ||
| 62 | + * 当前总佣金 | ||
| 63 | + */ | ||
| 64 | + private Integer totalPrice; | ||
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * 状态 | ||
| 68 | + * <p> | ||
| 69 | + * 枚举 {@link BrokerageRecordStatusEnum} | ||
| 70 | + */ | ||
| 71 | + private Integer status; | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 冻结时间(天) | ||
| 75 | + */ | ||
| 76 | + private Integer frozenDays; | ||
| 77 | + /** | ||
| 78 | + * 解冻时间 | ||
| 79 | + */ | ||
| 80 | + private LocalDateTime unfreezeTime; | ||
| 81 | + | ||
| 82 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/BrokerageUserDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 7 | +import lombok.*; | ||
| 8 | + | ||
| 9 | +import java.time.LocalDateTime; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 分销用户 DO | ||
| 13 | + * | ||
| 14 | + * @author owen | ||
| 15 | + */ | ||
| 16 | +@TableName("trade_brokerage_user") | ||
| 17 | +@KeySequence("trade_brokerage_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 18 | +@Data | ||
| 19 | +@EqualsAndHashCode(callSuper = true) | ||
| 20 | +@ToString(callSuper = true) | ||
| 21 | +@Builder | ||
| 22 | +@NoArgsConstructor | ||
| 23 | +@AllArgsConstructor | ||
| 24 | +public class BrokerageUserDO extends BaseDO { | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 用户编号 | ||
| 28 | + * <p> | ||
| 29 | + * 对应 MemberUserDO 的 id 字段 | ||
| 30 | + */ | ||
| 31 | + @TableId | ||
| 32 | + private Long id; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 推广员编号 | ||
| 36 | + * <p> | ||
| 37 | + * 关联 MemberUserDO 的 id 字段 | ||
| 38 | + */ | ||
| 39 | + private Long bindUserId; | ||
| 40 | + /** | ||
| 41 | + * 推广员绑定时间 | ||
| 42 | + */ | ||
| 43 | + private LocalDateTime bindUserTime; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 是否有分销资格 | ||
| 47 | + */ | ||
| 48 | + private Boolean brokerageEnabled; | ||
| 49 | + /** | ||
| 50 | + * 成为分销员时间 | ||
| 51 | + */ | ||
| 52 | + private LocalDateTime brokerageTime; | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * 可用佣金 | ||
| 56 | + */ | ||
| 57 | + private Integer brokeragePrice; | ||
| 58 | + /** | ||
| 59 | + * 冻结佣金 | ||
| 60 | + */ | ||
| 61 | + private Integer frozenPrice; | ||
| 62 | + | ||
| 63 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.dataobject.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; | ||
| 5 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; | ||
| 7 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 10 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 11 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 12 | +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | ||
| 13 | +import lombok.*; | ||
| 14 | + | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 交易中心配置 DO | ||
| 19 | + * | ||
| 20 | + * @author owen | ||
| 21 | + */ | ||
| 22 | +@TableName(value = "trade_config", autoResultMap = true) | ||
| 23 | +@KeySequence("trade_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 24 | +@Data | ||
| 25 | +@EqualsAndHashCode(callSuper = true) | ||
| 26 | +@ToString(callSuper = true) | ||
| 27 | +@Builder | ||
| 28 | +@NoArgsConstructor | ||
| 29 | +@AllArgsConstructor | ||
| 30 | +public class TradeConfigDO extends BaseDO { | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 自增主键 | ||
| 34 | + */ | ||
| 35 | + @TableId | ||
| 36 | + private Long id; | ||
| 37 | + | ||
| 38 | + // ========== 分销相关 ========== | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 是否启用分佣 | ||
| 42 | + */ | ||
| 43 | + private Boolean brokerageEnabled; | ||
| 44 | + /** | ||
| 45 | + * 分佣模式 | ||
| 46 | + * <p> | ||
| 47 | + * 枚举 {@link BrokerageEnabledConditionEnum 对应的类} | ||
| 48 | + */ | ||
| 49 | + private Integer brokerageEnabledCondition; | ||
| 50 | + /** | ||
| 51 | + * 分销关系绑定模式 | ||
| 52 | + * <p> | ||
| 53 | + * 枚举 {@link BrokerageBindModeEnum 对应的类} | ||
| 54 | + */ | ||
| 55 | + private Integer brokerageBindMode; | ||
| 56 | + /** | ||
| 57 | + * 分销海报图地址数组 | ||
| 58 | + */ | ||
| 59 | + @TableField(typeHandler = JacksonTypeHandler.class) | ||
| 60 | + private List<String> brokeragePostUrls; | ||
| 61 | + /** | ||
| 62 | + * 一级返佣比例 | ||
| 63 | + */ | ||
| 64 | + private Integer brokerageFirstPercent; | ||
| 65 | + /** | ||
| 66 | + * 二级返佣比例 | ||
| 67 | + */ | ||
| 68 | + private Integer brokerageSecondPercent; | ||
| 69 | + /** | ||
| 70 | + * 用户提现最低金额 | ||
| 71 | + */ | ||
| 72 | + private Integer brokerageWithdrawMinPrice; | ||
| 73 | + /** | ||
| 74 | + * 提现银行 | ||
| 75 | + */ | ||
| 76 | + @TableField(typeHandler = IntegerListTypeHandler.class) | ||
| 77 | + private List<Integer> brokerageBankNames; | ||
| 78 | + /** | ||
| 79 | + * 佣金冻结时间(天) | ||
| 80 | + */ | ||
| 81 | + private Integer brokerageFrozenDays; | ||
| 82 | + /** | ||
| 83 | + * 提现方式 | ||
| 84 | + * <p> | ||
| 85 | + * 枚举 {@link BrokerageWithdrawTypeEnum 对应的类} | ||
| 86 | + */ | ||
| 87 | + @TableField(typeHandler = IntegerListTypeHandler.class) | ||
| 88 | + private List<Integer> brokerageWithdrawType; | ||
| 89 | + | ||
| 90 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record; | ||
| 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.record.vo.BrokerageRecordPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; | ||
| 9 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
| 10 | +import org.apache.ibatis.annotations.Mapper; | ||
| 11 | +import org.apache.ibatis.annotations.Param; | ||
| 12 | +import org.apache.ibatis.annotations.Select; | ||
| 13 | + | ||
| 14 | +import java.time.LocalDateTime; | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 佣金记录 Mapper | ||
| 19 | + * | ||
| 20 | + * @author owen | ||
| 21 | + */ | ||
| 22 | +@Mapper | ||
| 23 | +public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { | ||
| 24 | + | ||
| 25 | + default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) { | ||
| 26 | + return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>() | ||
| 27 | + .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) | ||
| 28 | + .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) | ||
| 29 | + .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) | ||
| 30 | + .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) | ||
| 31 | + .orderByDesc(BrokerageRecordDO::getId)); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + default List<BrokerageRecordDO> selectListByStatusAndUnfreezeTimeLt(Integer status, LocalDateTime unfreezeTime) { | ||
| 35 | + return selectList(new LambdaQueryWrapper<BrokerageRecordDO>() | ||
| 36 | + .eq(BrokerageRecordDO::getStatus, status) | ||
| 37 | + .lt(BrokerageRecordDO::getUnfreezeTime, unfreezeTime)); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + default int updateByIdAndStatus(Integer id, Integer status, BrokerageRecordDO updateObj) { | ||
| 41 | + return update(updateObj, new LambdaQueryWrapper<BrokerageRecordDO>() | ||
| 42 | + .eq(BrokerageRecordDO::getId, id) | ||
| 43 | + .eq(BrokerageRecordDO::getStatus, status)); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + default BrokerageRecordDO selectByBizTypeAndBizId(Integer bizType, String bizId) { | ||
| 47 | + return selectOne(BrokerageRecordDO::getBizType, bizType, | ||
| 48 | + BrokerageRecordDO::getBizId, bizId); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + // TODO @疯狂:mysql 关键字,大写哈;这样看起来清晰点;例如说 SELECT COUNT(1) | ||
| 52 | + @Select("select count(1), sum(price) from trade_brokerage_record where user_id = #{userId} and biz_type = #{bizType} and status = #{status}") | ||
| 53 | + UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, | ||
| 54 | + @Param("bizType") Integer bizType, | ||
| 55 | + @Param("status") Integer status); | ||
| 56 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 9 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 10 | +import org.apache.ibatis.annotations.Mapper; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 分销用户 Mapper | ||
| 14 | + * | ||
| 15 | + * @author owen | ||
| 16 | + */ | ||
| 17 | +@Mapper | ||
| 18 | +public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> { | ||
| 19 | + | ||
| 20 | + default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) { | ||
| 21 | + return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>() | ||
| 22 | + .eqIfPresent(BrokerageUserDO::getBindUserId, reqVO.getBindUserId()) | ||
| 23 | + .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) | ||
| 24 | + .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) | ||
| 25 | + .orderByDesc(BrokerageUserDO::getId)); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 更新用户可用佣金(增加) | ||
| 30 | + * | ||
| 31 | + * @param id 用户编号 | ||
| 32 | + * @param incrCount 增加佣金(正数) | ||
| 33 | + */ | ||
| 34 | + default void updatePriceIncr(Long id, Integer incrCount) { | ||
| 35 | + Assert.isTrue(incrCount > 0); | ||
| 36 | + LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 37 | + .setSql(" price = price + " + incrCount) | ||
| 38 | + .eq(BrokerageUserDO::getId, id); | ||
| 39 | + update(null, lambdaUpdateWrapper); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 更新用户可用佣金(减少) | ||
| 44 | + * 注意:理论上佣金可能已经提现,这时会扣出负数,确保平台不会造成损失 | ||
| 45 | + * | ||
| 46 | + * @param id 用户编号 | ||
| 47 | + * @param incrCount 增加佣金(负数) | ||
| 48 | + */ | ||
| 49 | + default void updatePriceDecr(Long id, Integer incrCount) { | ||
| 50 | + Assert.isTrue(incrCount < 0); | ||
| 51 | + LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 52 | + .setSql(" price = price + " + incrCount) // 负数,所以使用 + 号 | ||
| 53 | + .eq(BrokerageUserDO::getId, id); | ||
| 54 | + update(null, lambdaUpdateWrapper); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 更新用户冻结佣金(增加) | ||
| 59 | + * | ||
| 60 | + * @param id 用户编号 | ||
| 61 | + * @param incrCount 增加冻结佣金(正数) | ||
| 62 | + */ | ||
| 63 | + default void updateFrozenPriceIncr(Long id, Integer incrCount) { | ||
| 64 | + Assert.isTrue(incrCount > 0); | ||
| 65 | + LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 66 | + .setSql(" frozen_price = frozen_price + " + incrCount) | ||
| 67 | + .eq(BrokerageUserDO::getId, id); | ||
| 68 | + update(null, lambdaUpdateWrapper); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 更新用户冻结佣金(减少) | ||
| 73 | + * 注意:理论上冻结佣金可能已经解冻,这时会扣出负数,确保平台不会造成损失 | ||
| 74 | + * | ||
| 75 | + * @param id 用户编号 | ||
| 76 | + * @param incrCount 减少冻结佣金(负数) | ||
| 77 | + */ | ||
| 78 | + default void updateFrozenPriceDecr(Long id, Integer incrCount) { | ||
| 79 | + Assert.isTrue(incrCount < 0); | ||
| 80 | + LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 81 | + .setSql(" frozen_price = frozen_price + " + incrCount) // 负数,所以使用 + 号 | ||
| 82 | + .eq(BrokerageUserDO::getId, id); | ||
| 83 | + update(null, lambdaUpdateWrapper); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + /** | ||
| 87 | + * 更新用户冻结佣金(减少), 更新用户佣金(增加) | ||
| 88 | + * | ||
| 89 | + * @param id 用户编号 | ||
| 90 | + * @param incrCount 减少冻结佣金(负数) | ||
| 91 | + * @return 更新条数 | ||
| 92 | + */ | ||
| 93 | + default int updateFrozenPriceDecrAndPriceIncr(Long id, Integer incrCount) { | ||
| 94 | + Assert.isTrue(incrCount < 0); | ||
| 95 | + LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 96 | + .setSql(" frozen_price = frozen_price + " + incrCount + // 负数,所以使用 + 号 | ||
| 97 | + ", price = price + " + -incrCount) // 负数,所以使用 - 号 | ||
| 98 | + .eq(BrokerageUserDO::getId, id) | ||
| 99 | + .ge(BrokerageUserDO::getFrozenPrice, -incrCount); // cas 逻辑 | ||
| 100 | + return update(null, lambdaUpdateWrapper); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + default void updateBindUserIdAndBindUserTimeToNull(Long id) { | ||
| 104 | + update(null, new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 105 | + .eq(BrokerageUserDO::getId, id) | ||
| 106 | + .set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null)); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + default void updateEnabledFalseAndBrokerageTimeToNull(Long id) { | ||
| 110 | + update(null, new LambdaUpdateWrapper<BrokerageUserDO>() | ||
| 111 | + .eq(BrokerageUserDO::getId, id) | ||
| 112 | + .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/config/TradeConfigMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.mysql.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 5 | +import org.apache.ibatis.annotations.Mapper; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 交易中心配置 Mapper | ||
| 9 | + * | ||
| 10 | + * @author owen | ||
| 11 | + */ | ||
| 12 | +@Mapper | ||
| 13 | +public interface TradeConfigMapper extends BaseMapperX<TradeConfigDO> { | ||
| 14 | + | ||
| 15 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.redis.no; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.date.DatePattern; | ||
| 4 | +import cn.hutool.core.date.DateUtil; | ||
| 5 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 6 | +import org.springframework.stereotype.Repository; | ||
| 7 | + | ||
| 8 | +import javax.annotation.Resource; | ||
| 9 | +import java.time.LocalDateTime; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 订单序号的 Redis DAO | ||
| 13 | + * | ||
| 14 | + * @author HUIHUI | ||
| 15 | + */ | ||
| 16 | +@Repository | ||
| 17 | +public class TradeOrderNoRedisDAO { | ||
| 18 | + | ||
| 19 | + public static final String TRADE_ORDER_NO_PREFIX = "O"; | ||
| 20 | + | ||
| 21 | + @Resource | ||
| 22 | + private StringRedisTemplate stringRedisTemplate; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 生成序号 | ||
| 26 | + * | ||
| 27 | + * @param prefix 前缀 | ||
| 28 | + * @return 序号 | ||
| 29 | + */ | ||
| 30 | + public String generate(String prefix) { | ||
| 31 | + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); | ||
| 32 | + Long no = stringRedisTemplate.opsForValue().increment(noPrefix); | ||
| 33 | + return noPrefix + no; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/brokerage/BrokerageRecordUnfreezeJob.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.job.brokerage; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||
| 5 | +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; | ||
| 6 | +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 佣金解冻 Job | ||
| 13 | + * | ||
| 14 | + * @author owen | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@TenantJob | ||
| 18 | +public class BrokerageRecordUnfreezeJob implements JobHandler { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private BrokerageRecordService brokerageRecordService; | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public String execute(String param) { | ||
| 25 | + int count = brokerageRecordService.unfreezeRecord(); | ||
| 26 | + return StrUtil.format("解冻佣金 {} 个", count); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/package-info.java
0 → 100644
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
| @@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa | @@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa | ||
| 90 | 90 | ||
| 91 | @Override | 91 | @Override |
| 92 | public TradeAfterSaleDO getAfterSale(Long id) { | 92 | public TradeAfterSaleDO getAfterSale(Long id) { |
| 93 | - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); | ||
| 94 | - // TODO @puhui999;读不到,不要这里报错哈;交给前端报错;一般是读取信息不到,message 提示,然后 close tab; | ||
| 95 | - if (afterSale == null) { | ||
| 96 | - throw exception(AFTER_SALE_NOT_FOUND); | ||
| 97 | - } | ||
| 98 | - return afterSale; | 93 | + return tradeAfterSaleMapper.selectById(id); |
| 99 | } | 94 | } |
| 100 | 95 | ||
| 101 | // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑? | 96 | // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑? |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.bo; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotBlank; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 佣金 增加 Request BO | ||
| 12 | + * | ||
| 13 | + * @author owen | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@NoArgsConstructor | ||
| 17 | +@AllArgsConstructor | ||
| 18 | +public class BrokerageAddReqBO { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 业务编号 | ||
| 22 | + */ | ||
| 23 | + @NotBlank(message = "业务编号不能为空") | ||
| 24 | + private String bizId; | ||
| 25 | + /** | ||
| 26 | + * 佣金基数 | ||
| 27 | + */ | ||
| 28 | + @NotNull(message = "佣金基数不能为空") | ||
| 29 | + private Integer basePrice; | ||
| 30 | + /** | ||
| 31 | + * 一级佣金(固定) | ||
| 32 | + */ | ||
| 33 | + private Integer firstFixedPrice; | ||
| 34 | + /** | ||
| 35 | + * 二级佣金(固定) | ||
| 36 | + */ | ||
| 37 | + private Integer secondFixedPrice; | ||
| 38 | + | ||
| 39 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.bo; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 用户佣金合计 BO | ||
| 9 | + * | ||
| 10 | + * @author owen | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +@NoArgsConstructor | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +public class UserBrokerageSummaryBO { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 佣金数量 | ||
| 19 | + */ | ||
| 20 | + private Integer count; | ||
| 21 | + /** | ||
| 22 | + * 佣金总额 | ||
| 23 | + */ | ||
| 24 | + private Integer price; | ||
| 25 | + | ||
| 26 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.record; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 7 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; | ||
| 9 | + | ||
| 10 | +import javax.validation.Valid; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 佣金记录 Service 接口 | ||
| 15 | + * | ||
| 16 | + * @author owen | ||
| 17 | + */ | ||
| 18 | +public interface BrokerageRecordService { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 获得佣金记录 | ||
| 22 | + * | ||
| 23 | + * @param id 编号 | ||
| 24 | + * @return 佣金记录 | ||
| 25 | + */ | ||
| 26 | + BrokerageRecordDO getBrokerageRecord(Integer id); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 获得佣金记录分页 | ||
| 30 | + * | ||
| 31 | + * @param pageReqVO 分页查询 | ||
| 32 | + * @return 佣金记录分页 | ||
| 33 | + */ | ||
| 34 | + PageResult<BrokerageRecordDO> getBrokerageRecordPage(BrokerageRecordPageReqVO pageReqVO); | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 增加佣金 | ||
| 38 | + * | ||
| 39 | + * @param userId 会员编号 | ||
| 40 | + * @param bizType 业务类型 | ||
| 41 | + * @param list 请求参数列表 | ||
| 42 | + */ | ||
| 43 | + void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, @Valid List<BrokerageAddReqBO> list); | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 取消佣金:将佣金记录,状态修改为已失效 | ||
| 47 | + * | ||
| 48 | + * @param userId 会员编号 | ||
| 49 | + * @param bizType 业务类型 | ||
| 50 | + * @param bizId 业务编号 | ||
| 51 | + */ | ||
| 52 | + void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId); | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * 解冻佣金:将待结算的佣金记录,状态修改为已结算 | ||
| 56 | + * | ||
| 57 | + * @return 解冻佣金的数量 | ||
| 58 | + */ | ||
| 59 | + int unfreezeRecord(); | ||
| 60 | + | ||
| 61 | + /** | ||
| 62 | + * 汇总用户佣金 | ||
| 63 | + * | ||
| 64 | + * @param userId 用户编号 | ||
| 65 | + * @param bizType 业务类型 | ||
| 66 | + * @param status 佣金状态 | ||
| 67 | + * @return 用户佣金汇总 | ||
| 68 | + */ | ||
| 69 | + UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status); | ||
| 70 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.record; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.util.BooleanUtil; | ||
| 5 | +import cn.hutool.core.util.ObjectUtil; | ||
| 6 | +import cn.hutool.extra.spring.SpringUtil; | ||
| 7 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 8 | +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||
| 9 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert; | ||
| 11 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; | ||
| 12 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 13 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 14 | +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper; | ||
| 15 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 16 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 17 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 18 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; | ||
| 19 | +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; | ||
| 20 | +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | ||
| 21 | +import lombok.extern.slf4j.Slf4j; | ||
| 22 | +import org.springframework.stereotype.Service; | ||
| 23 | +import org.springframework.transaction.annotation.Transactional; | ||
| 24 | +import org.springframework.validation.annotation.Validated; | ||
| 25 | + | ||
| 26 | +import javax.annotation.Resource; | ||
| 27 | +import java.time.LocalDateTime; | ||
| 28 | +import java.util.ArrayList; | ||
| 29 | +import java.util.List; | ||
| 30 | +import java.util.function.Function; | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * 佣金记录 Service 实现类 | ||
| 34 | + * | ||
| 35 | + * @author owen | ||
| 36 | + */ | ||
| 37 | +@Slf4j | ||
| 38 | +@Service | ||
| 39 | +@Validated | ||
| 40 | +public class BrokerageRecordServiceImpl implements BrokerageRecordService { | ||
| 41 | + | ||
| 42 | + @Resource | ||
| 43 | + private BrokerageRecordMapper brokerageRecordMapper; | ||
| 44 | + @Resource | ||
| 45 | + private TradeConfigService tradeConfigService; | ||
| 46 | + @Resource | ||
| 47 | + private BrokerageUserService brokerageUserService; | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public BrokerageRecordDO getBrokerageRecord(Integer id) { | ||
| 51 | + return brokerageRecordMapper.selectById(id); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public PageResult<BrokerageRecordDO> getBrokerageRecordPage(BrokerageRecordPageReqVO pageReqVO) { | ||
| 56 | + return brokerageRecordMapper.selectPage(pageReqVO); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + @Transactional(rollbackFor = Exception.class) | ||
| 61 | + public void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, List<BrokerageAddReqBO> list) { | ||
| 62 | + TradeConfigDO memberConfig = tradeConfigService.getTradeConfig(); | ||
| 63 | + // 0 未启用分销功能 | ||
| 64 | + if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) { | ||
| 65 | + log.warn("[addBrokerage][增加佣金失败:brokerageEnabled 未配置,userId({})", userId); | ||
| 66 | + return; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 1.1 获得一级推广人 | ||
| 70 | + BrokerageUserDO firstUser = brokerageUserService.getBindBrokerageUser(userId); | ||
| 71 | + if (firstUser == null || !BooleanUtil.isTrue(firstUser.getBrokerageEnabled())) { | ||
| 72 | + return; | ||
| 73 | + } | ||
| 74 | + // 1.2 计算一级分佣 | ||
| 75 | + addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getFirstFixedPrice, bizType); | ||
| 76 | + | ||
| 77 | + // 2.1 获得二级推广员 | ||
| 78 | + if (firstUser.getBindUserId() == null) { | ||
| 79 | + return; | ||
| 80 | + } | ||
| 81 | + BrokerageUserDO secondUser = brokerageUserService.getBrokerageUser(firstUser.getBindUserId()); | ||
| 82 | + if (secondUser == null || !BooleanUtil.isTrue(secondUser.getBrokerageEnabled())) { | ||
| 83 | + return; | ||
| 84 | + } | ||
| 85 | + // 2.2 计算二级分佣 | ||
| 86 | + addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), BrokerageAddReqBO::getSecondFixedPrice, bizType); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + @Transactional(rollbackFor = Exception.class) | ||
| 91 | + public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) { | ||
| 92 | + // TODO @疯狂:userId 加进去查询,会不会更好一点?万一穿错参数; | ||
| 93 | + BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId); | ||
| 94 | + if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) { | ||
| 95 | + log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); | ||
| 96 | + return; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + // 1. 更新佣金记录为已失效 | ||
| 100 | + BrokerageRecordDO updateObj = new BrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus()); | ||
| 101 | + int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); | ||
| 102 | + if (updateRows == 0) { | ||
| 103 | + log.error("[cancelBrokerage][record({}) 更新为已失效失败]", record.getId()); | ||
| 104 | + return; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + // 2. 更新用户的佣金 | ||
| 108 | + if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) { | ||
| 109 | + brokerageUserService.updateUserFrozenPrice(userId, -record.getPrice()); | ||
| 110 | + } else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) { | ||
| 111 | + brokerageUserService.updateUserPrice(userId, -record.getPrice()); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * 计算佣金 | ||
| 117 | + * | ||
| 118 | + * @param basePrice 佣金基数 | ||
| 119 | + * @param percent 佣金比例 | ||
| 120 | + * @param fixedPrice 固定佣金 | ||
| 121 | + * @return 佣金 | ||
| 122 | + */ | ||
| 123 | + int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) { | ||
| 124 | + // 1. 优先使用固定佣金 | ||
| 125 | + if (fixedPrice != null && fixedPrice > 0) { | ||
| 126 | + return ObjectUtil.defaultIfNull(fixedPrice, 0); | ||
| 127 | + } | ||
| 128 | + // 2. 根据比例计算佣金 | ||
| 129 | + if (basePrice != null && basePrice > 0 && percent != null && percent > 0) { | ||
| 130 | + return MoneyUtils.calculateRatePriceFloor(basePrice, Double.valueOf(percent)); | ||
| 131 | + } | ||
| 132 | + return 0; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + /** | ||
| 136 | + * 增加用户佣金 | ||
| 137 | + * | ||
| 138 | + * @param user 用户 | ||
| 139 | + * @param list 佣金增加参数列表 | ||
| 140 | + * @param brokerageFrozenDays 冻结天数 | ||
| 141 | + * @param brokeragePercent 佣金比例 | ||
| 142 | + * @param fixedPriceFun 固定佣金 // TODO 疯狂:这里是不是可以直接传递 fixedPrice 呀? | ||
| 143 | + * @param bizType 业务类型 | ||
| 144 | + */ | ||
| 145 | + private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays, | ||
| 146 | + Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> fixedPriceFun, | ||
| 147 | + BrokerageRecordBizTypeEnum bizType) { | ||
| 148 | + // 1.1 处理冻结时间 | ||
| 149 | + LocalDateTime unfreezeTime = null; | ||
| 150 | + if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { | ||
| 151 | + unfreezeTime = LocalDateTime.now().plusDays(brokerageFrozenDays); | ||
| 152 | + } | ||
| 153 | + // 1.2 计算分佣 | ||
| 154 | + int totalBrokerage = 0; | ||
| 155 | + List<BrokerageRecordDO> records = new ArrayList<>(); | ||
| 156 | + for (BrokerageAddReqBO item : list) { | ||
| 157 | + int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPriceFun.apply(item)); | ||
| 158 | + if (brokeragePerItem <= 0) { | ||
| 159 | + continue; | ||
| 160 | + } | ||
| 161 | + records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), | ||
| 162 | + brokerageFrozenDays, brokeragePerItem, unfreezeTime, bizType.getTitle())); | ||
| 163 | + totalBrokerage += brokeragePerItem; | ||
| 164 | + } | ||
| 165 | + if (CollUtil.isEmpty(records)) { | ||
| 166 | + return; | ||
| 167 | + } | ||
| 168 | + // 1.3 保存佣金记录 | ||
| 169 | + brokerageRecordMapper.insertBatch(records); | ||
| 170 | + | ||
| 171 | + // 2. 更新用户佣金 | ||
| 172 | + if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { // 更新用户冻结佣金 | ||
| 173 | + brokerageUserService.updateUserFrozenPrice(user.getId(), totalBrokerage); | ||
| 174 | + } else { // 更新用户可用佣金 | ||
| 175 | + brokerageUserService.updateUserPrice(user.getId(), totalBrokerage); | ||
| 176 | + } | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + @Override | ||
| 180 | + public int unfreezeRecord() { | ||
| 181 | + // 1. 查询待结算的佣金记录 | ||
| 182 | + List<BrokerageRecordDO> records = brokerageRecordMapper.selectListByStatusAndUnfreezeTimeLt( | ||
| 183 | + BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus(), LocalDateTime.now()); | ||
| 184 | + if (CollUtil.isEmpty(records)) { | ||
| 185 | + return 0; | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + // 2. 遍历执行 | ||
| 189 | + int count = 0; | ||
| 190 | + for (BrokerageRecordDO record : records) { | ||
| 191 | + try { | ||
| 192 | + boolean success = getSelf().unfreezeRecord(record); | ||
| 193 | + if (success) { | ||
| 194 | + count++; | ||
| 195 | + } | ||
| 196 | + } catch (Exception e) { | ||
| 197 | + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId(), e); | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + return count; | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + @Override | ||
| 204 | + public UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status) { | ||
| 205 | + UserBrokerageSummaryBO summaryBO = brokerageRecordMapper.selectCountAndSumPriceByUserIdAndBizTypeAndStatus(userId, bizType, status); | ||
| 206 | + return summaryBO != null ? summaryBO : new UserBrokerageSummaryBO(0, 0); | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + @Transactional(rollbackFor = Exception.class) | ||
| 210 | + public boolean unfreezeRecord(BrokerageRecordDO record) { | ||
| 211 | + // 更新记录状态 | ||
| 212 | + BrokerageRecordDO updateObj = new BrokerageRecordDO() | ||
| 213 | + .setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus()) | ||
| 214 | + .setUnfreezeTime(LocalDateTime.now()); | ||
| 215 | + int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); | ||
| 216 | + if (updateRows == 0) { | ||
| 217 | + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId()); | ||
| 218 | + return false; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + // 更新用户冻结佣金 | ||
| 222 | + brokerageUserService.updateFrozenPriceDecrAndPriceIncr(record.getUserId(), -record.getPrice()); | ||
| 223 | + log.info("[unfreezeRecord][record({}) 更新为已结算成功]", record.getId()); | ||
| 224 | + return true; | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + /** | ||
| 228 | + * 获得自身的代理对象,解决 AOP 生效问题 | ||
| 229 | + * | ||
| 230 | + * @return 自己 | ||
| 231 | + */ | ||
| 232 | + private BrokerageRecordServiceImpl getSelf() { | ||
| 233 | + return SpringUtil.getBean(getClass()); | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +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 | + | ||
| 7 | +import java.util.Collection; | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 分销用户 Service 接口 | ||
| 12 | + * | ||
| 13 | + * @author owen | ||
| 14 | + */ | ||
| 15 | +public interface BrokerageUserService { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 获得分销用户 | ||
| 19 | + * | ||
| 20 | + * @param id 编号 | ||
| 21 | + * @return 分销用户 | ||
| 22 | + */ | ||
| 23 | + BrokerageUserDO getBrokerageUser(Long id); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 获得分销用户列表 | ||
| 27 | + * | ||
| 28 | + * @param ids 编号 | ||
| 29 | + * @return 分销用户列表 | ||
| 30 | + */ | ||
| 31 | + List<BrokerageUserDO> getBrokerageUserList(Collection<Long> ids); | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 获得分销用户分页 | ||
| 35 | + * | ||
| 36 | + * @param pageReqVO 分页查询 | ||
| 37 | + * @return 分销用户分页 | ||
| 38 | + */ | ||
| 39 | + PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO); | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 修改推广员编号 | ||
| 43 | + * | ||
| 44 | + * @param id 用户编号 | ||
| 45 | + * @param bindUserId 推广员编号 | ||
| 46 | + */ | ||
| 47 | + void updateBrokerageUserId(Long id, Long bindUserId); | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * 修改推广资格 | ||
| 51 | + * | ||
| 52 | + * @param id 用户编号 | ||
| 53 | + * @param enabled 推广资格 | ||
| 54 | + */ | ||
| 55 | + void updateBrokerageUserEnabled(Long id, Boolean enabled); | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 获得用户的推广人 | ||
| 59 | + * | ||
| 60 | + * @param id 用户编号 | ||
| 61 | + * @return 用户的推广人 | ||
| 62 | + */ | ||
| 63 | + BrokerageUserDO getBindBrokerageUser(Long id); | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 更新用户佣金 | ||
| 67 | + * | ||
| 68 | + * @param id 用户编号 | ||
| 69 | + * @param price 用户可用佣金 | ||
| 70 | + */ | ||
| 71 | + void updateUserPrice(Long id, Integer price); | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 更新用户冻结佣金 | ||
| 75 | + * | ||
| 76 | + * @param id 用户编号 | ||
| 77 | + * @param frozenPrice 用户冻结佣金 | ||
| 78 | + */ | ||
| 79 | + void updateUserFrozenPrice(Long id, Integer frozenPrice); | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * 更新用户冻结佣金(减少),更新用户佣金(增加) | ||
| 83 | + * | ||
| 84 | + * @param id 用户编号 | ||
| 85 | + * @param frozenPrice 减少冻结佣金(负数) | ||
| 86 | + */ | ||
| 87 | + void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice); | ||
| 88 | + | ||
| 89 | + // TODO @疯狂:这个后面可能要支持下,二级 | ||
| 90 | + /** | ||
| 91 | + * 获得推广用户数量(一级) | ||
| 92 | + * | ||
| 93 | + * @param bindUserId 绑定的推广员编号 | ||
| 94 | + * @return 推广用户数量 | ||
| 95 | + */ | ||
| 96 | + Long getBrokerageUserCountByBindUserId(Long bindUserId); | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * 【会员】绑定推广员 | ||
| 100 | + * | ||
| 101 | + * @param userId 用户编号 | ||
| 102 | + * @param bindUserId 推广员编号 | ||
| 103 | + * @param isNewUser 是否为新用户 | ||
| 104 | + * @return 是否绑定 | ||
| 105 | + */ | ||
| 106 | + boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser); | ||
| 107 | + | ||
| 108 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.user; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.hutool.core.util.BooleanUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper; | ||
| 10 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; | ||
| 11 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; | ||
| 12 | +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 15 | + | ||
| 16 | +import javax.annotation.Resource; | ||
| 17 | +import java.time.LocalDateTime; | ||
| 18 | +import java.util.Collection; | ||
| 19 | +import java.util.List; | ||
| 20 | +import java.util.Objects; | ||
| 21 | +import java.util.Optional; | ||
| 22 | + | ||
| 23 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 24 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * 分销用户 Service 实现类 | ||
| 28 | + * | ||
| 29 | + * @author owen | ||
| 30 | + */ | ||
| 31 | +@Service | ||
| 32 | +@Validated | ||
| 33 | +public class BrokerageUserServiceImpl implements BrokerageUserService { | ||
| 34 | + | ||
| 35 | + @Resource | ||
| 36 | + private BrokerageUserMapper brokerageUserMapper; | ||
| 37 | + | ||
| 38 | + @Resource | ||
| 39 | + private TradeConfigService tradeConfigService; | ||
| 40 | + | ||
| 41 | + @Override | ||
| 42 | + public BrokerageUserDO getBrokerageUser(Long id) { | ||
| 43 | + return brokerageUserMapper.selectById(id); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public List<BrokerageUserDO> getBrokerageUserList(Collection<Long> ids) { | ||
| 48 | + return brokerageUserMapper.selectBatchIds(ids); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) { | ||
| 53 | + return brokerageUserMapper.selectPage(pageReqVO); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public void updateBrokerageUserId(Long id, Long bindUserId) { | ||
| 58 | + // 校验存在 | ||
| 59 | + validateBrokerageUserExists(id); | ||
| 60 | + | ||
| 61 | + // 情况一:清除推广员 | ||
| 62 | + if (bindUserId == null) { | ||
| 63 | + // 清除推广员 | ||
| 64 | + brokerageUserMapper.updateBindUserIdAndBindUserTimeToNull(id); | ||
| 65 | + return; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 情况二:修改推广员 | ||
| 69 | + // TODO @疯狂:要复用一些 validateCanBindUser 的校验哈; | ||
| 70 | + brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) | ||
| 71 | + .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | + public void updateBrokerageUserEnabled(Long id, Boolean enabled) { | ||
| 76 | + // 校验存在 | ||
| 77 | + validateBrokerageUserExists(id); | ||
| 78 | + if (BooleanUtil.isTrue(enabled)) { | ||
| 79 | + // 开通推广资格 | ||
| 80 | + brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) | ||
| 81 | + .setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now())); | ||
| 82 | + } else { | ||
| 83 | + // 取消推广资格 | ||
| 84 | + brokerageUserMapper.updateEnabledFalseAndBrokerageTimeToNull(id); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + private void validateBrokerageUserExists(Long id) { | ||
| 89 | + if (brokerageUserMapper.selectById(id) == null) { | ||
| 90 | + throw exception(BROKERAGE_USER_NOT_EXISTS); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + @Override | ||
| 95 | + public BrokerageUserDO getBindBrokerageUser(Long id) { | ||
| 96 | + return Optional.ofNullable(id) | ||
| 97 | + .map(this::getBrokerageUser) | ||
| 98 | + .map(BrokerageUserDO::getBindUserId) | ||
| 99 | + .map(this::getBrokerageUser) | ||
| 100 | + .orElse(null); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + @Override | ||
| 104 | + public void updateUserPrice(Long id, Integer price) { | ||
| 105 | + if (price > 0) { | ||
| 106 | + brokerageUserMapper.updatePriceIncr(id, price); | ||
| 107 | + } else if (price < 0) { | ||
| 108 | + brokerageUserMapper.updatePriceDecr(id, price); | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public void updateUserFrozenPrice(Long id, Integer frozenPrice) { | ||
| 114 | + if (frozenPrice > 0) { | ||
| 115 | + brokerageUserMapper.updateFrozenPriceIncr(id, frozenPrice); | ||
| 116 | + } else if (frozenPrice < 0) { | ||
| 117 | + brokerageUserMapper.updateFrozenPriceDecr(id, frozenPrice); | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + @Override | ||
| 122 | + public void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice) { | ||
| 123 | + Assert.isTrue(frozenPrice < 0); | ||
| 124 | + int updateRows = brokerageUserMapper.updateFrozenPriceDecrAndPriceIncr(id, frozenPrice); | ||
| 125 | + if (updateRows == 0) { | ||
| 126 | + throw exception(BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH); | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + @Override | ||
| 131 | + public Long getBrokerageUserCountByBindUserId(Long bindUserId) { | ||
| 132 | + // TODO @疯狂:mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法 | ||
| 133 | + return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + // TODO @疯狂:因为现在 user 会存在使用验证码直接注册,所以 isNewUser 不太好传递;我们是不是可以约定绑定的时间,createTime 在 30 秒内,就认为新用户; | ||
| 137 | + @Override | ||
| 138 | + public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) { | ||
| 139 | + // TODO @疯狂:userId 为空,搞到参数校验里哇; | ||
| 140 | + if (userId == null) { | ||
| 141 | + throw exception(0); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + // 1. 获得分销用户 | ||
| 145 | + boolean isNewBrokerageUser = false; | ||
| 146 | + BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); | ||
| 147 | + if (brokerageUser == null) { // 分销用户不存在的情况:1. 新注册;2. 旧数据;3. 分销功能关闭后又打开 | ||
| 148 | + isNewBrokerageUser = true; | ||
| 149 | + brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + // 2.1 校验能否绑定 | ||
| 153 | + boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser); | ||
| 154 | + if (!validated) { | ||
| 155 | + return false; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + // 2.2 绑定用户 | ||
| 159 | + if (isNewBrokerageUser) { | ||
| 160 | + Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); | ||
| 161 | + if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格 | ||
| 162 | + // TODO @疯狂:应该设置下 brokerageTime,而不是 bindUserTime | ||
| 163 | + brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now()); | ||
| 164 | + } | ||
| 165 | + // TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈; | ||
| 166 | + brokerageUserMapper.insert(brokerageUser); | ||
| 167 | + } else { | ||
| 168 | + brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) | ||
| 169 | + .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); | ||
| 170 | + } | ||
| 171 | + return true; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + // TODO @疯狂:validate 方法,一般不返回 true false,而是抛出异常;如果要返回 true false 这种,方法名字可以改成 isUserCanBind | ||
| 175 | + private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) { | ||
| 176 | + // TODO @疯狂:bindUserId 为空,搞到参数校验里哇; | ||
| 177 | + if (bindUserId == null) { | ||
| 178 | + return false; | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + // 校验分销功能是否启用 | ||
| 182 | + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); | ||
| 183 | + if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) { | ||
| 184 | + return false; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + // 校验绑定自己 | ||
| 188 | + if (Objects.equals(user.getId(), bindUserId)) { | ||
| 189 | + throw exception(BROKERAGE_BIND_SELF); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + // 校验要绑定的用户有无推广资格 | ||
| 193 | + BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); | ||
| 194 | + if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) { | ||
| 195 | + throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + // 校验分佣模式:仅可后台手动设置推广员 | ||
| 199 | + if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) { | ||
| 200 | + throw exception(BROKERAGE_BIND_CONDITION_ADMIN); | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + // 校验分销关系绑定模式 | ||
| 204 | + if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) { | ||
| 205 | + if (!BooleanUtil.isTrue(isNewUser)) { | ||
| 206 | + throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定 | ||
| 207 | + } | ||
| 208 | + } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) { | ||
| 209 | + if (user.getBindUserId() != null) { | ||
| 210 | + throw exception(BROKERAGE_BIND_OVERRIDE); // 已绑定了推广人 | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈 | ||
| 215 | + // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!! | ||
| 216 | + if (Objects.equals(user.getId(), bindUser.getBindUserId())) { | ||
| 217 | + throw exception(BROKERAGE_BIND_LOOP); | ||
| 218 | + } | ||
| 219 | + return true; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; | ||
| 4 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 5 | + | ||
| 6 | +import javax.validation.Valid; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 交易中心配置 Service 接口 | ||
| 10 | + * | ||
| 11 | + * @author owen | ||
| 12 | + */ | ||
| 13 | +public interface TradeConfigService { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 更新交易中心配置 | ||
| 17 | + * | ||
| 18 | + * @param updateReqVO 更新信息 | ||
| 19 | + */ | ||
| 20 | + void saveTradeConfig(@Valid TradeConfigSaveReqVO updateReqVO); | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 获得交易中心配置 | ||
| 24 | + * | ||
| 25 | + * @return 交易中心配置 | ||
| 26 | + */ | ||
| 27 | + TradeConfigDO getTradeConfig(); | ||
| 28 | + | ||
| 29 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert; | ||
| 6 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.mysql.config.TradeConfigMapper; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | +import org.springframework.validation.annotation.Validated; | ||
| 10 | + | ||
| 11 | +import javax.annotation.Resource; | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 交易中心配置 Service 实现类 | ||
| 16 | + * | ||
| 17 | + * @author owen | ||
| 18 | + */ | ||
| 19 | +@Service | ||
| 20 | +@Validated | ||
| 21 | +public class TradeConfigServiceImpl implements TradeConfigService { | ||
| 22 | + | ||
| 23 | + @Resource | ||
| 24 | + private TradeConfigMapper tradeConfigMapper; | ||
| 25 | + | ||
| 26 | + @Override | ||
| 27 | + public void saveTradeConfig(TradeConfigSaveReqVO saveReqVO) { | ||
| 28 | + // 存在,则进行更新 | ||
| 29 | + TradeConfigDO dbConfig = getTradeConfig(); | ||
| 30 | + if (dbConfig != null) { | ||
| 31 | + tradeConfigMapper.updateById(TradeConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId())); | ||
| 32 | + return; | ||
| 33 | + } | ||
| 34 | + // 不存在,则进行插入 | ||
| 35 | + tradeConfigMapper.insert(TradeConfigConvert.INSTANCE.convert(saveReqVO)); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + @Override | ||
| 39 | + public TradeConfigDO getTradeConfig() { | ||
| 40 | + List<TradeConfigDO> list = tradeConfigMapper.selectList(); | ||
| 41 | + return CollectionUtils.getFirst(list); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order; | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order; | ||
| 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.hutool.core.util.IdUtil; | ||
| 6 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 7 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 8 | import cn.hutool.extra.spring.SpringUtil; | 7 | import cn.hutool.extra.spring.SpringUtil; |
| @@ -25,12 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | @@ -25,12 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | ||
| 25 | import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; | 24 | import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; |
| 26 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; | 25 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; |
| 27 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 26 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 27 | +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi; | ||
| 28 | import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; | 28 | import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; |
| 29 | import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; | 29 | import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; |
| 30 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; | 30 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 31 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | ||
| 32 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | 31 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; |
| 33 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; | 32 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; |
| 33 | +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; | ||
| 34 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | ||
| 34 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; | 35 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; |
| 35 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; | 36 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; |
| 36 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; | 37 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; |
| @@ -46,10 +47,14 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | @@ -46,10 +47,14 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | ||
| 46 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 47 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 47 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; | 48 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; |
| 48 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | 49 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| 50 | +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO; | ||
| 49 | import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; | 51 | import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; |
| 52 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 50 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | 53 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; |
| 51 | import cn.iocoder.yudao.module.trade.enums.order.*; | 54 | import cn.iocoder.yudao.module.trade.enums.order.*; |
| 52 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | 55 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; |
| 56 | +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; | ||
| 57 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 53 | import cn.iocoder.yudao.module.trade.service.cart.CartService; | 58 | import cn.iocoder.yudao.module.trade.service.cart.CartService; |
| 54 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; | 59 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; |
| 55 | import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; | 60 | import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; |
| @@ -71,7 +76,7 @@ import java.util.Set; | @@ -71,7 +76,7 @@ import java.util.Set; | ||
| 71 | 76 | ||
| 72 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 77 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 73 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 78 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 74 | -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND; | 79 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL; |
| 75 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID; | 80 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID; |
| 76 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; | 81 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 77 | 82 | ||
| @@ -89,6 +94,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -89,6 +94,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 89 | private TradeOrderMapper tradeOrderMapper; | 94 | private TradeOrderMapper tradeOrderMapper; |
| 90 | @Resource | 95 | @Resource |
| 91 | private TradeOrderItemMapper tradeOrderItemMapper; | 96 | private TradeOrderItemMapper tradeOrderItemMapper; |
| 97 | + @Resource | ||
| 98 | + private TradeOrderNoRedisDAO orderNoRedisDAO; | ||
| 92 | 99 | ||
| 93 | @Resource | 100 | @Resource |
| 94 | private CartService cartService; | 101 | private CartService cartService; |
| @@ -112,12 +119,18 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -112,12 +119,18 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 112 | @Resource | 119 | @Resource |
| 113 | private BargainRecordApi bargainRecordApi; | 120 | private BargainRecordApi bargainRecordApi; |
| 114 | @Resource | 121 | @Resource |
| 122 | + private SeckillActivityApi seckillActivityApi; | ||
| 123 | + @Resource | ||
| 124 | + private BargainActivityApi bargainActivityApi; | ||
| 125 | + @Resource | ||
| 115 | private MemberUserApi memberUserApi; | 126 | private MemberUserApi memberUserApi; |
| 116 | @Resource | 127 | @Resource |
| 117 | private MemberLevelApi memberLevelApi; | 128 | private MemberLevelApi memberLevelApi; |
| 118 | @Resource | 129 | @Resource |
| 119 | private MemberPointApi memberPointApi; | 130 | private MemberPointApi memberPointApi; |
| 120 | @Resource | 131 | @Resource |
| 132 | + private BrokerageRecordService brokerageRecordService; | ||
| 133 | + @Resource | ||
| 121 | private ProductCommentApi productCommentApi; | 134 | private ProductCommentApi productCommentApi; |
| 122 | 135 | ||
| 123 | @Resource | 136 | @Resource |
| @@ -190,22 +203,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -190,22 +203,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 190 | // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去 | 203 | // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去 |
| 191 | // 拼团 | 204 | // 拼团 |
| 192 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { | 205 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { |
| 193 | - MemberUserRespDTO user = memberUserApi.getUser(userId); | ||
| 194 | - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId()); | ||
| 195 | - // TODO 拼团一次应该只能选择一种规格的商品 | ||
| 196 | - TradeOrderItemDO orderItemDO = orderItems.get(0); | ||
| 197 | - if (CollUtil.isNotEmpty(recordRespDTOS)) { | ||
| 198 | - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | ||
| 199 | - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS, | ||
| 200 | - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | ||
| 201 | - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(), | ||
| 202 | - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount()); | ||
| 203 | - } | ||
| 204 | - | ||
| 205 | - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); | 206 | + createCombinationRecord(userId, createReqVO, orderItems, order); |
| 206 | } | 207 | } |
| 207 | // 3.2 秒杀的特殊逻辑 | 208 | // 3.2 秒杀的特殊逻辑 |
| 208 | - // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除 | ||
| 209 | if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) { | 209 | if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) { |
| 210 | 210 | ||
| 211 | } | 211 | } |
| @@ -215,6 +215,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -215,6 +215,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 215 | return order; | 215 | return order; |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | + private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) { | ||
| 219 | + MemberUserRespDTO user = memberUserApi.getUser(userId); | ||
| 220 | + List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId()); | ||
| 221 | + // TODO 拼团一次应该只能选择一种规格的商品 | ||
| 222 | + TradeOrderItemDO orderItemDO = orderItems.get(0); | ||
| 223 | + if (CollUtil.isNotEmpty(recordRespDTOS)) { | ||
| 224 | + List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | ||
| 225 | + List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS, | ||
| 226 | + CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | ||
| 227 | + combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(), | ||
| 228 | + CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount()); | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); | ||
| 232 | + } | ||
| 233 | + | ||
| 218 | // TODO @puhui999:订单超时,自动取消; | 234 | // TODO @puhui999:订单超时,自动取消; |
| 219 | 235 | ||
| 220 | /** | 236 | /** |
| @@ -241,8 +257,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -241,8 +257,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 241 | address = validateAddress(userId, createReqVO.getAddressId()); | 257 | address = validateAddress(userId, createReqVO.getAddressId()); |
| 242 | } | 258 | } |
| 243 | TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); | 259 | TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); |
| 260 | + String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX); | ||
| 244 | order.setType(validateActivity(createReqVO)); | 261 | order.setType(validateActivity(createReqVO)); |
| 245 | - order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈; | 262 | + order.setNo(no); |
| 246 | order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); | 263 | order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); |
| 247 | order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | 264 | order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); |
| 248 | order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); | 265 | order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); |
| @@ -294,19 +311,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -294,19 +311,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 294 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, | 311 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, |
| 295 | TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, | 312 | TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, |
| 296 | TradePriceCalculateRespBO calculateRespBO) { | 313 | TradePriceCalculateRespBO calculateRespBO) { |
| 297 | - // 下单时扣减商品库存 | ||
| 298 | - // TODO @puhui999:扣库存,需要前置; | 314 | + Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum); |
| 299 | // 1)如果是秒杀商品:额外扣减秒杀的库存; | 315 | // 1)如果是秒杀商品:额外扣减秒杀的库存; |
| 300 | - // 2)如果是拼团活动:额外扣减拼团的库存; | ||
| 301 | - // 3)如果是砍价活动:额外扣减砍价的库存; | ||
| 302 | - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); | ||
| 303 | - | ||
| 304 | - // 删除购物车商品 | ||
| 305 | - Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); | ||
| 306 | - if (CollUtil.isNotEmpty(cartIds)) { | ||
| 307 | - cartService.deleteCart(userId, cartIds); | ||
| 308 | - } | ||
| 309 | - | 316 | + if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) { |
| 317 | + SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO(); | ||
| 318 | + updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId()); | ||
| 319 | + updateStockReqDTO.setCount(count); | ||
| 320 | + updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> { | ||
| 321 | + SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item(); | ||
| 322 | + item1.setSpuId(item.getSpuId()); | ||
| 323 | + item1.setSkuId(item.getSkuId()); | ||
| 324 | + item1.setCount(item.getCount()); | ||
| 325 | + return item1; | ||
| 326 | + })); | ||
| 327 | + seckillActivityApi.updateSeckillStock(updateStockReqDTO); | ||
| 328 | + } | ||
| 329 | + // 2)如果是砍价活动:额外扣减砍价的库存; | ||
| 330 | + bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count); | ||
| 310 | // 扣减积分 TODO 芋艿:待实现,需要前置; | 331 | // 扣减积分 TODO 芋艿:待实现,需要前置; |
| 311 | // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 | 332 | // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 |
| 312 | 333 | ||
| @@ -316,6 +337,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -316,6 +337,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 316 | .setOrderId(tradeOrderDO.getId())); | 337 | .setOrderId(tradeOrderDO.getId())); |
| 317 | } | 338 | } |
| 318 | 339 | ||
| 340 | + // 下单时扣减商品库存 | ||
| 341 | + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); | ||
| 342 | + | ||
| 343 | + // 删除购物车商品 | ||
| 344 | + Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); | ||
| 345 | + if (CollUtil.isNotEmpty(cartIds)) { | ||
| 346 | + cartService.deleteCart(userId, cartIds); | ||
| 347 | + } | ||
| 348 | + | ||
| 319 | // 生成预支付 | 349 | // 生成预支付 |
| 320 | createPayOrder(tradeOrderDO, orderItems, calculateRespBO); | 350 | createPayOrder(tradeOrderDO, orderItems, calculateRespBO); |
| 321 | 351 | ||
| @@ -352,8 +382,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -352,8 +382,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 352 | // 1、拼团活动 | 382 | // 1、拼团活动 |
| 353 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { | 383 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { |
| 354 | // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 | 384 | // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 |
| 355 | - combinationRecordApi.updateCombinationRecordStatus(new CombinationRecordUpdateStatusReqDTO().setUserId(order.getUserId()) | ||
| 356 | - .setOrderId(order.getId()).setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus()).setStartTime(LocalDateTime.now())); | 385 | + combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); |
| 357 | } | 386 | } |
| 358 | // TODO 芋艿:发送订单变化的消息 | 387 | // TODO 芋艿:发送订单变化的消息 |
| 359 | 388 | ||
| @@ -365,6 +394,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -365,6 +394,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 365 | getSelf().addUserPointAsync(order.getUserId(), order.getPayPrice(), order.getId()); | 394 | getSelf().addUserPointAsync(order.getUserId(), order.getPayPrice(), order.getId()); |
| 366 | // 增加用户经验 | 395 | // 增加用户经验 |
| 367 | getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); | 396 | getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); |
| 397 | + // 增加用户佣金 | ||
| 398 | + getSelf().addBrokerageAsync(order.getUserId(), order.getId()); | ||
| 368 | } | 399 | } |
| 369 | 400 | ||
| 370 | /** | 401 | /** |
| @@ -466,11 +497,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -466,11 +497,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 466 | */ | 497 | */ |
| 467 | private TradeOrderDO validateOrderDeliverable(Long id) { | 498 | private TradeOrderDO validateOrderDeliverable(Long id) { |
| 468 | TradeOrderDO order = validateOrderExists(id); | 499 | TradeOrderDO order = validateOrderExists(id); |
| 469 | - // 校验订单是否是待发货状态 | ||
| 470 | - // TODO @puhui999:已经发货,可以重新发货,修改信息; | ||
| 471 | - if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) { | ||
| 472 | - throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED); | ||
| 473 | - } | ||
| 474 | // 校验订单是否退款 | 500 | // 校验订单是否退款 |
| 475 | if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { | 501 | if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { |
| 476 | throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE); | 502 | throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE); |
| @@ -536,20 +562,35 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -536,20 +562,35 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 536 | } | 562 | } |
| 537 | 563 | ||
| 538 | @Override | 564 | @Override |
| 565 | + // TODO @puhui999:考虑事务性 | ||
| 539 | public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) { | 566 | public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) { |
| 540 | // 校验交易订单 | 567 | // 校验交易订单 |
| 541 | TradeOrderDO order = validateOrderExists(reqVO.getId()); | 568 | TradeOrderDO order = validateOrderExists(reqVO.getId()); |
| 542 | if (order.getPayStatus()) { | 569 | if (order.getPayStatus()) { |
| 543 | throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); | 570 | throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); |
| 544 | } | 571 | } |
| 545 | - // TODO @puhui999:如果改价,需要校验下是否真的变化; | ||
| 546 | - | ||
| 547 | - // 更新 | ||
| 548 | - // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下; | 572 | + if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) { |
| 573 | + throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL); | ||
| 574 | + } | ||
| 575 | + | ||
| 576 | + // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的 | ||
| 577 | + List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId()); | ||
| 578 | + // TradeOrderItemDO 需要做 adjustPrice 的分摊 | ||
| 579 | + int price = reqVO.getAdjustPrice() / itemDOs.size(); | ||
| 580 | + itemDOs.forEach(item -> { | ||
| 581 | + item.setAdjustPrice(price); | ||
| 582 | + }); | ||
| 583 | + // 更新 TradeOrderItem | ||
| 584 | + // TODO @puhui999:不要整个对象去更新哈;应该 new 一下; | ||
| 585 | + tradeOrderItemMapper.updateBatch(itemDOs); | ||
| 586 | + // 更新订单 | ||
| 587 | + // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格; | ||
| 549 | TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO); | 588 | TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO); |
| 550 | update.setPayPrice(update.getPayPrice() + update.getAdjustPrice()); | 589 | update.setPayPrice(update.getPayPrice() + update.getAdjustPrice()); |
| 551 | // TODO @芋艿:改价时,赠送的积分,要不要做改动??? | 590 | // TODO @芋艿:改价时,赠送的积分,要不要做改动??? |
| 552 | tradeOrderMapper.updateById(update); | 591 | tradeOrderMapper.updateById(update); |
| 592 | + // 更新支付订单 | ||
| 593 | + payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice()); | ||
| 553 | } | 594 | } |
| 554 | 595 | ||
| 555 | @Override | 596 | @Override |
| @@ -629,12 +670,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -629,12 +670,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 629 | .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); | 670 | .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); |
| 630 | } | 671 | } |
| 631 | 672 | ||
| 632 | - // TODO 芋艿:未来如果有分佣,需要更新相关分佣订单为已失效 | ||
| 633 | - | ||
| 634 | // 扣减用户积分 | 673 | // 扣减用户积分 |
| 635 | getSelf().reduceUserPointAsync(order.getUserId(), orderRefundPrice, afterSaleId); | 674 | getSelf().reduceUserPointAsync(order.getUserId(), orderRefundPrice, afterSaleId); |
| 636 | // 扣减用户经验 | 675 | // 扣减用户经验 |
| 637 | getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); | 676 | getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); |
| 677 | + // 更新分佣记录为已失效 | ||
| 678 | + getSelf().cancelBrokerageAsync(order.getUserId(), id); | ||
| 638 | } | 679 | } |
| 639 | 680 | ||
| 640 | @Override | 681 | @Override |
| @@ -742,6 +783,20 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -742,6 +783,20 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 742 | memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); | 783 | memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); |
| 743 | } | 784 | } |
| 744 | 785 | ||
| 786 | + | ||
| 787 | + @Async | ||
| 788 | + protected void addBrokerageAsync(Long userId, Long orderId) { | ||
| 789 | + List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId); | ||
| 790 | + List<BrokerageAddReqBO> list = convertList(orderItems, | ||
| 791 | + item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId()))); | ||
| 792 | + brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list); | ||
| 793 | + } | ||
| 794 | + | ||
| 795 | + @Async | ||
| 796 | + protected void cancelBrokerageAsync(Long userId, Long orderItemId) { | ||
| 797 | + brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId)); | ||
| 798 | + } | ||
| 799 | + | ||
| 745 | /** | 800 | /** |
| 746 | * 获得自身的代理对象,解决 AOP 生效问题 | 801 | * 获得自身的代理对象,解决 AOP 生效问题 |
| 747 | * | 802 | * |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.record; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.NumberUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||
| 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; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; | ||
| 10 | +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | ||
| 11 | +import org.junit.jupiter.api.Disabled; | ||
| 12 | +import org.junit.jupiter.api.Test; | ||
| 13 | +import org.springframework.boot.test.mock.mockito.MockBean; | ||
| 14 | +import org.springframework.context.annotation.Import; | ||
| 15 | + | ||
| 16 | +import javax.annotation.Resource; | ||
| 17 | +import java.math.RoundingMode; | ||
| 18 | + | ||
| 19 | +import static cn.hutool.core.util.RandomUtil.randomEle; | ||
| 20 | +import static cn.hutool.core.util.RandomUtil.randomInt; | ||
| 21 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | ||
| 22 | +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | ||
| 23 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | ||
| 24 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger; | ||
| 25 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 26 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 27 | + | ||
| 28 | +// TODO @芋艿:单测后续看看 | ||
| 29 | +/** | ||
| 30 | + * {@link BrokerageRecordServiceImpl} 的单元测试类 | ||
| 31 | + * | ||
| 32 | + * @author owen | ||
| 33 | + */ | ||
| 34 | +@Import(BrokerageRecordServiceImpl.class) | ||
| 35 | +public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | ||
| 36 | + | ||
| 37 | + @Resource | ||
| 38 | + private BrokerageRecordServiceImpl brokerageRecordService; | ||
| 39 | + @Resource | ||
| 40 | + private BrokerageRecordMapper brokerageRecordMapper; | ||
| 41 | + | ||
| 42 | + @MockBean | ||
| 43 | + private TradeConfigService tradeConfigService; | ||
| 44 | + @MockBean | ||
| 45 | + private BrokerageUserService brokerageUserService; | ||
| 46 | + | ||
| 47 | + @Test | ||
| 48 | + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | ||
| 49 | + public void testGetBrokerageRecordPage() { | ||
| 50 | + // mock 数据 | ||
| 51 | + BrokerageRecordDO dbBrokerageRecord = randomPojo(BrokerageRecordDO.class, o -> { // 等会查询到 | ||
| 52 | + o.setUserId(null); | ||
| 53 | + o.setBizType(null); | ||
| 54 | + o.setStatus(null); | ||
| 55 | + o.setCreateTime(null); | ||
| 56 | + }); | ||
| 57 | + brokerageRecordMapper.insert(dbBrokerageRecord); | ||
| 58 | + // 测试 userId 不匹配 | ||
| 59 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(null))); | ||
| 60 | + // 测试 bizType 不匹配 | ||
| 61 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setBizType(null))); | ||
| 62 | + // 测试 status 不匹配 | ||
| 63 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setStatus(null))); | ||
| 64 | + // 测试 createTime 不匹配 | ||
| 65 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setCreateTime(null))); | ||
| 66 | + // 准备参数 | ||
| 67 | + BrokerageRecordPageReqVO reqVO = new BrokerageRecordPageReqVO(); | ||
| 68 | + reqVO.setUserId(null); | ||
| 69 | + reqVO.setBizType(null); | ||
| 70 | + reqVO.setStatus(null); | ||
| 71 | + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | ||
| 72 | + | ||
| 73 | + // 调用 | ||
| 74 | + PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(reqVO); | ||
| 75 | + // 断言 | ||
| 76 | + assertEquals(1, pageResult.getTotal()); | ||
| 77 | + assertEquals(1, pageResult.getList().size()); | ||
| 78 | + assertPojoEquals(dbBrokerageRecord, pageResult.getList().get(0)); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Test | ||
| 82 | + public void testCalculatePrice_useFixedPrice() { | ||
| 83 | + // mock 数据 | ||
| 84 | + Integer payPrice = randomInteger(); | ||
| 85 | + Integer percent = randomInt(1, 101); | ||
| 86 | + Integer fixedPrice = randomInt(); | ||
| 87 | + // 调用 | ||
| 88 | + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | ||
| 89 | + // 断言 | ||
| 90 | + assertEquals(brokerage, fixedPrice); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @Test | ||
| 94 | + public void testCalculatePrice_usePercent() { | ||
| 95 | + // mock 数据 | ||
| 96 | + Integer payPrice = randomInteger(); | ||
| 97 | + Integer percent = randomInt(1, 101); | ||
| 98 | + Integer fixedPrice = randomEle(new Integer[]{0, null}); | ||
| 99 | + System.out.println("fixedPrice=" + fixedPrice); | ||
| 100 | + // 调用 | ||
| 101 | + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | ||
| 102 | + // 断言 | ||
| 103 | + assertEquals(brokerage, NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue()); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + @Test | ||
| 107 | + public void testCalculatePrice_equalsZero() { | ||
| 108 | + // mock 数据 | ||
| 109 | + Integer payPrice = null; | ||
| 110 | + Integer percent = null; | ||
| 111 | + Integer fixedPrice = null; | ||
| 112 | + // 调用 | ||
| 113 | + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | ||
| 114 | + // 断言 | ||
| 115 | + assertEquals(brokerage, 0); | ||
| 116 | + } | ||
| 117 | +} |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.brokerage.user; | ||
| 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.user.vo.BrokerageUserPageReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper; | ||
| 8 | +import org.junit.jupiter.api.Disabled; | ||
| 9 | +import org.junit.jupiter.api.Test; | ||
| 10 | +import org.springframework.context.annotation.Import; | ||
| 11 | + | ||
| 12 | +import javax.annotation.Resource; | ||
| 13 | + | ||
| 14 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | ||
| 15 | +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | ||
| 16 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | ||
| 17 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 18 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 19 | + | ||
| 20 | +// TODO @芋艿:单测后续看看 | ||
| 21 | +/** | ||
| 22 | + * {@link BrokerageUserServiceImpl} 的单元测试类 | ||
| 23 | + * | ||
| 24 | + * @author owen | ||
| 25 | + */ | ||
| 26 | +@Import(BrokerageUserServiceImpl.class) | ||
| 27 | +public class BrokerageUserServiceImplTest extends BaseDbUnitTest { | ||
| 28 | + | ||
| 29 | + @Resource | ||
| 30 | + private BrokerageUserServiceImpl brokerageUserService; | ||
| 31 | + | ||
| 32 | + @Resource | ||
| 33 | + private BrokerageUserMapper brokerageUserMapper; | ||
| 34 | + | ||
| 35 | + @Test | ||
| 36 | + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | ||
| 37 | + public void testGetBrokerageUserPage() { | ||
| 38 | + // mock 数据 | ||
| 39 | + BrokerageUserDO dbBrokerageUser = randomPojo(BrokerageUserDO.class, o -> { // 等会查询到 | ||
| 40 | + o.setBindUserId(null); | ||
| 41 | + o.setBrokerageEnabled(null); | ||
| 42 | + o.setCreateTime(null); | ||
| 43 | + }); | ||
| 44 | + brokerageUserMapper.insert(dbBrokerageUser); | ||
| 45 | + // 测试 brokerageUserId 不匹配 | ||
| 46 | + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBindUserId(null))); | ||
| 47 | + // 测试 brokerageEnabled 不匹配 | ||
| 48 | + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBrokerageEnabled(null))); | ||
| 49 | + // 测试 createTime 不匹配 | ||
| 50 | + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setCreateTime(null))); | ||
| 51 | + // 准备参数 | ||
| 52 | + BrokerageUserPageReqVO reqVO = new BrokerageUserPageReqVO(); | ||
| 53 | + reqVO.setBindUserId(null); | ||
| 54 | + reqVO.setBrokerageEnabled(null); | ||
| 55 | + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | ||
| 56 | + | ||
| 57 | + // 调用 | ||
| 58 | + PageResult<BrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(reqVO); | ||
| 59 | + // 断言 | ||
| 60 | + assertEquals(1, pageResult.getTotal()); | ||
| 61 | + assertEquals(1, pageResult.getList().size()); | ||
| 62 | + assertPojoEquals(dbBrokerageUser, pageResult.getList().get(0)); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | +} |
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
| @@ -2,3 +2,5 @@ DELETE FROM trade_order; | @@ -2,3 +2,5 @@ DELETE FROM trade_order; | ||
| 2 | DELETE FROM trade_order_item; | 2 | DELETE FROM trade_order_item; |
| 3 | DELETE FROM trade_after_sale; | 3 | 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; | ||
| 6 | +DELETE FROM trade_brokerage_record; |
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
| @@ -125,3 +125,42 @@ CREATE TABLE IF NOT EXISTS "trade_after_sale_log" ( | @@ -125,3 +125,42 @@ CREATE TABLE IF NOT EXISTS "trade_after_sale_log" ( | ||
| 125 | "deleted" bit NOT NULL DEFAULT FALSE, | 125 | "deleted" bit NOT NULL DEFAULT FALSE, |
| 126 | PRIMARY KEY ("id") | 126 | PRIMARY KEY ("id") |
| 127 | ) COMMENT '交易售后日志'; | 127 | ) COMMENT '交易售后日志'; |
| 128 | + | ||
| 129 | +CREATE TABLE IF NOT EXISTS "trade_brokerage_user" | ||
| 130 | +( | ||
| 131 | + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 132 | + "bind_user_id" bigint NOT NULL, | ||
| 133 | + "bind_user_time" varchar, | ||
| 134 | + "brokerage_enabled" bit NOT NULL, | ||
| 135 | + "brokerage_time" varchar, | ||
| 136 | + "price" int NOT NULL, | ||
| 137 | + "frozen_price" int NOT NULL, | ||
| 138 | + "creator" varchar DEFAULT '', | ||
| 139 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 140 | + "updater" varchar DEFAULT '', | ||
| 141 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 142 | + "deleted" bit NOT NULL DEFAULT FALSE, | ||
| 143 | + "tenant_id" bigint NOT NULL DEFAULT '0', | ||
| 144 | + PRIMARY KEY ("id") | ||
| 145 | +) COMMENT '分销用户'; | ||
| 146 | +CREATE TABLE IF NOT EXISTS "trade_brokerage_record" | ||
| 147 | +( | ||
| 148 | + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 149 | + "user_id" bigint NOT NULL, | ||
| 150 | + "biz_id" varchar NOT NULL, | ||
| 151 | + "biz_type" varchar NOT NULL, | ||
| 152 | + "title" varchar NOT NULL, | ||
| 153 | + "price" int NOT NULL, | ||
| 154 | + "total_price" int NOT NULL, | ||
| 155 | + "description" varchar NOT NULL, | ||
| 156 | + "status" varchar NOT NULL, | ||
| 157 | + "frozen_days" int NOT NULL, | ||
| 158 | + "unfreeze_time" varchar, | ||
| 159 | + "creator" varchar DEFAULT '', | ||
| 160 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 161 | + "updater" varchar DEFAULT '', | ||
| 162 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 163 | + "deleted" bit NOT NULL DEFAULT FALSE, | ||
| 164 | + "tenant_id" bigint not null default '0', | ||
| 165 | + PRIMARY KEY ("id") | ||
| 166 | +) COMMENT '佣金记录'; | ||
| 128 | \ No newline at end of file | 167 | \ No newline at end of file |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
| @@ -28,6 +28,17 @@ tenant-id: {{appTenentId}} | @@ -28,6 +28,17 @@ tenant-id: {{appTenentId}} | ||
| 28 | "code": 9999 | 28 | "code": 9999 |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | +### 请求 /social-login 接口 => 成功 | ||
| 32 | +POST {{appApi}}/member/auth/social-login | ||
| 33 | +Content-Type: application/json | ||
| 34 | +tenant-id: {{appTenentId}} | ||
| 35 | + | ||
| 36 | +{ | ||
| 37 | + "type": 34, | ||
| 38 | + "code": "0e1oc9000CTjFQ1oim200bhtb61oc90g", | ||
| 39 | + "state": "default" | ||
| 40 | +} | ||
| 41 | + | ||
| 31 | ### 请求 /weixin-mini-app-login 接口 => 成功 | 42 | ### 请求 /weixin-mini-app-login 接口 => 成功 |
| 32 | POST {{appApi}}/member/auth/weixin-mini-app-login | 43 | POST {{appApi}}/member/auth/weixin-mini-app-login |
| 33 | Content-Type: application/json | 44 | Content-Type: application/json |
| @@ -38,7 +49,6 @@ tenant-id: {{appTenentId}} | @@ -38,7 +49,6 @@ tenant-id: {{appTenentId}} | ||
| 38 | "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR" | 49 | "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR" |
| 39 | } | 50 | } |
| 40 | 51 | ||
| 41 | - | ||
| 42 | ### 请求 /logout 接口 => 成功 | 52 | ### 请求 /logout 接口 => 成功 |
| 43 | POST {{appApi}}/member/auth/logout | 53 | POST {{appApi}}/member/auth/logout |
| 44 | Content-Type: application/json | 54 | Content-Type: application/json |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java
| @@ -27,4 +27,12 @@ public class AppAuthLoginRespVO { | @@ -27,4 +27,12 @@ public class AppAuthLoginRespVO { | ||
| 27 | @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) | 27 | @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 28 | private LocalDateTime expiresTime; | 28 | private LocalDateTime expiresTime; |
| 29 | 29 | ||
| 30 | + /** | ||
| 31 | + * 仅社交登录、社交绑定时会返回 | ||
| 32 | + * | ||
| 33 | + * 为什么需要返回?微信公众号、微信小程序支付需要传递 openid 给支付接口 | ||
| 34 | + */ | ||
| 35 | + @Schema(description = "社交用户 openid", example = "qq768") | ||
| 36 | + private String openid; | ||
| 37 | + | ||
| 30 | } | 38 | } |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java
| @@ -29,7 +29,6 @@ public class AppMemberUserController { | @@ -29,7 +29,6 @@ public class AppMemberUserController { | ||
| 29 | 29 | ||
| 30 | @Resource | 30 | @Resource |
| 31 | private MemberUserService userService; | 31 | private MemberUserService userService; |
| 32 | - | ||
| 33 | @Resource | 32 | @Resource |
| 34 | private MemberLevelService levelService; | 33 | private MemberLevelService levelService; |
| 35 | 34 |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
| @@ -29,6 +29,9 @@ public class AppMemberUserInfoRespVO { | @@ -29,6 +29,9 @@ public class AppMemberUserInfoRespVO { | ||
| 29 | @Schema(description = "用户等级") | 29 | @Schema(description = "用户等级") |
| 30 | private Level level; | 30 | private Level level; |
| 31 | 31 | ||
| 32 | + @Schema(description = "是否成为推广员", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 33 | + private Boolean brokerageEnabled; | ||
| 34 | + | ||
| 32 | @Schema(description = "用户 App - 会员等级") | 35 | @Schema(description = "用户 App - 会员等级") |
| 33 | @Data | 36 | @Data |
| 34 | public static class Level { | 37 | public static class Level { |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
| @@ -25,7 +25,7 @@ public interface AuthConvert { | @@ -25,7 +25,7 @@ public interface AuthConvert { | ||
| 25 | SmsCodeUseReqDTO convert(AppMemberUserResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); | 25 | SmsCodeUseReqDTO convert(AppMemberUserResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); |
| 26 | SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); | 26 | SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); |
| 27 | 27 | ||
| 28 | - AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); | 28 | + AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean, String openid); |
| 29 | 29 | ||
| 30 | SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); | 30 | SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); |
| 31 | 31 |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/point/MemberPointConfigDO.java
| @@ -6,14 +6,12 @@ import com.baomidou.mybatisplus.annotation.TableId; | @@ -6,14 +6,12 @@ import com.baomidou.mybatisplus.annotation.TableId; | ||
| 6 | import com.baomidou.mybatisplus.annotation.TableName; | 6 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | import lombok.*; | 7 | import lombok.*; |
| 8 | 8 | ||
| 9 | -import java.math.BigDecimal; | ||
| 10 | - | ||
| 11 | /** | 9 | /** |
| 12 | * 会员积分配置 DO | 10 | * 会员积分配置 DO |
| 13 | * | 11 | * |
| 14 | * @author QingX | 12 | * @author QingX |
| 15 | */ | 13 | */ |
| 16 | -@TableName("member_point_config") | 14 | +@TableName(value = "member_point_config", autoResultMap = true) |
| 17 | @KeySequence("member_point_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | 15 | @KeySequence("member_point_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| 18 | @Data | 16 | @Data |
| 19 | @EqualsAndHashCode(callSuper = true) | 17 | @EqualsAndHashCode(callSuper = true) |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
| @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; | @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; | ||
| 20 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; | 20 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 21 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; | 21 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| 22 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 22 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 23 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 23 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; | 24 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; |
| 24 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; | 25 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; |
| 25 | import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; | 26 | import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; |
| @@ -65,13 +66,14 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -65,13 +66,14 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 65 | MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); | 66 | MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); |
| 66 | 67 | ||
| 67 | // 如果 socialType 非空,说明需要绑定社交用户 | 68 | // 如果 socialType 非空,说明需要绑定社交用户 |
| 69 | + String openid = null; | ||
| 68 | if (reqVO.getSocialType() != null) { | 70 | if (reqVO.getSocialType() != null) { |
| 69 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | 71 | + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), |
| 70 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); | 72 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | // 创建 Token 令牌,记录登录日志 | 75 | // 创建 Token 令牌,记录登录日志 |
| 74 | - return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); | 76 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, openid); |
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | @Override | 79 | @Override |
| @@ -86,32 +88,33 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -86,32 +88,33 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 86 | Assert.notNull(user, "获取用户失败,结果为空"); | 88 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 87 | 89 | ||
| 88 | // 如果 socialType 非空,说明需要绑定社交用户 | 90 | // 如果 socialType 非空,说明需要绑定社交用户 |
| 91 | + String openid = null; | ||
| 89 | if (reqVO.getSocialType() != null) { | 92 | if (reqVO.getSocialType() != null) { |
| 90 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | 93 | + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), |
| 91 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); | 94 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); |
| 92 | } | 95 | } |
| 93 | 96 | ||
| 94 | // 创建 Token 令牌,记录登录日志 | 97 | // 创建 Token 令牌,记录登录日志 |
| 95 | - return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS); | 98 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, openid); |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | @Override | 101 | @Override |
| 99 | public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { | 102 | public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { |
| 100 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 | 103 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 101 | - Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | 104 | + SocialUserRespDTO socialUser = socialUserApi.getSocialUser(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), |
| 102 | reqVO.getCode(), reqVO.getState()); | 105 | reqVO.getCode(), reqVO.getState()); |
| 103 | - if (userId == null) { | 106 | + if (socialUser == null) { |
| 104 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); | 107 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 105 | } | 108 | } |
| 106 | 109 | ||
| 107 | // 自动登录 | 110 | // 自动登录 |
| 108 | - MemberUserDO user = userService.getUser(userId); | 111 | + MemberUserDO user = userService.getUser(socialUser.getUserId()); |
| 109 | if (user == null) { | 112 | if (user == null) { |
| 110 | throw exception(USER_NOT_EXISTS); | 113 | throw exception(USER_NOT_EXISTS); |
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | // 创建 Token 令牌,记录登录日志 | 116 | // 创建 Token 令牌,记录登录日志 |
| 114 | - return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL); | 117 | + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, socialUser.getOpenid()); |
| 115 | } | 118 | } |
| 116 | 119 | ||
| 117 | @Override | 120 | @Override |
| @@ -129,14 +132,15 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -129,14 +132,15 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 129 | Assert.notNull(user, "获取用户失败,结果为空"); | 132 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 130 | 133 | ||
| 131 | // 绑定社交用户 | 134 | // 绑定社交用户 |
| 132 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | 135 | + String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), |
| 133 | SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), "")); | 136 | SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), "")); |
| 134 | 137 | ||
| 135 | // 创建 Token 令牌,记录登录日志 | 138 | // 创建 Token 令牌,记录登录日志 |
| 136 | - return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL); | 139 | + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| 139 | - private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) { | 142 | + private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, |
| 143 | + LoginLogTypeEnum logType, String openid) { | ||
| 140 | // 插入登陆日志 | 144 | // 插入登陆日志 |
| 141 | createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); | 145 | createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); |
| 142 | // 创建 Token 令牌 | 146 | // 创建 Token 令牌 |
| @@ -144,7 +148,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -144,7 +148,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 144 | .setUserId(user.getId()).setUserType(getUserType().getValue()) | 148 | .setUserId(user.getId()).setUserType(getUserType().getValue()) |
| 145 | .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)); | 149 | .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)); |
| 146 | // 构建返回结果 | 150 | // 构建返回结果 |
| 147 | - return AuthConvert.INSTANCE.convert(accessTokenRespDTO); | 151 | + return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid); |
| 148 | } | 152 | } |
| 149 | 153 | ||
| 150 | @Override | 154 | @Override |
| @@ -231,7 +235,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -231,7 +235,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 231 | public AppAuthLoginRespVO refreshToken(String refreshToken) { | 235 | public AppAuthLoginRespVO refreshToken(String refreshToken) { |
| 232 | OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, | 236 | OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, |
| 233 | OAuth2ClientConstants.CLIENT_ID_DEFAULT); | 237 | OAuth2ClientConstants.CLIENT_ID_DEFAULT); |
| 234 | - return AuthConvert.INSTANCE.convert(accessTokenDO); | 238 | + return AuthConvert.INSTANCE.convert(accessTokenDO, null); |
| 235 | } | 239 | } |
| 236 | 240 | ||
| 237 | private void createLogoutLog(Long userId) { | 241 | private void createLogoutLog(Long userId) { |
yudao-module-member/yudao-module-member-biz/src/test/resources/sql/create_tables.sql
| @@ -90,3 +90,24 @@ CREATE TABLE IF NOT EXISTS "member_group" | @@ -90,3 +90,24 @@ CREATE TABLE IF NOT EXISTS "member_group" | ||
| 90 | "tenant_id" bigint not null default '0', | 90 | "tenant_id" bigint not null default '0', |
| 91 | PRIMARY KEY ("id") | 91 | PRIMARY KEY ("id") |
| 92 | ) COMMENT '用户分组'; | 92 | ) COMMENT '用户分组'; |
| 93 | +CREATE TABLE IF NOT EXISTS "member_brokerage_record" | ||
| 94 | +( | ||
| 95 | + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 96 | + "user_id" bigint NOT NULL, | ||
| 97 | + "biz_id" varchar NOT NULL, | ||
| 98 | + "biz_type" varchar NOT NULL, | ||
| 99 | + "title" varchar NOT NULL, | ||
| 100 | + "price" int NOT NULL, | ||
| 101 | + "total_price" int NOT NULL, | ||
| 102 | + "description" varchar NOT NULL, | ||
| 103 | + "status" varchar NOT NULL, | ||
| 104 | + "frozen_days" int NOT NULL, | ||
| 105 | + "unfreeze_time" varchar, | ||
| 106 | + "creator" varchar DEFAULT '', | ||
| 107 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 108 | + "updater" varchar DEFAULT '', | ||
| 109 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 110 | + "deleted" bit NOT NULL DEFAULT FALSE, | ||
| 111 | + "tenant_id" bigint not null default '0', | ||
| 112 | + PRIMARY KEY ("id") | ||
| 113 | +) COMMENT '佣金记录'; |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
| @@ -29,4 +29,13 @@ public interface PayOrderApi { | @@ -29,4 +29,13 @@ public interface PayOrderApi { | ||
| 29 | */ | 29 | */ |
| 30 | PayOrderRespDTO getOrder(Long id); | 30 | PayOrderRespDTO getOrder(Long id); |
| 31 | 31 | ||
| 32 | + // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id; | ||
| 33 | + /** | ||
| 34 | + * 更新支付订单价格 | ||
| 35 | + * | ||
| 36 | + * @param payOrderId 支付单编号 | ||
| 37 | + * @param payPrice 支付单价格 | ||
| 38 | + */ | ||
| 39 | + void updatePayOrderPriceById(Long payOrderId, Integer payPrice); | ||
| 40 | + | ||
| 32 | } | 41 | } |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
| @@ -28,6 +28,7 @@ public interface ErrorCodeConstants { | @@ -28,6 +28,7 @@ public interface ErrorCodeConstants { | ||
| 28 | ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_002_004, "发起支付报错,错误码:{},错误提示:{}"); | 28 | ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_002_004, "发起支付报错,错误码:{},错误提示:{}"); |
| 29 | ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1_007_002_005, "支付订单退款失败,原因:状态不是已支付或已退款"); | 29 | ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1_007_002_005, "支付订单退款失败,原因:状态不是已支付或已退款"); |
| 30 | ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1_007_002_006, "支付订单调价失败,原因:支付订单已付款,不能调价"); | 30 | ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1_007_002_006, "支付订单调价失败,原因:支付订单已付款,不能调价"); |
| 31 | + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化"); | ||
| 31 | 32 | ||
| 32 | // ========== ORDER 模块(拓展单) 1-007-003-000 ========== | 33 | // ========== ORDER 模块(拓展单) 1-007-003-000 ========== |
| 33 | ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1_007_003_000, "支付交易拓展单不存在"); | 34 | ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1_007_003_000, "支付交易拓展单不存在"); |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
| @@ -31,4 +31,9 @@ public class PayOrderApiImpl implements PayOrderApi { | @@ -31,4 +31,9 @@ public class PayOrderApiImpl implements PayOrderApi { | ||
| 31 | return PayOrderConvert.INSTANCE.convert2(order); | 31 | return PayOrderConvert.INSTANCE.convert2(order); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | + @Override | ||
| 35 | + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) { | ||
| 36 | + payOrderService.updatePayOrderPriceById(payOrderId, payPrice); | ||
| 37 | + } | ||
| 38 | + | ||
| 34 | } | 39 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
| @@ -5,13 +5,16 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -5,13 +5,16 @@ 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.framework.excel.core.util.ExcelUtils; | 6 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | ||
| 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; | 9 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 9 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | 10 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 14 | +import cn.iocoder.yudao.module.pay.framework.pay.wallet.WalletPayClient; | ||
| 13 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 15 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 14 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 16 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 17 | +import com.google.common.collect.Maps; | ||
| 15 | import io.swagger.v3.oas.annotations.Operation; | 18 | import io.swagger.v3.oas.annotations.Operation; |
| 16 | import io.swagger.v3.oas.annotations.Parameter; | 19 | import io.swagger.v3.oas.annotations.Parameter; |
| 17 | import io.swagger.v3.oas.annotations.tags.Tag; | 20 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -26,11 +29,14 @@ import java.io.IOException; | @@ -26,11 +29,14 @@ import java.io.IOException; | ||
| 26 | import java.util.ArrayList; | 29 | import java.util.ArrayList; |
| 27 | import java.util.List; | 30 | import java.util.List; |
| 28 | import java.util.Map; | 31 | import java.util.Map; |
| 32 | +import java.util.Objects; | ||
| 29 | 33 | ||
| 30 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 34 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 31 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 35 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 32 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | 36 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 33 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 37 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 38 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | ||
| 39 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; | ||
| 34 | 40 | ||
| 35 | @Tag(name = "管理后台 - 支付订单") | 41 | @Tag(name = "管理后台 - 支付订单") |
| 36 | @RestController | 42 | @RestController |
| @@ -70,6 +76,16 @@ public class PayOrderController { | @@ -70,6 +76,16 @@ public class PayOrderController { | ||
| 70 | @PostMapping("/submit") | 76 | @PostMapping("/submit") |
| 71 | @Operation(summary = "提交支付订单") | 77 | @Operation(summary = "提交支付订单") |
| 72 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { | 78 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { |
| 79 | + // 1. 钱包支付事,需要额外传 user_id 和 user_type | ||
| 80 | + if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { | ||
| 81 | + Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? | ||
| 82 | + Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); | ||
| 83 | + channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); | ||
| 84 | + channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); | ||
| 85 | + reqVO.setChannelExtras(channelExtras); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + // 2. 提交支付 | ||
| 73 | PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP()); | 89 | PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP()); |
| 74 | return success(respVO); | 90 | return success(respVO); |
| 75 | } | 91 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
| @@ -37,7 +37,7 @@ public class AppPayWalletController { | @@ -37,7 +37,7 @@ public class AppPayWalletController { | ||
| 37 | @Operation(summary = "获取钱包") | 37 | @Operation(summary = "获取钱包") |
| 38 | @PreAuthenticated | 38 | @PreAuthenticated |
| 39 | public CommonResult<AppPayWalletRespVO> getPayWallet() { | 39 | public CommonResult<AppPayWalletRespVO> getPayWallet() { |
| 40 | - PayWalletDO wallet = payWalletService.getPayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); | 40 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); |
| 41 | return success(PayWalletConvert.INSTANCE.convert(wallet)); | 41 | return success(PayWalletConvert.INSTANCE.convert(wallet)); |
| 42 | } | 42 | } |
| 43 | 43 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionRespVO.java
| @@ -15,9 +15,6 @@ public class AppPayWalletTransactionRespVO { | @@ -15,9 +15,6 @@ public class AppPayWalletTransactionRespVO { | ||
| 15 | @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 15 | @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 16 | private Integer bizType; | 16 | private Integer bizType; |
| 17 | 17 | ||
| 18 | - @Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | ||
| 19 | - private LocalDateTime transactionTime; | ||
| 20 | - | ||
| 21 | @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | 18 | @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") |
| 22 | private Long price; | 19 | private Long price; |
| 23 | 20 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java
| @@ -11,9 +11,9 @@ public class AppPayWalletRespVO { | @@ -11,9 +11,9 @@ public class AppPayWalletRespVO { | ||
| 11 | private Integer balance; | 11 | private Integer balance; |
| 12 | 12 | ||
| 13 | @Schema(description = "累计支出, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") | 13 | @Schema(description = "累计支出, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") |
| 14 | - private Long totalExpense; | 14 | + private Integer totalExpense; |
| 15 | 15 | ||
| 16 | @Schema(description = "累计充值, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") | 16 | @Schema(description = "累计充值, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") |
| 17 | - private Long totalRecharge; | 17 | + private Integer totalRecharge; |
| 18 | 18 | ||
| 19 | } | 19 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.wallet; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.wallet; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO; | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | ||
| 6 | import org.mapstruct.Mapper; | 7 | import org.mapstruct.Mapper; |
| 7 | import org.mapstruct.factory.Mappers; | 8 | import org.mapstruct.factory.Mappers; |
| 8 | 9 | ||
| @@ -12,4 +13,7 @@ public interface PayWalletTransactionConvert { | @@ -12,4 +13,7 @@ public interface PayWalletTransactionConvert { | ||
| 12 | PayWalletTransactionConvert INSTANCE = Mappers.getMapper(PayWalletTransactionConvert.class); | 13 | PayWalletTransactionConvert INSTANCE = Mappers.getMapper(PayWalletTransactionConvert.class); |
| 13 | 14 | ||
| 14 | PageResult<AppPayWalletTransactionRespVO> convertPage(PageResult<PayWalletTransactionDO> page); | 15 | PageResult<AppPayWalletTransactionRespVO> convertPage(PageResult<PayWalletTransactionDO> page); |
| 16 | + | ||
| 17 | + PayWalletTransactionDO convert(CreateWalletTransactionBO bean); | ||
| 18 | + | ||
| 15 | } | 19 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java
| @@ -45,10 +45,10 @@ public class PayWalletDO extends BaseDO { | @@ -45,10 +45,10 @@ public class PayWalletDO extends BaseDO { | ||
| 45 | /** | 45 | /** |
| 46 | * 累计支出,单位分 | 46 | * 累计支出,单位分 |
| 47 | */ | 47 | */ |
| 48 | - private Long totalExpense; | 48 | + private Integer totalExpense; |
| 49 | /** | 49 | /** |
| 50 | * 累计充值,单位分 | 50 | * 累计充值,单位分 |
| 51 | */ | 51 | */ |
| 52 | - private Long totalRecharge; | 52 | + private Integer totalRecharge; |
| 53 | 53 | ||
| 54 | } | 54 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java
| @@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableId; | @@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableId; | ||
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 7 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | import lombok.Data; | 8 | import lombok.Data; |
| 9 | 9 | ||
| 10 | -import java.time.LocalDateTime; | ||
| 11 | - | ||
| 12 | /** | 10 | /** |
| 13 | * 会员钱包流水 DO | 11 | * 会员钱包流水 DO |
| 14 | * | 12 | * |
| @@ -24,6 +22,7 @@ public class PayWalletTransactionDO extends BaseDO { | @@ -24,6 +22,7 @@ public class PayWalletTransactionDO extends BaseDO { | ||
| 24 | */ | 22 | */ |
| 25 | @TableId | 23 | @TableId |
| 26 | private Long id; | 24 | private Long id; |
| 25 | + | ||
| 27 | /** | 26 | /** |
| 28 | * 流水号 | 27 | * 流水号 |
| 29 | */ | 28 | */ |
| @@ -42,34 +41,26 @@ public class PayWalletTransactionDO extends BaseDO { | @@ -42,34 +41,26 @@ public class PayWalletTransactionDO extends BaseDO { | ||
| 42 | * 枚举 {@link PayWalletBizTypeEnum#getType()} | 41 | * 枚举 {@link PayWalletBizTypeEnum#getType()} |
| 43 | */ | 42 | */ |
| 44 | private Integer bizType; | 43 | private Integer bizType; |
| 45 | - // TODO @jason:使用 string;因为可能有业务是 string 接入哈。 | 44 | + |
| 46 | /** | 45 | /** |
| 47 | * 关联业务编号 | 46 | * 关联业务编号 |
| 48 | */ | 47 | */ |
| 49 | - private Long bizId; | 48 | + private String bizId; |
| 50 | 49 | ||
| 51 | - // TODO @jason:想了下,改成 title;流水标题;因为账户明细那,会看到这个; | ||
| 52 | /** | 50 | /** |
| 53 | - * 附加说明 | 51 | + * 流水说明 |
| 54 | */ | 52 | */ |
| 55 | - private String description; | 53 | + private String title; |
| 56 | 54 | ||
| 57 | - // TODO @jason:使用 price 哈。项目里,金额都是用这个为主; | ||
| 58 | /** | 55 | /** |
| 59 | * 交易金额,单位分 | 56 | * 交易金额,单位分 |
| 60 | * | 57 | * |
| 61 | * 正值表示余额增加,负值表示余额减少 | 58 | * 正值表示余额增加,负值表示余额减少 |
| 62 | */ | 59 | */ |
| 63 | - private Integer amount; | 60 | + private Integer price; |
| 61 | + | ||
| 64 | /** | 62 | /** |
| 65 | * 交易后余额,单位分 | 63 | * 交易后余额,单位分 |
| 66 | */ | 64 | */ |
| 67 | private Integer balance; | 65 | private Integer balance; |
| 68 | - | ||
| 69 | - // TODO @jason:使用 createTime 就够啦 | ||
| 70 | - /** | ||
| 71 | - * 交易时间 | ||
| 72 | - */ | ||
| 73 | - private LocalDateTime transactionTime; | ||
| 74 | - | ||
| 75 | } | 66 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.dal.mysql.wallet; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.dal.mysql.wallet; | ||
| 3 | 3 | ||
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 6 | import org.apache.ibatis.annotations.Mapper; | 7 | import org.apache.ibatis.annotations.Mapper; |
| 7 | 8 | ||
| 8 | @Mapper | 9 | @Mapper |
| @@ -12,6 +13,35 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { | @@ -12,6 +13,35 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { | ||
| 12 | return selectOne(PayWalletDO::getUserId, userId, | 13 | return selectOne(PayWalletDO::getUserId, userId, |
| 13 | PayWalletDO::getUserType, userType); | 14 | PayWalletDO::getUserType, userType); |
| 14 | } | 15 | } |
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 当消费退款时候, 更新钱包 | ||
| 19 | + * | ||
| 20 | + * @param price 消费金额 | ||
| 21 | + * @param id 钱包 id | ||
| 22 | + */ | ||
| 23 | + default int updateWhenConsumptionRefund(Integer price, Long id){ | ||
| 24 | + LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>() | ||
| 25 | + .setSql(" balance = balance + " + price | ||
| 26 | + + ", total_expense = total_expense - " + price) | ||
| 27 | + .eq(PayWalletDO::getId, id); | ||
| 28 | + return update(null, lambdaUpdateWrapper); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 当消费时候, 更新钱包 | ||
| 33 | + * | ||
| 34 | + * @param price 消费金额 | ||
| 35 | + * @param id 钱包 id | ||
| 36 | + */ | ||
| 37 | + default int updateWhenConsumption(Integer price, Long id){ | ||
| 38 | + LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>() | ||
| 39 | + .setSql(" balance = balance - " + price | ||
| 40 | + + ", total_expense = total_expense + " + price) | ||
| 41 | + .eq(PayWalletDO::getId, id) | ||
| 42 | + .ge(PayWalletDO::getBalance, price); // cas 逻辑 | ||
| 43 | + return update(null, lambdaUpdateWrapper); | ||
| 44 | + } | ||
| 15 | } | 45 | } |
| 16 | 46 | ||
| 17 | 47 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java
| @@ -18,9 +18,9 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | @@ -18,9 +18,9 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | ||
| 18 | LambdaQueryWrapperX<PayWalletTransactionDO> query = new LambdaQueryWrapperX<PayWalletTransactionDO>() | 18 | LambdaQueryWrapperX<PayWalletTransactionDO> query = new LambdaQueryWrapperX<PayWalletTransactionDO>() |
| 19 | .eq(PayWalletTransactionDO::getWalletId, walletId); | 19 | .eq(PayWalletTransactionDO::getWalletId, walletId); |
| 20 | if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_INCOME)) { | 20 | if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_INCOME)) { |
| 21 | - query.gt(PayWalletTransactionDO::getAmount, 0); | 21 | + query.gt(PayWalletTransactionDO::getPrice, 0); |
| 22 | } else if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_EXPENSE)) { | 22 | } else if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_EXPENSE)) { |
| 23 | - query.lt(PayWalletTransactionDO::getAmount, 0); | 23 | + query.lt(PayWalletTransactionDO::getPrice, 0); |
| 24 | } | 24 | } |
| 25 | query.orderByDesc(PayWalletTransactionDO::getId); | 25 | query.orderByDesc(PayWalletTransactionDO::getId); |
| 26 | return selectPage(pageReqVO, query); | 26 | return selectPage(pageReqVO, query); |
| @@ -30,9 +30,8 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | @@ -30,9 +30,8 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | ||
| 30 | return selectOne(PayWalletTransactionDO::getNo, no); | 30 | return selectOne(PayWalletTransactionDO::getNo, no); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | - default PayWalletTransactionDO selectByWalletIdAndBiz(Long walletId, Long bizId, Integer bizType) { | ||
| 34 | - return selectOne(PayWalletTransactionDO::getWalletId, walletId, | ||
| 35 | - PayWalletTransactionDO::getBizId, bizId, | 33 | + default PayWalletTransactionDO selectByBiz(String bizId, Integer bizType) { |
| 34 | + return selectOne(PayWalletTransactionDO::getBizId, bizId, | ||
| 36 | PayWalletTransactionDO::getBizType, bizType); | 35 | PayWalletTransactionDO::getBizType, bizType); |
| 37 | } | 36 | } |
| 38 | 37 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
| 1 | package cn.iocoder.yudao.module.pay.framework.pay.wallet; | 1 | package cn.iocoder.yudao.module.pay.framework.pay.wallet; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 3 | import cn.hutool.extra.spring.SpringUtil; | 5 | import cn.hutool.extra.spring.SpringUtil; |
| 4 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 6 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| @@ -9,13 +11,23 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq | @@ -9,13 +11,23 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq | ||
| 9 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | 11 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 10 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | 12 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; |
| 11 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | 13 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 14 | +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | ||
| 15 | +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | ||
| 16 | +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | ||
| 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 17 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 18 | +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | ||
| 19 | +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | ||
| 20 | +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | ||
| 21 | +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | ||
| 13 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | 22 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; |
| 23 | +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; | ||
| 14 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
| 15 | 25 | ||
| 16 | import java.util.Map; | 26 | import java.util.Map; |
| 17 | 27 | ||
| 18 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; | 28 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; |
| 29 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND; | ||
| 30 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND; | ||
| 19 | 31 | ||
| 20 | /** | 32 | /** |
| 21 | * 钱包支付的 PayClient 实现类 | 33 | * 钱包支付的 PayClient 实现类 |
| @@ -25,7 +37,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | @@ -25,7 +37,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | ||
| 25 | @Slf4j | 37 | @Slf4j |
| 26 | public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | 38 | public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 27 | 39 | ||
| 40 | + public static final String USER_ID_KEY = "user_id"; | ||
| 41 | + public static final String USER_TYPE_KEY = "user_type"; | ||
| 42 | + | ||
| 28 | private PayWalletService wallService; | 43 | private PayWalletService wallService; |
| 44 | + private PayWalletTransactionService walletTransactionService; | ||
| 45 | + private PayOrderService orderService; | ||
| 46 | + private PayRefundService refundService; | ||
| 29 | 47 | ||
| 30 | public WalletPayClient(Long channelId, NonePayClientConfig config) { | 48 | public WalletPayClient(Long channelId, NonePayClientConfig config) { |
| 31 | super(channelId, PayChannelEnum.WALLET.getCode(), config); | 49 | super(channelId, PayChannelEnum.WALLET.getCode(), config); |
| @@ -36,14 +54,22 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -36,14 +54,22 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 36 | if (wallService == null) { | 54 | if (wallService == null) { |
| 37 | wallService = SpringUtil.getBean(PayWalletService.class); | 55 | wallService = SpringUtil.getBean(PayWalletService.class); |
| 38 | } | 56 | } |
| 57 | + if (walletTransactionService == null) { | ||
| 58 | + walletTransactionService = SpringUtil.getBean(PayWalletTransactionService.class); | ||
| 59 | + } | ||
| 39 | } | 60 | } |
| 40 | 61 | ||
| 41 | @Override | 62 | @Override |
| 42 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | 63 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { |
| 43 | try { | 64 | try { |
| 44 | - PayWalletTransactionDO transaction = wallService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice()); | 65 | + Long userId = MapUtil.getLong(reqDTO.getChannelExtras(), USER_ID_KEY); |
| 66 | + Integer userType = MapUtil.getInt(reqDTO.getChannelExtras(), USER_TYPE_KEY); | ||
| 67 | + Assert.notNull(userId, "用户 id 不能为空"); | ||
| 68 | + Assert.notNull(userType, "用户类型不能为空"); | ||
| 69 | + PayWalletTransactionDO transaction = wallService.orderPay(userId, userType, reqDTO.getOutTradeNo(), | ||
| 70 | + reqDTO.getPrice()); | ||
| 45 | return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), | 71 | return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), |
| 46 | - transaction.getTransactionTime(), | 72 | + transaction.getCreateTime(), |
| 47 | reqDTO.getOutTradeNo(), transaction); | 73 | reqDTO.getOutTradeNo(), transaction); |
| 48 | } catch (Throwable ex) { | 74 | } catch (Throwable ex) { |
| 49 | log.error("[doUnifiedOrder] 失败", ex); | 75 | log.error("[doUnifiedOrder] 失败", ex); |
| @@ -66,15 +92,39 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -66,15 +92,39 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 66 | 92 | ||
| 67 | @Override | 93 | @Override |
| 68 | protected PayOrderRespDTO doGetOrder(String outTradeNo) { | 94 | protected PayOrderRespDTO doGetOrder(String outTradeNo) { |
| 69 | - throw new UnsupportedOperationException("待实现"); | 95 | + if (orderService == null) { |
| 96 | + orderService = SpringUtil.getBean(PayOrderService.class); | ||
| 97 | + } | ||
| 98 | + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); | ||
| 99 | + // 支付交易拓展单不存在, 返回关闭状态 | ||
| 100 | + if (orderExtension == null) { | ||
| 101 | + return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()), | ||
| 102 | + ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, ""); | ||
| 103 | + } | ||
| 104 | + // 关闭状态 | ||
| 105 | + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { | ||
| 106 | + return PayOrderRespDTO.closedOf(orderExtension.getChannelErrorCode(), | ||
| 107 | + orderExtension.getChannelErrorMsg(), outTradeNo, ""); | ||
| 108 | + } | ||
| 109 | + // 成功状态 | ||
| 110 | + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { | ||
| 111 | + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction( | ||
| 112 | + String.valueOf(orderExtension.getOrderId()), PayWalletBizTypeEnum.PAYMENT); | ||
| 113 | + Assert.notNull(walletTransaction, "支付单 {} 钱包流水不能为空", outTradeNo); | ||
| 114 | + return PayOrderRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreator(), | ||
| 115 | + walletTransaction.getCreateTime(), outTradeNo, walletTransaction); | ||
| 116 | + } | ||
| 117 | + // 其它状态为无效状态 | ||
| 118 | + log.error("[doGetOrder] 支付单 {} 的状态不正确", outTradeNo); | ||
| 119 | + throw new IllegalStateException(String.format("支付单[%s] 状态不正确", outTradeNo)); | ||
| 70 | } | 120 | } |
| 71 | 121 | ||
| 72 | @Override | 122 | @Override |
| 73 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | 123 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { |
| 74 | try { | 124 | try { |
| 75 | - PayWalletTransactionDO payWalletTransaction = wallService.refund(reqDTO.getOutRefundNo(), | 125 | + PayWalletTransactionDO payWalletTransaction = wallService.orderRefund(reqDTO.getOutRefundNo(), |
| 76 | reqDTO.getRefundPrice(), reqDTO.getReason()); | 126 | reqDTO.getRefundPrice(), reqDTO.getReason()); |
| 77 | - return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getTransactionTime(), | 127 | + return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(), |
| 78 | reqDTO.getOutRefundNo(), payWalletTransaction); | 128 | reqDTO.getOutRefundNo(), payWalletTransaction); |
| 79 | } catch (Throwable ex) { | 129 | } catch (Throwable ex) { |
| 80 | log.error("[doUnifiedRefund] 失败", ex); | 130 | log.error("[doUnifiedRefund] 失败", ex); |
| @@ -97,7 +147,31 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -97,7 +147,31 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 97 | 147 | ||
| 98 | @Override | 148 | @Override |
| 99 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { | 149 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { |
| 100 | - throw new UnsupportedOperationException("待实现"); | 150 | + if (refundService == null) { |
| 151 | + refundService = SpringUtil.getBean(PayRefundService.class); | ||
| 152 | + } | ||
| 153 | + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); | ||
| 154 | + // 支付退款单不存在, 返回退款失败状态 | ||
| 155 | + if (payRefund == null) { | ||
| 156 | + return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(), | ||
| 157 | + outRefundNo, ""); | ||
| 158 | + } | ||
| 159 | + // 退款失败 | ||
| 160 | + if (PayRefundStatusRespEnum.isFailure(payRefund.getStatus())) { | ||
| 161 | + return PayRefundRespDTO.failureOf(payRefund.getChannelErrorCode(), payRefund.getChannelErrorMsg(), | ||
| 162 | + outRefundNo, ""); | ||
| 163 | + } | ||
| 164 | + // 退款成功 | ||
| 165 | + if (PayRefundStatusRespEnum.isSuccess(payRefund.getStatus())) { | ||
| 166 | + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction( | ||
| 167 | + String.valueOf(payRefund.getId()), PayWalletBizTypeEnum.PAYMENT_REFUND); | ||
| 168 | + Assert.notNull(walletTransaction, "支付退款单 {} 钱包流水不能为空", outRefundNo); | ||
| 169 | + return PayRefundRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreateTime(), | ||
| 170 | + outRefundNo, walletTransaction); | ||
| 171 | + } | ||
| 172 | + // 其它状态为无效状态 | ||
| 173 | + log.error("[doGetRefund] 支付退款单 {} 的状态不正确", outRefundNo); | ||
| 174 | + throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo)); | ||
| 101 | } | 175 | } |
| 102 | 176 | ||
| 103 | } | 177 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
| @@ -33,7 +33,7 @@ public interface PayOrderService { | @@ -33,7 +33,7 @@ public interface PayOrderService { | ||
| 33 | /** | 33 | /** |
| 34 | * 获得支付订单 | 34 | * 获得支付订单 |
| 35 | * | 35 | * |
| 36 | - * @param appId 应用编号 | 36 | + * @param appId 应用编号 |
| 37 | * @param merchantOrderId 商户订单编号 | 37 | * @param merchantOrderId 商户订单编号 |
| 38 | * @return 支付订单 | 38 | * @return 支付订单 |
| 39 | */ | 39 | */ |
| @@ -75,7 +75,7 @@ public interface PayOrderService { | @@ -75,7 +75,7 @@ public interface PayOrderService { | ||
| 75 | * 提交支付 | 75 | * 提交支付 |
| 76 | * 此时,会发起支付渠道的调用 | 76 | * 此时,会发起支付渠道的调用 |
| 77 | * | 77 | * |
| 78 | - * @param reqVO 提交请求 | 78 | + * @param reqVO 提交请求 |
| 79 | * @param userIp 提交 IP | 79 | * @param userIp 提交 IP |
| 80 | * @return 提交结果 | 80 | * @return 提交结果 |
| 81 | */ | 81 | */ |
| @@ -93,12 +93,20 @@ public interface PayOrderService { | @@ -93,12 +93,20 @@ public interface PayOrderService { | ||
| 93 | /** | 93 | /** |
| 94 | * 更新支付订单的退款金额 | 94 | * 更新支付订单的退款金额 |
| 95 | * | 95 | * |
| 96 | - * @param id 编号 | 96 | + * @param id 编号 |
| 97 | * @param incrRefundPrice 增加的退款金额 | 97 | * @param incrRefundPrice 增加的退款金额 |
| 98 | */ | 98 | */ |
| 99 | void updateOrderRefundPrice(Long id, Integer incrRefundPrice); | 99 | void updateOrderRefundPrice(Long id, Integer incrRefundPrice); |
| 100 | 100 | ||
| 101 | /** | 101 | /** |
| 102 | + * 更新支付订单价格 | ||
| 103 | + * | ||
| 104 | + * @param payOrderId 支付单编号 | ||
| 105 | + * @param payPrice 支付单价格 | ||
| 106 | + */ | ||
| 107 | + void updatePayOrderPriceById(Long payOrderId, Integer payPrice); | ||
| 108 | + | ||
| 109 | + /** | ||
| 102 | * 获得支付订单 | 110 | * 获得支付订单 |
| 103 | * | 111 | * |
| 104 | * @param id 编号 | 112 | * @param id 编号 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| @@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil; | @@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil; | ||
| 6 | import cn.hutool.extra.spring.SpringUtil; | 6 | import cn.hutool.extra.spring.SpringUtil; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | 8 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 9 | +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||
| 9 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | 10 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 10 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | 11 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| @@ -31,7 +32,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | @@ -31,7 +32,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | ||
| 31 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 32 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 32 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | 33 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 33 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 34 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 34 | -import cn.iocoder.yudao.module.pay.util.MoneyUtils; | ||
| 35 | import com.google.common.annotations.VisibleForTesting; | 35 | import com.google.common.annotations.VisibleForTesting; |
| 36 | import lombok.extern.slf4j.Slf4j; | 36 | import lombok.extern.slf4j.Slf4j; |
| 37 | import org.springframework.stereotype.Service; | 37 | import org.springframework.stereotype.Service; |
| @@ -412,6 +412,18 @@ public class PayOrderServiceImpl implements PayOrderService { | @@ -412,6 +412,18 @@ public class PayOrderServiceImpl implements PayOrderService { | ||
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | @Override | 414 | @Override |
| 415 | + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) { | ||
| 416 | + // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈; | ||
| 417 | + PayOrderDO order = orderMapper.selectById(payOrderId); | ||
| 418 | + if (order == null) { | ||
| 419 | + throw exception(ORDER_NOT_FOUND); | ||
| 420 | + } | ||
| 421 | + | ||
| 422 | + order.setPrice(payPrice); | ||
| 423 | + orderMapper.updateById(order); | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + @Override | ||
| 415 | public PayOrderExtensionDO getOrderExtension(Long id) { | 427 | public PayOrderExtensionDO getOrderExtension(Long id) { |
| 416 | return orderExtensionMapper.selectById(id); | 428 | return orderExtensionMapper.selectById(id); |
| 417 | } | 429 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.service.wallet; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.service.wallet; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 3 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 5 | +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | ||
| 5 | 6 | ||
| 6 | /** | 7 | /** |
| 7 | * 钱包 Service 接口 | 8 | * 钱包 Service 接口 |
| @@ -10,30 +11,59 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | @@ -10,30 +11,59 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | ||
| 10 | */ | 11 | */ |
| 11 | public interface PayWalletService { | 12 | public interface PayWalletService { |
| 12 | 13 | ||
| 13 | - // TODO @jason:改成 getOrCreateWallet;因为目前解耦,用户注册时,不会创建钱包;需要这里兜底处理; | ||
| 14 | /** | 14 | /** |
| 15 | * 获取钱包信息 | 15 | * 获取钱包信息 |
| 16 | * | 16 | * |
| 17 | + * 如果不存在,则创建钱包。由于用户注册时候不会创建钱包 | ||
| 18 | + * | ||
| 17 | * @param userId 用户编号 | 19 | * @param userId 用户编号 |
| 18 | * @param userType 用户类型 | 20 | * @param userType 用户类型 |
| 19 | */ | 21 | */ |
| 20 | - PayWalletDO getPayWallet(Long userId, Integer userType); | 22 | + PayWalletDO getOrCreateWallet(Long userId, Integer userType); |
| 21 | 23 | ||
| 22 | /** | 24 | /** |
| 23 | - * 钱包支付 | 25 | + * 钱包订单支付 |
| 24 | * | 26 | * |
| 27 | + * @param userId 用户 id | ||
| 28 | + * @param userType 用户类型 | ||
| 25 | * @param outTradeNo 外部订单号 | 29 | * @param outTradeNo 外部订单号 |
| 26 | * @param price 金额 | 30 | * @param price 金额 |
| 27 | */ | 31 | */ |
| 28 | - PayWalletTransactionDO pay(String outTradeNo, Integer price); | 32 | + PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price); |
| 29 | 33 | ||
| 30 | /** | 34 | /** |
| 31 | - * 钱包支付退款 | 35 | + * 钱包订单支付退款 |
| 32 | * | 36 | * |
| 33 | * @param outRefundNo 外部退款号 | 37 | * @param outRefundNo 外部退款号 |
| 34 | * @param refundPrice 退款金额 | 38 | * @param refundPrice 退款金额 |
| 35 | * @param reason 退款原因 | 39 | * @param reason 退款原因 |
| 36 | */ | 40 | */ |
| 37 | - PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason); | 41 | + PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason); |
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 扣减钱包余额 | ||
| 45 | + * | ||
| 46 | + * @param userId 用户 id | ||
| 47 | + * @param userType 用户类型 | ||
| 48 | + * @param bizId 业务关联 id | ||
| 49 | + * @param bizType 业务关联分类 | ||
| 50 | + * @param price 扣减金额 | ||
| 51 | + * @return 钱包流水 | ||
| 52 | + */ | ||
| 53 | + PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, | ||
| 54 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 增加钱包余额 | ||
| 58 | + * | ||
| 59 | + * @param userId 用户 id | ||
| 60 | + * @param userType 用户类型 | ||
| 61 | + * @param bizId 业务关联 id | ||
| 62 | + * @param bizType 业务关联分类 | ||
| 63 | + * @param price 增加金额 | ||
| 64 | + * @return 钱包流水 | ||
| 65 | + */ | ||
| 66 | + PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, | ||
| 67 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price); | ||
| 38 | 68 | ||
| 39 | } | 69 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
| 1 | package cn.iocoder.yudao.module.pay.service.wallet; | 1 | package cn.iocoder.yudao.module.pay.service.wallet; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 3 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 7 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; | 8 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; |
| 8 | -import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | 9 | +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 9 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 10 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 10 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | 11 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 12 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | ||
| 11 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 12 | import org.springframework.context.annotation.Lazy; | 14 | import org.springframework.context.annotation.Lazy; |
| 13 | import org.springframework.stereotype.Service; | 15 | import org.springframework.stereotype.Service; |
| @@ -17,8 +19,6 @@ import javax.annotation.Resource; | @@ -17,8 +19,6 @@ import javax.annotation.Resource; | ||
| 17 | import java.time.LocalDateTime; | 19 | import java.time.LocalDateTime; |
| 18 | 20 | ||
| 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 20 | -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | ||
| 21 | -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; | ||
| 22 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | 22 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 23 | import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT; | 23 | import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT; |
| 24 | import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT_REFUND; | 24 | import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT_REFUND; |
| @@ -32,105 +32,55 @@ import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYM | @@ -32,105 +32,55 @@ import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYM | ||
| 32 | @Slf4j | 32 | @Slf4j |
| 33 | public class PayWalletServiceImpl implements PayWalletService { | 33 | public class PayWalletServiceImpl implements PayWalletService { |
| 34 | 34 | ||
| 35 | - /** | ||
| 36 | - * 余额支付的 no 前缀 | ||
| 37 | - */ | ||
| 38 | - private static final String WALLET_PAY_NO_PREFIX = "WP"; | ||
| 39 | - /** | ||
| 40 | - * 余额退款的 no 前缀 | ||
| 41 | - */ | ||
| 42 | - private static final String WALLET_REFUND_NO_PREFIX = "WR"; | ||
| 43 | - | ||
| 44 | @Resource | 35 | @Resource |
| 45 | - private PayWalletMapper payWalletMapper; | 36 | + private PayWalletMapper walletMapper; |
| 46 | @Resource | 37 | @Resource |
| 47 | - private PayNoRedisDAO noRedisDAO; | ||
| 48 | - | ||
| 49 | - @Resource | ||
| 50 | - private PayWalletTransactionService payWalletTransactionService; | 38 | + private PayWalletTransactionService walletTransactionService; |
| 51 | @Resource | 39 | @Resource |
| 52 | @Lazy | 40 | @Lazy |
| 53 | - private PayOrderService payOrderService; | 41 | + private PayOrderService orderService; |
| 54 | @Resource | 42 | @Resource |
| 55 | @Lazy | 43 | @Lazy |
| 56 | - private PayRefundService payRefundService; | 44 | + private PayRefundService refundService; |
| 57 | 45 | ||
| 58 | @Override | 46 | @Override |
| 59 | - public PayWalletDO getPayWallet(Long userId, Integer userType) { | ||
| 60 | - return payWalletMapper.selectByUserIdAndType(userId, userType); | 47 | + public PayWalletDO getOrCreateWallet(Long userId, Integer userType) { |
| 48 | + PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType); | ||
| 49 | + if (wallet == null) { | ||
| 50 | + wallet = new PayWalletDO().setUserId(userId).setUserType(userType) | ||
| 51 | + .setBalance(0).setTotalExpense(0).setTotalRecharge(0); | ||
| 52 | + wallet.setCreateTime(LocalDateTime.now()); | ||
| 53 | + walletMapper.insert(wallet); | ||
| 54 | + } | ||
| 55 | + return wallet; | ||
| 61 | } | 56 | } |
| 62 | 57 | ||
| 63 | - // TODO @jason:可以做的更抽象一点;pay(bizType, bizId, price);reduceWalletBalance; | ||
| 64 | - // TODO @jason:最好是,明确传入哪个 userId 或者 walletId; | ||
| 65 | @Override | 58 | @Override |
| 66 | @Transactional(rollbackFor = Exception.class) | 59 | @Transactional(rollbackFor = Exception.class) |
| 67 | - public PayWalletTransactionDO pay(String outTradeNo, Integer price) { | ||
| 68 | - // 1.1 判断支付交易拓展单是否存 | ||
| 69 | - PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo); | 60 | + public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) { |
| 61 | + // 1. 判断支付交易拓展单是否存 | ||
| 62 | + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); | ||
| 70 | if (orderExtension == null) { | 63 | if (orderExtension == null) { |
| 71 | throw exception(ORDER_EXTENSION_NOT_FOUND); | 64 | throw exception(ORDER_EXTENSION_NOT_FOUND); |
| 72 | } | 65 | } |
| 73 | - // 1.2 判断余额是否足够 | ||
| 74 | - PayWalletDO payWallet = validatePayWallet(); | ||
| 75 | - int afterBalance = payWallet.getBalance() - price; | ||
| 76 | - if (afterBalance < 0) { | ||
| 77 | - throw exception(WALLET_BALANCE_NOT_ENOUGH); | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - // 2.1 扣除余额 | ||
| 81 | - // TODO @jason:不要直接整个更新;而是 new 一个出来更新;然后要考虑并发,要 where 余额 > price,以及 - price | ||
| 82 | - payWallet.setBalance(afterBalance); | ||
| 83 | - payWallet.setTotalExpense(payWallet.getTotalExpense() + price); | ||
| 84 | - payWalletMapper.updateById(payWallet); | ||
| 85 | - | ||
| 86 | - // 2.2 生成钱包流水 | ||
| 87 | - String walletNo = noRedisDAO.generate(WALLET_PAY_NO_PREFIX); | ||
| 88 | - PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | ||
| 89 | - .setNo(walletNo).setAmount(price * -1).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) | ||
| 90 | - .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getType()); | ||
| 91 | - payWalletTransactionService.createWalletTransaction(walletTransaction); | ||
| 92 | - return walletTransaction; | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - // TODO @jason:不要在 service 里去使用用户上下文,这样和 request 就耦合了。 | ||
| 96 | - private PayWalletDO validatePayWallet() { | ||
| 97 | - Long userId = getLoginUserId(); | ||
| 98 | - Integer userType = getLoginUserType(); | ||
| 99 | - PayWalletDO payWallet = getPayWallet(userId, userType); | ||
| 100 | - if (payWallet == null) { | ||
| 101 | - log.error("[validatePayWallet] 用户 {} 钱包不存在", userId); | ||
| 102 | - throw exception(WALLET_NOT_FOUND); | ||
| 103 | - } | ||
| 104 | - return payWallet; | 66 | + // 2. 扣减余额 |
| 67 | + return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price); | ||
| 105 | } | 68 | } |
| 106 | 69 | ||
| 107 | - // TODO @jason:可以做的更抽象一点;pay(bizType, bizId, price);addWalletBalance;这样,如果后续充值,应该也是能复用这个方法的; | ||
| 108 | @Override | 70 | @Override |
| 109 | @Transactional(rollbackFor = Exception.class) | 71 | @Transactional(rollbackFor = Exception.class) |
| 110 | - public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) { | 72 | + public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) { |
| 111 | // 1.1 判断退款单是否存在 | 73 | // 1.1 判断退款单是否存在 |
| 112 | - PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo); | 74 | + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); |
| 113 | if (payRefund == null) { | 75 | if (payRefund == null) { |
| 114 | throw exception(REFUND_NOT_FOUND); | 76 | throw exception(REFUND_NOT_FOUND); |
| 115 | } | 77 | } |
| 116 | // 1.2 校验是否可以退款 | 78 | // 1.2 校验是否可以退款 |
| 117 | - PayWalletDO payWallet = validatePayWallet(); | ||
| 118 | - validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), payWallet.getId(), refundPrice); | ||
| 119 | - | ||
| 120 | - // TODO @jason:不要直接整个更新;而是 new 一个出来更新;然后要考虑并发,要 where 余额 + 金额 | ||
| 121 | - Integer afterBalance = payWallet.getBalance() + refundPrice; | ||
| 122 | - payWallet.setBalance(afterBalance); | ||
| 123 | - payWallet.setTotalExpense(payWallet.getTotalExpense() + refundPrice * -1L); | ||
| 124 | - payWalletMapper.updateById(payWallet); | ||
| 125 | - | ||
| 126 | - // 2.2 生成钱包流水 | ||
| 127 | - String walletNo = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX); | ||
| 128 | - PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | ||
| 129 | - .setNo(walletNo).setAmount(refundPrice).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) | ||
| 130 | - .setBizId(payRefund.getId()).setBizType(PAYMENT_REFUND.getType()) | ||
| 131 | - .setDescription(reason); | ||
| 132 | - payWalletTransactionService.createWalletTransaction(newWalletTransaction); | ||
| 133 | - return newWalletTransaction; | 79 | + Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), refundPrice); |
| 80 | + PayWalletDO wallet = walletMapper.selectById(walletId); | ||
| 81 | + Assert.notNull(wallet, "钱包 {} 不存在", walletId); | ||
| 82 | + // 2. 增加余额 | ||
| 83 | + return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice); | ||
| 134 | } | 84 | } |
| 135 | 85 | ||
| 136 | /** | 86 | /** |
| @@ -138,24 +88,78 @@ public class PayWalletServiceImpl implements PayWalletService { | @@ -138,24 +88,78 @@ public class PayWalletServiceImpl implements PayWalletService { | ||
| 138 | * | 88 | * |
| 139 | * @param refundId 支付退款单 id | 89 | * @param refundId 支付退款单 id |
| 140 | * @param walletPayNo 钱包支付 no | 90 | * @param walletPayNo 钱包支付 no |
| 141 | - * @param walletId 钱包 id | ||
| 142 | */ | 91 | */ |
| 143 | - // TODO @jason:不要使用基本类型; | ||
| 144 | - private void validateWalletCanRefund(long refundId, String walletPayNo, long walletId, int refundPrice) { | ||
| 145 | - // 查询钱包支付交易 | ||
| 146 | - PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getWalletTransactionByNo(walletPayNo); | ||
| 147 | - if (payWalletTransaction == null) { | 92 | + private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) { |
| 93 | + // 1. 校验钱包支付交易存在 | ||
| 94 | + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo); | ||
| 95 | + if (walletTransaction == null) { | ||
| 148 | throw exception(WALLET_TRANSACTION_NOT_FOUND); | 96 | throw exception(WALLET_TRANSACTION_NOT_FOUND); |
| 149 | } | 97 | } |
| 150 | // 原来的支付金额 | 98 | // 原来的支付金额 |
| 151 | - int amount = payWalletTransaction.getAmount() * -1; // TODO @jason:直接 - payWalletTransaction.getAmount() 即可; | 99 | + // TODO @jason:应该允许多次退款哈; |
| 100 | + int amount = - walletTransaction.getPrice(); | ||
| 152 | if (refundPrice != amount) { | 101 | if (refundPrice != amount) { |
| 153 | throw exception(WALLET_REFUND_AMOUNT_ERROR); | 102 | throw exception(WALLET_REFUND_AMOUNT_ERROR); |
| 154 | } | 103 | } |
| 155 | - PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction(walletId, refundId, PAYMENT_REFUND); | 104 | + PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction( |
| 105 | + String.valueOf(refundId), PAYMENT_REFUND); | ||
| 156 | if (refundTransaction != null) { | 106 | if (refundTransaction != null) { |
| 157 | throw exception(WALLET_REFUND_EXIST); | 107 | throw exception(WALLET_REFUND_EXIST); |
| 158 | } | 108 | } |
| 109 | + return walletTransaction.getWalletId(); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, | ||
| 114 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price) { | ||
| 115 | + // 1. 获取钱包 | ||
| 116 | + PayWalletDO payWallet = getOrCreateWallet(userId, userType); | ||
| 117 | + | ||
| 118 | + // 2.1 扣除余额 | ||
| 119 | + int updateCounts = 0 ; | ||
| 120 | + switch (bizType) { | ||
| 121 | + case PAYMENT: { | ||
| 122 | + updateCounts = walletMapper.updateWhenConsumption(price, payWallet.getId()); | ||
| 123 | + break; | ||
| 124 | + } | ||
| 125 | + case RECHARGE_REFUND: { | ||
| 126 | + // TODO | ||
| 127 | + break; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + if (updateCounts == 0) { | ||
| 131 | + throw exception(WALLET_BALANCE_NOT_ENOUGH); | ||
| 132 | + } | ||
| 133 | + // 2.2 生成钱包流水 | ||
| 134 | + Integer afterBalance = payWallet.getBalance() - price; | ||
| 135 | + CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId()) | ||
| 136 | + .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId)) | ||
| 137 | + .setBizType(bizType.getType()).setTitle(bizType.getDescription()); | ||
| 138 | + return walletTransactionService.createWalletTransaction(bo); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + @Override | ||
| 142 | + public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, | ||
| 143 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price) { | ||
| 144 | + // 1. 获取钱包 | ||
| 145 | + PayWalletDO payWallet = getOrCreateWallet(userId, userType); | ||
| 146 | + switch (bizType) { | ||
| 147 | + case PAYMENT_REFUND: { | ||
| 148 | + // 更新退款 | ||
| 149 | + walletMapper.updateWhenConsumptionRefund(price, payWallet.getId()); | ||
| 150 | + break; | ||
| 151 | + } | ||
| 152 | + case RECHARGE: { | ||
| 153 | + //TODO | ||
| 154 | + break; | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + // 2. 生成钱包流水 | ||
| 159 | + CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId()) | ||
| 160 | + .setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(String.valueOf(bizId)) | ||
| 161 | + .setBizType(bizType.getType()).setTitle(bizType.getDescription()); | ||
| 162 | + return walletTransactionService.createWalletTransaction(bo); | ||
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | } | 165 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
| @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | 6 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 7 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | ||
| 8 | + | ||
| 9 | +import javax.validation.Valid; | ||
| 7 | 10 | ||
| 8 | /** | 11 | /** |
| 9 | * 钱包余额流水 Service 接口 | 12 | * 钱包余额流水 Service 接口 |
| @@ -25,10 +28,10 @@ public interface PayWalletTransactionService { | @@ -25,10 +28,10 @@ public interface PayWalletTransactionService { | ||
| 25 | /** | 28 | /** |
| 26 | * 新增钱包余额流水 | 29 | * 新增钱包余额流水 |
| 27 | * | 30 | * |
| 28 | - * @param payWalletTransaction 余额流水 | ||
| 29 | - * @return id | 31 | + * @param bo 创建钱包流水 bo |
| 32 | + * @return 新建的钱包 do | ||
| 30 | */ | 33 | */ |
| 31 | - Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction); | 34 | + PayWalletTransactionDO createWalletTransaction(@Valid CreateWalletTransactionBO bo); |
| 32 | 35 | ||
| 33 | /** | 36 | /** |
| 34 | * 根据 no,获取钱包余流水 | 37 | * 根据 no,获取钱包余流水 |
| @@ -40,11 +43,10 @@ public interface PayWalletTransactionService { | @@ -40,11 +43,10 @@ public interface PayWalletTransactionService { | ||
| 40 | /** | 43 | /** |
| 41 | * 获取钱包流水 | 44 | * 获取钱包流水 |
| 42 | * | 45 | * |
| 43 | - * @param walletId 钱包编号 | ||
| 44 | * @param bizId 业务编号 | 46 | * @param bizId 业务编号 |
| 45 | * @param type 业务类型 | 47 | * @param type 业务类型 |
| 46 | * @return 钱包流水 | 48 | * @return 钱包流水 |
| 47 | */ | 49 | */ |
| 48 | - PayWalletTransactionDO getWalletTransaction(Long walletId, Long bizId, PayWalletBizTypeEnum type); | ||
| 49 | - | 50 | + PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type); |
| 51 | + | ||
| 50 | } | 52 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
| @@ -2,18 +2,18 @@ package cn.iocoder.yudao.module.pay.service.wallet; | @@ -2,18 +2,18 @@ package cn.iocoder.yudao.module.pay.service.wallet; | ||
| 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.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; |
| 5 | +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert; | ||
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 7 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; | 8 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; |
| 9 | +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | ||
| 8 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | 10 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 11 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | ||
| 9 | import lombok.extern.slf4j.Slf4j; | 12 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.stereotype.Service; | 13 | import org.springframework.stereotype.Service; |
| 11 | 14 | ||
| 12 | import javax.annotation.Resource; | 15 | import javax.annotation.Resource; |
| 13 | 16 | ||
| 14 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 15 | -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.WALLET_NOT_FOUND; | ||
| 16 | - | ||
| 17 | /** | 17 | /** |
| 18 | * 钱包流水 Service 实现类 | 18 | * 钱包流水 Service 实现类 |
| 19 | * | 19 | * |
| @@ -23,27 +23,31 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.WALLET_NOT_FO | @@ -23,27 +23,31 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.WALLET_NOT_FO | ||
| 23 | @Slf4j | 23 | @Slf4j |
| 24 | public class PayWalletTransactionServiceImpl implements PayWalletTransactionService { | 24 | public class PayWalletTransactionServiceImpl implements PayWalletTransactionService { |
| 25 | 25 | ||
| 26 | + /** | ||
| 27 | + * 钱包流水的 no 前缀 | ||
| 28 | + */ | ||
| 29 | + private static final String WALLET_NO_PREFIX = "W"; | ||
| 30 | + | ||
| 26 | @Resource | 31 | @Resource |
| 27 | private PayWalletService payWalletService; | 32 | private PayWalletService payWalletService; |
| 28 | - | ||
| 29 | @Resource | 33 | @Resource |
| 30 | private PayWalletTransactionMapper payWalletTransactionMapper; | 34 | private PayWalletTransactionMapper payWalletTransactionMapper; |
| 35 | + @Resource | ||
| 36 | + private PayNoRedisDAO noRedisDAO; | ||
| 31 | 37 | ||
| 32 | @Override | 38 | @Override |
| 33 | public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, | 39 | public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, |
| 34 | AppPayWalletTransactionPageReqVO pageVO) { | 40 | AppPayWalletTransactionPageReqVO pageVO) { |
| 35 | - PayWalletDO wallet = payWalletService.getPayWallet(userId, userType); | ||
| 36 | - if (wallet == null) { | ||
| 37 | - log.error("[getWalletTransactionPage][用户({}/{}) 钱包不存在", userId, userType); | ||
| 38 | - throw exception(WALLET_NOT_FOUND); | ||
| 39 | - } | 41 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); |
| 40 | return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO); | 42 | return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO); |
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | @Override | 45 | @Override |
| 44 | - public Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction) { | ||
| 45 | - payWalletTransactionMapper.insert(payWalletTransaction); | ||
| 46 | - return payWalletTransaction.getId(); | 46 | + public PayWalletTransactionDO createWalletTransaction(CreateWalletTransactionBO bo) { |
| 47 | + PayWalletTransactionDO transaction = PayWalletTransactionConvert.INSTANCE.convert(bo) | ||
| 48 | + .setNo(noRedisDAO.generate(WALLET_NO_PREFIX)); | ||
| 49 | + payWalletTransactionMapper.insert(transaction); | ||
| 50 | + return transaction; | ||
| 47 | } | 51 | } |
| 48 | 52 | ||
| 49 | @Override | 53 | @Override |
| @@ -52,8 +56,8 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ | @@ -52,8 +56,8 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ | ||
| 52 | } | 56 | } |
| 53 | 57 | ||
| 54 | @Override | 58 | @Override |
| 55 | - public PayWalletTransactionDO getWalletTransaction(Long walletId, Long bizId, PayWalletBizTypeEnum type) { | ||
| 56 | - return payWalletTransactionMapper.selectByWalletIdAndBiz(walletId, bizId, type.getType()); | 59 | + public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) { |
| 60 | + return payWalletTransactionMapper.selectByBiz(bizId, type.getType()); | ||
| 57 | } | 61 | } |
| 58 | 62 | ||
| 59 | } | 63 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/CreateWalletTransactionBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.service.wallet.bo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 创建钱包流水 BO | ||
| 8 | + * | ||
| 9 | + * @author jason | ||
| 10 | + */ | ||
| 11 | +@Data | ||
| 12 | +public class CreateWalletTransactionBO { | ||
| 13 | + | ||
| 14 | + // TODO @jason:bo 的话,最好加个参数校验哈; | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 钱包编号 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + private Long walletId; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 交易金额,单位分 | ||
| 24 | + * | ||
| 25 | + * 正值表示余额增加,负值表示余额减少 | ||
| 26 | + */ | ||
| 27 | + private Integer price; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 交易后余额,单位分 | ||
| 31 | + */ | ||
| 32 | + private Integer balance; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 关联业务分类 | ||
| 36 | + * | ||
| 37 | + * 枚举 {@link PayWalletBizTypeEnum#getType()} | ||
| 38 | + */ | ||
| 39 | + private Integer bizType; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 关联业务编号 | ||
| 43 | + */ | ||
| 44 | + private String bizId; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 流水说明 | ||
| 48 | + */ | ||
| 49 | + private String title; | ||
| 50 | +} |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.social; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.social; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 5 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 5 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 6 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | 7 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 7 | 8 | ||
| @@ -27,8 +28,9 @@ public interface SocialUserApi { | @@ -27,8 +28,9 @@ public interface SocialUserApi { | ||
| 27 | * 绑定社交用户 | 28 | * 绑定社交用户 |
| 28 | * | 29 | * |
| 29 | * @param reqDTO 绑定信息 | 30 | * @param reqDTO 绑定信息 |
| 31 | + * @return 社交用户 openid | ||
| 30 | */ | 32 | */ |
| 31 | - void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | 33 | + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); |
| 32 | 34 | ||
| 33 | /** | 35 | /** |
| 34 | * 取消绑定社交用户 | 36 | * 取消绑定社交用户 |
| @@ -38,16 +40,17 @@ public interface SocialUserApi { | @@ -38,16 +40,17 @@ public interface SocialUserApi { | ||
| 38 | void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); | 40 | void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); |
| 39 | 41 | ||
| 40 | /** | 42 | /** |
| 41 | - * 获得社交用户的绑定用户编号 | ||
| 42 | - * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号! | 43 | + * 获得社交用户 |
| 44 | + * | ||
| 43 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 | 45 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| 44 | * | 46 | * |
| 45 | * @param userType 用户类型 | 47 | * @param userType 用户类型 |
| 46 | * @param type 社交平台的类型 | 48 | * @param type 社交平台的类型 |
| 47 | * @param code 授权码 | 49 | * @param code 授权码 |
| 48 | * @param state state | 50 | * @param state state |
| 49 | - * @return 绑定用户编号 | 51 | + * @return 社交用户 |
| 50 | */ | 52 | */ |
| 51 | - Long getBindUserId(Integer userType, Integer type, String code, String state); | 53 | + SocialUserRespDTO getSocialUser(Integer userType, Integer type, |
| 54 | + String code, String state); | ||
| 52 | 55 | ||
| 53 | } | 56 | } |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social.dto; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 社交用户 Response DTO | ||
| 9 | + * | ||
| 10 | + * @author 芋道源码 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +@NoArgsConstructor | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +public class SocialUserRespDTO { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 社交用户 openid | ||
| 19 | + */ | ||
| 20 | + private String openid; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 关联的用户编号 | ||
| 24 | + */ | ||
| 25 | + private Long userId; | ||
| 26 | + | ||
| 27 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
| 1 | package cn.iocoder.yudao.module.system.api.social; | 1 | package cn.iocoder.yudao.module.system.api.social; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 3 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 4 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; | 5 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 5 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; | 6 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; |
| 6 | import org.springframework.stereotype.Service; | 7 | import org.springframework.stereotype.Service; |
| @@ -26,8 +27,8 @@ public class SocialUserApiImpl implements SocialUserApi { | @@ -26,8 +27,8 @@ public class SocialUserApiImpl implements SocialUserApi { | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | @Override | 29 | @Override |
| 29 | - public void bindSocialUser(SocialUserBindReqDTO reqDTO) { | ||
| 30 | - socialUserService.bindSocialUser(reqDTO); | 30 | + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
| 31 | + return socialUserService.bindSocialUser(reqDTO); | ||
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | @Override | 34 | @Override |
| @@ -37,8 +38,8 @@ public class SocialUserApiImpl implements SocialUserApi { | @@ -37,8 +38,8 @@ public class SocialUserApiImpl implements SocialUserApi { | ||
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | @Override | 40 | @Override |
| 40 | - public Long getBindUserId(Integer userType, Integer type, String code, String state) { | ||
| 41 | - return socialUserService.getBindUserId(userType, type, code, state); | 41 | + public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { |
| 42 | + return socialUserService.getSocialUser(userType, type, code, state); | ||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | } | 45 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
| @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | ||
| 9 | import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; | 9 | import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; |
| 10 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; | 10 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 11 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 11 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 12 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 12 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; | 13 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; |
| 13 | import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; | 14 | import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; |
| 14 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; | 15 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; |
| @@ -155,14 +156,14 @@ public class AdminAuthServiceImpl implements AdminAuthService { | @@ -155,14 +156,14 @@ public class AdminAuthServiceImpl implements AdminAuthService { | ||
| 155 | @Override | 156 | @Override |
| 156 | public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { | 157 | public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { |
| 157 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 | 158 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 158 | - Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), | 159 | + SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), |
| 159 | reqVO.getCode(), reqVO.getState()); | 160 | reqVO.getCode(), reqVO.getState()); |
| 160 | - if (userId == null) { | 161 | + if (socialUser == null) { |
| 161 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); | 162 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | // 获得用户 | 165 | // 获得用户 |
| 165 | - AdminUserDO user = userService.getUser(userId); | 166 | + AdminUserDO user = userService.getUser(socialUser.getUserId()); |
| 166 | if (user == null) { | 167 | if (user == null) { |
| 167 | throw exception(USER_NOT_EXISTS); | 168 | throw exception(USER_NOT_EXISTS); |
| 168 | } | 169 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.social; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.social; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 5 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 5 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; | 6 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 6 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | 7 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 7 | 8 | ||
| @@ -50,8 +51,9 @@ public interface SocialUserService { | @@ -50,8 +51,9 @@ public interface SocialUserService { | ||
| 50 | * 绑定社交用户 | 51 | * 绑定社交用户 |
| 51 | * | 52 | * |
| 52 | * @param reqDTO 绑定信息 | 53 | * @param reqDTO 绑定信息 |
| 54 | + * @return 社交用户 openid | ||
| 53 | */ | 55 | */ |
| 54 | - void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | 56 | + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); |
| 55 | 57 | ||
| 56 | /** | 58 | /** |
| 57 | * 取消绑定社交用户 | 59 | * 取消绑定社交用户 |
| @@ -64,15 +66,16 @@ public interface SocialUserService { | @@ -64,15 +66,16 @@ public interface SocialUserService { | ||
| 64 | void unbindSocialUser(Long userId, Integer userType, Integer type, String openid); | 66 | void unbindSocialUser(Long userId, Integer userType, Integer type, String openid); |
| 65 | 67 | ||
| 66 | /** | 68 | /** |
| 67 | - * 获得社交用户的绑定用户编号 | ||
| 68 | - * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号! | 69 | + * 获得社交用户 |
| 70 | + * | ||
| 69 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 | 71 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| 70 | * | 72 | * |
| 71 | * @param userType 用户类型 | 73 | * @param userType 用户类型 |
| 72 | * @param type 社交平台的类型 | 74 | * @param type 社交平台的类型 |
| 73 | * @param code 授权码 | 75 | * @param code 授权码 |
| 74 | * @param state state | 76 | * @param state state |
| 75 | - * @return 绑定用户编号 | 77 | + * @return 社交用户 |
| 76 | */ | 78 | */ |
| 77 | - Long getBindUserId(Integer userType, Integer type, String code, String state); | 79 | + SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state); |
| 80 | + | ||
| 78 | } | 81 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
| @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert; | @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | 5 | import cn.iocoder.yudao.framework.common.util.http.HttpUtils; |
| 6 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; | 6 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; |
| 7 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 7 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 8 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 8 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; |
| 9 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 10 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; | 11 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; |
| @@ -98,7 +99,7 @@ public class SocialUserServiceImpl implements SocialUserService { | @@ -98,7 +99,7 @@ public class SocialUserServiceImpl implements SocialUserService { | ||
| 98 | 99 | ||
| 99 | @Override | 100 | @Override |
| 100 | @Transactional | 101 | @Transactional |
| 101 | - public void bindSocialUser(SocialUserBindReqDTO reqDTO) { | 102 | + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
| 102 | // 获得社交用户 | 103 | // 获得社交用户 |
| 103 | SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState()); | 104 | SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState()); |
| 104 | Assert.notNull(socialUser, "社交用户不能为空"); | 105 | Assert.notNull(socialUser, "社交用户不能为空"); |
| @@ -115,6 +116,7 @@ public class SocialUserServiceImpl implements SocialUserService { | @@ -115,6 +116,7 @@ public class SocialUserServiceImpl implements SocialUserService { | ||
| 115 | .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) | 116 | .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) |
| 116 | .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); | 117 | .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); |
| 117 | socialUserBindMapper.insert(socialUserBind); | 118 | socialUserBindMapper.insert(socialUserBind); |
| 119 | + return socialUser.getOpenid(); | ||
| 118 | } | 120 | } |
| 119 | 121 | ||
| 120 | @Override | 122 | @Override |
| @@ -130,7 +132,7 @@ public class SocialUserServiceImpl implements SocialUserService { | @@ -130,7 +132,7 @@ public class SocialUserServiceImpl implements SocialUserService { | ||
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | @Override | 134 | @Override |
| 133 | - public Long getBindUserId(Integer userType, Integer type, String code, String state) { | 135 | + public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { |
| 134 | // 获得社交用户 | 136 | // 获得社交用户 |
| 135 | SocialUserDO socialUser = authSocialUser(type, code, state); | 137 | SocialUserDO socialUser = authSocialUser(type, code, state); |
| 136 | Assert.notNull(socialUser, "社交用户不能为空"); | 138 | Assert.notNull(socialUser, "社交用户不能为空"); |
| @@ -141,7 +143,7 @@ public class SocialUserServiceImpl implements SocialUserService { | @@ -141,7 +143,7 @@ public class SocialUserServiceImpl implements SocialUserService { | ||
| 141 | if (socialUserBind == null) { | 143 | if (socialUserBind == null) { |
| 142 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); | 144 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 143 | } | 145 | } |
| 144 | - return socialUserBind.getUserId(); | 146 | + return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); |
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | /** | 149 | /** |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; | 7 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 8 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 8 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 9 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 9 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; | 10 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; |
| 10 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; |
| 11 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| @@ -235,8 +236,8 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { | @@ -235,8 +236,8 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { | ||
| 235 | AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); | 236 | AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); |
| 236 | // mock 方法(绑定的用户编号) | 237 | // mock 方法(绑定的用户编号) |
| 237 | Long userId = 1L; | 238 | Long userId = 1L; |
| 238 | - when(socialUserService.getBindUserId(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), | ||
| 239 | - eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(userId); | 239 | + when(socialUserService.getSocialUser(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), |
| 240 | + eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId)); | ||
| 240 | // mock(用户) | 241 | // mock(用户) |
| 241 | AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); | 242 | AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); |
| 242 | when(userService.getUser(eq(userId))).thenReturn(user); | 243 | when(userService.getUser(eq(userId))).thenReturn(user); |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
| @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 4 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; | 4 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; |
| 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 7 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | ||
| 7 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; |
| 8 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 9 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; | 10 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; |
| @@ -195,10 +196,11 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { | @@ -195,10 +196,11 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { | ||
| 195 | .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(socialUser.getId())); | 196 | .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(socialUser.getId())); |
| 196 | 197 | ||
| 197 | // 调用 | 198 | // 调用 |
| 198 | - socialUserService.bindSocialUser(reqDTO); | 199 | + String openid = socialUserService.bindSocialUser(reqDTO); |
| 199 | // 断言 | 200 | // 断言 |
| 200 | List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectList(); | 201 | List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectList(); |
| 201 | assertEquals(1, socialUserBinds.size()); | 202 | assertEquals(1, socialUserBinds.size()); |
| 203 | + assertEquals(socialUser.getOpenid(), openid); | ||
| 202 | } | 204 | } |
| 203 | 205 | ||
| 204 | @Test | 206 | @Test |
| @@ -232,25 +234,26 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { | @@ -232,25 +234,26 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { | ||
| 232 | } | 234 | } |
| 233 | 235 | ||
| 234 | @Test | 236 | @Test |
| 235 | - public void testGetBindUserId() { | 237 | + public void testGetSocialUser() { |
| 236 | // 准备参数 | 238 | // 准备参数 |
| 237 | Integer userType = UserTypeEnum.ADMIN.getValue(); | 239 | Integer userType = UserTypeEnum.ADMIN.getValue(); |
| 238 | Integer type = SocialTypeEnum.GITEE.getType(); | 240 | Integer type = SocialTypeEnum.GITEE.getType(); |
| 239 | String code = "tudou"; | 241 | String code = "tudou"; |
| 240 | String state = "yuanma"; | 242 | String state = "yuanma"; |
| 241 | // mock 社交用户 | 243 | // mock 社交用户 |
| 242 | - SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state); | ||
| 243 | - socialUserMapper.insert(socialUser); | 244 | + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state); |
| 245 | + socialUserMapper.insert(socialUserDO); | ||
| 244 | // mock 社交用户的绑定 | 246 | // mock 社交用户的绑定 |
| 245 | Long userId = randomLong(); | 247 | Long userId = randomLong(); |
| 246 | SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType).setUserId(userId) | 248 | SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType).setUserId(userId) |
| 247 | - .setSocialType(type).setSocialUserId(socialUser.getId()); | 249 | + .setSocialType(type).setSocialUserId(socialUserDO.getId()); |
| 248 | socialUserBindMapper.insert(socialUserBind); | 250 | socialUserBindMapper.insert(socialUserBind); |
| 249 | 251 | ||
| 250 | // 调用 | 252 | // 调用 |
| 251 | - Long result = socialUserService.getBindUserId(userType, type, code, state); | 253 | + SocialUserRespDTO socialUser = socialUserService.getSocialUser(userType, type, code, state); |
| 252 | // 断言 | 254 | // 断言 |
| 253 | - assertEquals(userId, result); | 255 | + assertEquals(userId, socialUser.getUserId()); |
| 256 | + assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); | ||
| 254 | } | 257 | } |
| 255 | 258 | ||
| 256 | } | 259 | } |
yudao-server/pom.xml
| @@ -41,24 +41,24 @@ | @@ -41,24 +41,24 @@ | ||
| 41 | <artifactId>yudao-spring-boot-starter-biz-error-code</artifactId> | 41 | <artifactId>yudao-spring-boot-starter-biz-error-code</artifactId> |
| 42 | </dependency> | 42 | </dependency> |
| 43 | 43 | ||
| 44 | - <!-- 数据报表 --> | 44 | + <!-- 数据报表。默认注释,保证编译速度 --> |
| 45 | <!-- <dependency>--> | 45 | <!-- <dependency>--> |
| 46 | <!-- <groupId>cn.iocoder.boot</groupId>--> | 46 | <!-- <groupId>cn.iocoder.boot</groupId>--> |
| 47 | <!-- <artifactId>yudao-module-report-biz</artifactId>--> | 47 | <!-- <artifactId>yudao-module-report-biz</artifactId>--> |
| 48 | <!-- <version>${revision}</version>--> | 48 | <!-- <version>${revision}</version>--> |
| 49 | <!-- </dependency>--> | 49 | <!-- </dependency>--> |
| 50 | - <!-- 工作流 --> | 50 | + <!-- 工作流。默认注释,保证编译速度 --> |
| 51 | <!-- <dependency>--> | 51 | <!-- <dependency>--> |
| 52 | <!-- <groupId>cn.iocoder.boot</groupId>--> | 52 | <!-- <groupId>cn.iocoder.boot</groupId>--> |
| 53 | <!-- <artifactId>yudao-module-bpm-biz</artifactId>--> | 53 | <!-- <artifactId>yudao-module-bpm-biz</artifactId>--> |
| 54 | <!-- <version>${revision}</version>--> | 54 | <!-- <version>${revision}</version>--> |
| 55 | <!-- </dependency>--> | 55 | <!-- </dependency>--> |
| 56 | <!-- 支付服务。默认注释,保证编译速度 --> | 56 | <!-- 支付服务。默认注释,保证编译速度 --> |
| 57 | -<!-- <dependency>--> | ||
| 58 | -<!-- <groupId>cn.iocoder.boot</groupId>--> | ||
| 59 | -<!-- <artifactId>yudao-module-pay-biz</artifactId>--> | ||
| 60 | -<!-- <version>${revision}</version>--> | ||
| 61 | -<!-- </dependency>--> | 57 | + <dependency> |
| 58 | + <groupId>cn.iocoder.boot</groupId> | ||
| 59 | + <artifactId>yudao-module-pay-biz</artifactId> | ||
| 60 | + <version>${revision}</version> | ||
| 61 | + </dependency> | ||
| 62 | 62 | ||
| 63 | <!-- 微信公众号模块。默认注释,保证编译速度 --> | 63 | <!-- 微信公众号模块。默认注释,保证编译速度 --> |
| 64 | <!-- <dependency>--> | 64 | <!-- <dependency>--> |
| @@ -68,21 +68,21 @@ | @@ -68,21 +68,21 @@ | ||
| 68 | <!-- </dependency>--> | 68 | <!-- </dependency>--> |
| 69 | 69 | ||
| 70 | <!-- 商城相关模块。默认注释,保证编译速度 --> | 70 | <!-- 商城相关模块。默认注释,保证编译速度 --> |
| 71 | -<!-- <dependency>--> | ||
| 72 | -<!-- <groupId>cn.iocoder.boot</groupId>--> | ||
| 73 | -<!-- <artifactId>yudao-module-promotion-biz</artifactId>--> | ||
| 74 | -<!-- <version>${revision}</version>--> | ||
| 75 | -<!-- </dependency>--> | ||
| 76 | -<!-- <dependency>--> | ||
| 77 | -<!-- <groupId>cn.iocoder.boot</groupId>--> | ||
| 78 | -<!-- <artifactId>yudao-module-product-biz</artifactId>--> | ||
| 79 | -<!-- <version>${revision}</version>--> | ||
| 80 | -<!-- </dependency>--> | ||
| 81 | -<!-- <dependency>--> | ||
| 82 | -<!-- <groupId>cn.iocoder.boot</groupId>--> | ||
| 83 | -<!-- <artifactId>yudao-module-trade-biz</artifactId>--> | ||
| 84 | -<!-- <version>${revision}</version>--> | ||
| 85 | -<!-- </dependency>--> | 71 | + <dependency> |
| 72 | + <groupId>cn.iocoder.boot</groupId> | ||
| 73 | + <artifactId>yudao-module-promotion-biz</artifactId> | ||
| 74 | + <version>${revision}</version> | ||
| 75 | + </dependency> | ||
| 76 | + <dependency> | ||
| 77 | + <groupId>cn.iocoder.boot</groupId> | ||
| 78 | + <artifactId>yudao-module-product-biz</artifactId> | ||
| 79 | + <version>${revision}</version> | ||
| 80 | + </dependency> | ||
| 81 | + <dependency> | ||
| 82 | + <groupId>cn.iocoder.boot</groupId> | ||
| 83 | + <artifactId>yudao-module-trade-biz</artifactId> | ||
| 84 | + <version>${revision}</version> | ||
| 85 | + </dependency> | ||
| 86 | 86 | ||
| 87 | <!-- spring boot 配置所需依赖 --> | 87 | <!-- spring boot 配置所需依赖 --> |
| 88 | <dependency> | 88 | <dependency> |
yudao-server/src/main/resources/application-local.yaml
| @@ -165,16 +165,20 @@ debug: false | @@ -165,16 +165,20 @@ debug: false | ||
| 165 | --- #################### 微信公众号、小程序相关配置 #################### | 165 | --- #################### 微信公众号、小程序相关配置 #################### |
| 166 | wx: | 166 | wx: |
| 167 | mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 | 167 | mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 |
| 168 | - app-id: wx041349c6f39b268b | ||
| 169 | - secret: 5abee519483bc9f8cb37ce280e814bd0 | 168 | +# app-id: wx041349c6f39b268b |
| 169 | +# secret: 5abee519483bc9f8cb37ce280e814bd0 | ||
| 170 | + app-id: wx5b23ba7a5589ecbb # 测试号 | ||
| 171 | + secret: 2a7b3b20c537e52e74afd395eb85f61f | ||
| 170 | # 存储配置,解决 AccessToken 的跨节点的共享 | 172 | # 存储配置,解决 AccessToken 的跨节点的共享 |
| 171 | config-storage: | 173 | config-storage: |
| 172 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 | 174 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 173 | key-prefix: wx # Redis Key 的前缀 | 175 | key-prefix: wx # Redis Key 的前缀 |
| 174 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 | 176 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 175 | miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 | 177 | miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 |
| 176 | - appid: wx62056c0d5e8db250 | ||
| 177 | - secret: 333ae72f41552af1e998fe1f54e1584a | 178 | +# appid: wx62056c0d5e8db250 |
| 179 | +# secret: 333ae72f41552af1e998fe1f54e1584a | ||
| 180 | + appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 | ||
| 181 | + secret: 6f270509224a7ae1296bbf1c8cb97aed | ||
| 178 | config-storage: | 182 | config-storage: |
| 179 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 | 183 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 180 | key-prefix: wa # Redis Key 的前缀 | 184 | key-prefix: wa # Redis Key 的前缀 |
| @@ -219,6 +223,11 @@ justauth: | @@ -219,6 +223,11 @@ justauth: | ||
| 219 | client-secret: ${wx.miniapp.secret} | 223 | client-secret: ${wx.miniapp.secret} |
| 220 | ignore-check-redirect-uri: true | 224 | ignore-check-redirect-uri: true |
| 221 | ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 | 225 | ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 |
| 226 | + WECHAT_MP: # 微信公众号 | ||
| 227 | + client-id: ${wx.mp.app-id} | ||
| 228 | + client-secret: ${wx.mp.secret} | ||
| 229 | + ignore-check-redirect-uri: true | ||
| 230 | + ignore-check-state: true # 微信公众号,未调用后端的 getSocialAuthorizeUrl 方法,所以无法进行 state 校验 TODO 芋艿:后续考虑支持 | ||
| 222 | 231 | ||
| 223 | cache: | 232 | cache: |
| 224 | type: REDIS | 233 | type: REDIS |
yudao-ui-admin/src/utils/constants.js
| @@ -163,6 +163,10 @@ export const PayChannelEnum = { | @@ -163,6 +163,10 @@ export const PayChannelEnum = { | ||
| 163 | MOCK : { | 163 | MOCK : { |
| 164 | "code": "mock", | 164 | "code": "mock", |
| 165 | "name": "模拟支付" | 165 | "name": "模拟支付" |
| 166 | + }, | ||
| 167 | + WALLET : { | ||
| 168 | + "code": "wallet", | ||
| 169 | + "name": "钱包支付" | ||
| 166 | } | 170 | } |
| 167 | } | 171 | } |
| 168 | 172 |
yudao-ui-admin/src/views/pay/app/components/mockChannelForm.vue renamed to yudao-ui-admin/src/views/pay/app/components/noneConfigChannelForm.vue
| @@ -5,7 +5,8 @@ | @@ -5,7 +5,8 @@ | ||
| 5 | <el-form-item label-width="180px" label="渠道状态" prop="status"> | 5 | <el-form-item label-width="180px" label="渠道状态" prop="status"> |
| 6 | <el-radio-group v-model="formData.status" size="medium"> | 6 | <el-radio-group v-model="formData.status" size="medium"> |
| 7 | <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)" | 7 | <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)" |
| 8 | - :label="parseInt(dict.value)"> | 8 | + :label="parseInt(dict.value)" |
| 9 | + > | ||
| 9 | {{ dict.label }} | 10 | {{ dict.label }} |
| 10 | </el-radio> | 11 | </el-radio> |
| 11 | </el-radio-group> | 12 | </el-radio-group> |
| @@ -22,16 +23,16 @@ | @@ -22,16 +23,16 @@ | ||
| 22 | </div> | 23 | </div> |
| 23 | </template> | 24 | </template> |
| 24 | <script> | 25 | <script> |
| 25 | -import { createChannel, getChannel, updateChannel } from "@/api/pay/channel"; | ||
| 26 | -import { CommonStatusEnum } from "@/utils/constants"; | 26 | +import { createChannel, getChannel, updateChannel } from '@/api/pay/channel' |
| 27 | +import { CommonStatusEnum } from '@/utils/constants' | ||
| 27 | 28 | ||
| 28 | export default { | 29 | export default { |
| 29 | - name: "mockChannelForm", | 30 | + name: 'noneConfigChannelForm', |
| 30 | data() { | 31 | data() { |
| 31 | return { | 32 | return { |
| 32 | dialogVisible: false, | 33 | dialogVisible: false, |
| 33 | formLoading: false, | 34 | formLoading: false, |
| 34 | - title:'', | 35 | + title: '', |
| 35 | formData: { | 36 | formData: { |
| 36 | appId: '', | 37 | appId: '', |
| 37 | code: '', | 38 | code: '', |
| @@ -39,54 +40,54 @@ export default { | @@ -39,54 +40,54 @@ export default { | ||
| 39 | feeRate: 0, | 40 | feeRate: 0, |
| 40 | remark: '', | 41 | remark: '', |
| 41 | config: { | 42 | config: { |
| 42 | - name: 'mock-conf' | 43 | + name: 'none-config' |
| 43 | } | 44 | } |
| 44 | }, | 45 | }, |
| 45 | rules: { | 46 | rules: { |
| 46 | - status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }] | 47 | + status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }] |
| 47 | } | 48 | } |
| 48 | } | 49 | } |
| 49 | }, | 50 | }, |
| 50 | methods: { | 51 | methods: { |
| 51 | open(appId, code) { | 52 | open(appId, code) { |
| 52 | - this.dialogVisible = true; | ||
| 53 | - this.formLoading = true; | ||
| 54 | - this.reset(appId, code); | 53 | + this.dialogVisible = true |
| 54 | + this.formLoading = true | ||
| 55 | + this.reset(appId, code) | ||
| 55 | getChannel(appId, code).then(response => { | 56 | getChannel(appId, code).then(response => { |
| 56 | if (response.data && response.data.id) { | 57 | if (response.data && response.data.id) { |
| 57 | - this.formData = response.data; | ||
| 58 | - this.formData.config = JSON.parse(response.data.config); | 58 | + this.formData = response.data |
| 59 | + this.formData.config = JSON.parse(response.data.config) | ||
| 59 | } | 60 | } |
| 60 | this.title = !this.formData.id ? '创建支付渠道' : '编辑支付渠道' | 61 | this.title = !this.formData.id ? '创建支付渠道' : '编辑支付渠道' |
| 61 | }).finally(() => { | 62 | }).finally(() => { |
| 62 | - this.formLoading = false; | ||
| 63 | - }); | 63 | + this.formLoading = false |
| 64 | + }) | ||
| 64 | }, | 65 | }, |
| 65 | close() { | 66 | close() { |
| 66 | - this.dialogVisible = false; | ||
| 67 | - this.reset(undefined, undefined); | 67 | + this.dialogVisible = false |
| 68 | + this.reset(undefined, undefined) | ||
| 68 | }, | 69 | }, |
| 69 | submitForm() { | 70 | submitForm() { |
| 70 | this.$refs['form'].validate(valid => { | 71 | this.$refs['form'].validate(valid => { |
| 71 | if (!valid) { | 72 | if (!valid) { |
| 72 | return | 73 | return |
| 73 | } | 74 | } |
| 74 | - const data = { ...this.formData }; | ||
| 75 | - data.config = JSON.stringify(this.formData.config); | 75 | + const data = { ...this.formData } |
| 76 | + data.config = JSON.stringify(this.formData.config) | ||
| 76 | if (!data.id) { | 77 | if (!data.id) { |
| 77 | createChannel(data).then(response => { | 78 | createChannel(data).then(response => { |
| 78 | - this.$modal.msgSuccess("新增成功"); | 79 | + this.$modal.msgSuccess('新增成功') |
| 79 | this.$emit('success') | 80 | this.$emit('success') |
| 80 | - this.close(); | ||
| 81 | - }); | 81 | + this.close() |
| 82 | + }) | ||
| 82 | } else { | 83 | } else { |
| 83 | updateChannel(data).then(response => { | 84 | updateChannel(data).then(response => { |
| 84 | - this.$modal.msgSuccess("修改成功"); | 85 | + this.$modal.msgSuccess('修改成功') |
| 85 | this.$emit('success') | 86 | this.$emit('success') |
| 86 | - this.close(); | 87 | + this.close() |
| 87 | }) | 88 | }) |
| 88 | } | 89 | } |
| 89 | - }); | 90 | + }) |
| 90 | }, | 91 | }, |
| 91 | /** 重置表单 */ | 92 | /** 重置表单 */ |
| 92 | reset(appId, code) { | 93 | reset(appId, code) { |
| @@ -97,11 +98,11 @@ export default { | @@ -97,11 +98,11 @@ export default { | ||
| 97 | remark: '', | 98 | remark: '', |
| 98 | feeRate: 0, | 99 | feeRate: 0, |
| 99 | config: { | 100 | config: { |
| 100 | - name: 'mock-conf' | 101 | + name: 'none-config' |
| 101 | } | 102 | } |
| 102 | } | 103 | } |
| 103 | this.resetForm('form') | 104 | this.resetForm('form') |
| 104 | - }, | 105 | + } |
| 105 | } | 106 | } |
| 106 | } | 107 | } |
| 107 | </script> | 108 | </script> |
yudao-ui-admin/src/views/pay/app/index.vue
| @@ -170,6 +170,19 @@ | @@ -170,6 +170,19 @@ | ||
| 170 | </template> | 170 | </template> |
| 171 | </el-table-column> | 171 | </el-table-column> |
| 172 | </el-table-column> | 172 | </el-table-column> |
| 173 | + <el-table-column label="钱包支付配置" align="center"> | ||
| 174 | + <el-table-column :label="payChannelEnum.WALLET.name" align="center"> | ||
| 175 | + <template v-slot="scope"> | ||
| 176 | + <el-button type="success" icon="el-icon-check" circle | ||
| 177 | + v-if="isChannelExists(scope.row.channelCodes, payChannelEnum.WALLET.code)" | ||
| 178 | + @click="handleChannel(scope.row, payChannelEnum.WALLET.code)"> | ||
| 179 | + </el-button> | ||
| 180 | + <el-button v-else type="danger" icon="el-icon-close" circle | ||
| 181 | + @click="handleChannel(scope.row, payChannelEnum.WALLET.code)"> | ||
| 182 | + </el-button> | ||
| 183 | + </template> | ||
| 184 | + </el-table-column> | ||
| 185 | + </el-table-column> | ||
| 173 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | 186 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| 174 | <template v-slot="scope"> | 187 | <template v-slot="scope"> |
| 175 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" | 188 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" |
| @@ -219,7 +232,7 @@ | @@ -219,7 +232,7 @@ | ||
| 219 | <!-- 对话框(支付应用的配置) --> | 232 | <!-- 对话框(支付应用的配置) --> |
| 220 | <weixin-channel-form ref="weixinChannelFormRef" @success="getList" /> | 233 | <weixin-channel-form ref="weixinChannelFormRef" @success="getList" /> |
| 221 | <alipay-channel-form ref="alipayChannelFormRef" @success="getList" /> | 234 | <alipay-channel-form ref="alipayChannelFormRef" @success="getList" /> |
| 222 | - <mock-channel-form ref="mockChannelFormRef" @success="getList" /> | 235 | + <none-config-channel-form ref="noneConfigChannelFormRef" @success="getList" /> |
| 223 | </div> | 236 | </div> |
| 224 | </template> | 237 | </template> |
| 225 | 238 | ||
| @@ -228,14 +241,14 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage } | @@ -228,14 +241,14 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage } | ||
| 228 | import { PayChannelEnum, CommonStatusEnum } from "@/utils/constants"; | 241 | import { PayChannelEnum, CommonStatusEnum } from "@/utils/constants"; |
| 229 | import weixinChannelForm from "@/views/pay/app/components/weixinChannelForm"; | 242 | import weixinChannelForm from "@/views/pay/app/components/weixinChannelForm"; |
| 230 | import alipayChannelForm from "@/views/pay/app/components/alipayChannelForm"; | 243 | import alipayChannelForm from "@/views/pay/app/components/alipayChannelForm"; |
| 231 | -import mockChannelForm from '@/views/pay/app/components/mockChannelForm'; | 244 | +import noneConfigChannelForm from '@/views/pay/app/components/noneConfigChannelForm'; |
| 232 | 245 | ||
| 233 | export default { | 246 | export default { |
| 234 | name: "PayApp", | 247 | name: "PayApp", |
| 235 | components: { | 248 | components: { |
| 236 | weixinChannelForm, | 249 | weixinChannelForm, |
| 237 | alipayChannelForm, | 250 | alipayChannelForm, |
| 238 | - mockChannelForm | 251 | + noneConfigChannelForm |
| 239 | }, | 252 | }, |
| 240 | data() { | 253 | data() { |
| 241 | return { | 254 | return { |
| @@ -391,7 +404,11 @@ export default { | @@ -391,7 +404,11 @@ export default { | ||
| 391 | return | 404 | return |
| 392 | } | 405 | } |
| 393 | if (code === 'mock') { | 406 | if (code === 'mock') { |
| 394 | - this.$refs['mockChannelFormRef'].open(row.id, code); | 407 | + this.$refs['noneConfigChannelFormRef'].open(row.id, code); |
| 408 | + return | ||
| 409 | + } | ||
| 410 | + if (code === 'wallet') { | ||
| 411 | + this.$refs['noneConfigChannelFormRef'].open(row.id, code); | ||
| 395 | return | 412 | return |
| 396 | } | 413 | } |
| 397 | }, | 414 | }, |
yudao-ui-admin/src/views/pay/cashier/index.vue
| @@ -136,6 +136,10 @@ export default { | @@ -136,6 +136,10 @@ export default { | ||
| 136 | name: '模拟支付', | 136 | name: '模拟支付', |
| 137 | icon: require("@/assets/images/pay/icon/mock.svg"), | 137 | icon: require("@/assets/images/pay/icon/mock.svg"), |
| 138 | code: "mock" | 138 | code: "mock" |
| 139 | + }, { | ||
| 140 | + name: '钱包支付', | ||
| 141 | + icon: require("@/assets/images/pay/icon/mock.svg"), | ||
| 142 | + code: "wallet" | ||
| 139 | }], | 143 | }], |
| 140 | submitLoading: false, // 提交支付的 loading | 144 | submitLoading: false, // 提交支付的 loading |
| 141 | interval: undefined, // 定时任务,轮询是否完成支付 | 145 | interval: undefined, // 定时任务,轮询是否完成支付 |