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

# Conflicts:
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
This commit is contained in:
puhui999 2023-09-20 10:14:43 +08:00
commit 52848d6341
56 changed files with 989 additions and 411 deletions

View File

@ -2,41 +2,50 @@
create table trade_config
(
id bigint auto_increment comment '自增主键' primary key,
brokerage_enabled bit default 1 not null comment '是否启用分佣',
brokerage_enabled_condition tinyint default 0 not null comment '分佣模式1-人人分销 2-指定分销',
brokerage_bind_mode tinyint default 0 not null comment '分销关系绑定模式: 1-没有推广人2-新用户, 3-扫码覆盖',
brokerage_post_urls varchar(2000) default '' null comment '分销海报图地址数组',
brokerage_first_percent int default 0 not null comment '一级返佣比例',
brokerage_second_percent int default 0 not null comment '二级返佣比例',
brokerage_withdraw_min_price int default 0 not null comment '用户提现最低金额',
brokerage_bank_names varchar(200) default '' not null comment '提现银行字典类型=brokerage_bank_name',
brokerage_frozen_days int default 7 not null comment '佣金冻结时间()',
brokerage_withdraw_type varchar(32) default '1,2,3,4' not null comment '提现方式1-钱包2-银行卡3-微信4-支付宝',
creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
brokerage_enabled bit default 1 not null comment '是否启用分佣',
brokerage_enabled_condition tinyint default 0 not null comment '分佣模式1-人人分销 2-指定分销',
brokerage_bind_mode tinyint default 0 not null comment '分销关系绑定模式: 1-没有推广人2-新用户, 3-扫码覆盖',
brokerage_post_urls varchar(2000) default '' null comment '分销海报图地址数组',
brokerage_first_percent int default 0 not null comment '一级返佣比例',
brokerage_second_percent int default 0 not null comment '二级返佣比例',
brokerage_withdraw_min_price int default 0 not null comment '用户提现最低金额',
brokerage_bank_names varchar(200) default '' not null comment '提现银行字典类型=brokerage_bank_name',
brokerage_frozen_days int default 7 not null comment '佣金冻结时间()',
brokerage_withdraw_type varchar(32) default '1,2,3,4' not null comment '提现方式1-钱包2-银行卡3-微信4-支付宝',
creator varchar(64) default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
) comment '交易中心配置';
# alter table trade_brokerage_user
# add level int not null default 1 comment '等级' after frozen_price;
# alter table trade_brokerage_user
# add path varchar(2000) null comment '路径' after level;
-- 增加分销用户扩展表
create table trade_brokerage_user
(
id bigint auto_increment comment '用户编号' primary key,
bind_user_id bigint null comment '推广员编号',
bind_user_time datetime null comment '推广员绑定时间',
brokerage_enabled bit default 1 not null comment '是否成为推广员',
brokerage_time datetime null comment '成为分销员时间',
price int default 0 not null comment '可用佣金',
frozen_price int default 0 not null comment '冻结佣金',
creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
) comment '分销用户';
bind_user_id bigint null comment '推广员编号',
bind_user_time datetime null comment '推广员绑定时间',
brokerage_enabled bit default 1 not null comment '是否成为推广员',
brokerage_time datetime null comment '成为分销员时间',
price int default 0 not null comment '可用佣金',
frozen_price int default 0 not null comment '冻结佣金',
level int default 1 not null comment '等级',
path varchar(2000) null comment '路径',
creator varchar(64) default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
)
comment '分销用户';
create index idx_invite_user_id on trade_brokerage_user (bind_user_id) comment '推广员编号';
create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是否成为推广员';
@ -44,26 +53,26 @@ create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是
create table trade_brokerage_record
(
id int auto_increment comment '编号'
id int auto_increment comment '编号'
primary key,
user_id bigint not null comment '用户编号',
biz_id varchar(64) default '' not null comment '业务编号',
biz_type tinyint default 0 not null comment '业务类型1-订单2-提现',
title varchar(64) default '' not null comment '标题',
price int default 0 not null comment '金额',
total_price int default 0 not null comment '当前总佣金',
description varchar(500) default '' not null comment '说明',
status tinyint default 0 not null comment '状态0-待结算1-已结算2-已取消',
frozen_days int default 0 not null comment '冻结时间',
unfreeze_time datetime null comment '解冻时间',
source_user_type tinyint not null comment '来源用户类型1-一级推广用户2-二级推广用户',
source_user_id bigint not null comment '来源用户编号',
creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
user_id bigint not null comment '用户编号',
biz_id varchar(64) default '' not null comment '业务编号',
biz_type tinyint default 0 not null comment '业务类型1-订单2-提现',
title varchar(64) default '' not null comment '标题',
price int default 0 not null comment '金额',
total_price int default 0 not null comment '当前总佣金',
description varchar(500) default '' not null comment '说明',
status tinyint default 0 not null comment '状态0-待结算1-已结算2-已取消',
frozen_days int default 0 not null comment '冻结时间',
unfreeze_time datetime null comment '解冻时间',
source_user_level int not null comment '来源用户等级',
source_user_id bigint not null comment '来源用户编号',
creator varchar(64) default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
)
comment '佣金记录';
@ -76,26 +85,26 @@ create table trade_brokerage_withdraw
(
id int auto_increment comment '编号'
primary key,
user_id bigint not null comment '用户编号',
price int default 0 not null comment '提现金额',
fee_price int default 0 not null comment '提现手续费',
total_price int default 0 not null comment '当前总佣金',
type tinyint default 0 not null comment '提现类型1-钱包2-银行卡3-微信4-支付宝',
name varchar(64) null comment '真实姓名',
account_no varchar(64) null comment '账号',
bank_name varchar(100) null comment '银行名称',
bank_address varchar(200) null comment '开户地址',
account_qr_code_url varchar(512) null comment '收款码',
status tinyint(2) default 0 not null comment '状态0-审核中10-审核通过 20-审核不通过预留11 - 提现成功21-提现失败',
audit_reason varchar(128) null comment '审核驳回原因',
audit_time datetime null comment '审核时间',
remark varchar(500) null comment '备注',
creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
user_id bigint not null comment '用户编号',
price int default 0 not null comment '提现金额',
fee_price int default 0 not null comment '提现手续费',
total_price int default 0 not null comment '当前总佣金',
type tinyint default 0 not null comment '提现类型1-钱包2-银行卡3-微信4-支付宝',
name varchar(64) null comment '真实姓名',
account_no varchar(64) null comment '账号',
bank_name varchar(100) null comment '银行名称',
bank_address varchar(200) null comment '开户地址',
account_qr_code_url varchar(512) null comment '收款码',
status tinyint(2) default 0 not null comment '状态0-审核中10-审核通过 20-审核不通过预留11 - 提现成功21-提现失败',
audit_reason varchar(128) null comment '审核驳回原因',
audit_time datetime null comment '审核时间',
remark varchar(500) null comment '备注',
creator varchar(64) default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除',
tenant_id bigint default 0 not null comment '租户编号'
)
comment '佣金提现';
@ -139,12 +148,12 @@ values ('brokerage_record_status', '待结算', 0, 0),
insert into system_dict_type(type, name)
values ('brokerage_withdraw_status', '佣金提现状态');
insert into system_dict_data(dict_type, label, value, sort)
values ('brokerage_withdraw_status', '审核中', 0, 0),
('brokerage_withdraw_status', '审核通过', 10, 10),
('brokerage_withdraw_status', '提现成功', 11, 11),
('brokerage_withdraw_status', '审核不通过', 20, 20),
('brokerage_withdraw_status', '提现失败', 21, 21);
insert into system_dict_data(dict_type, label, value, sort, color_type)
values ('brokerage_withdraw_status', '审核中', 0, 0, ''),
('brokerage_withdraw_status', '审核通过', 10, 10, 'success'),
('brokerage_withdraw_status', '提现成功', 11, 11, 'success'),
('brokerage_withdraw_status', '审核不通过', 20, 20, 'danger'),
('brokerage_withdraw_status', '提现失败', 21, 21, 'danger');
insert into system_dict_type(type, name)
values ('brokerage_bank_name', '佣金提现银行');
@ -220,4 +229,10 @@ SELECT @parentId := LAST_INSERT_ID();
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);
VALUES ('佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);
-- 站内信模板
INSERT INTO `ruoyi-vue-pro`.system_notify_template (name, code, nickname, content, type, params, status)
VALUES
('佣金提现审核通过', 'brokerage_withdraw_audit_approve', 'system', '您在{createTime}提现{price}元的申请已通过审核', 2, '["createTime","price"]', 0),
('佣金提现审核不通过', 'brokerage_withdraw_audit_reject', 'system', '您在{createTime}提现{price}元的申请未通过审核原因{reason}', 2, '["createTime","price","reason"]', 0);

View File

@ -50,6 +50,7 @@ public class LocalDateTimeUtils {
* @return 指定时间
*/
public static LocalDateTime buildTime(String timeStr) {
// TODO @puhui999这个方法的实现 LocalDateTimeUtil.parse() 的差异点是啥呀
return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
}

View File

@ -100,6 +100,14 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> {
return betweenIfPresent(column, val1, val2);
}
// TODO @疯狂这个是 mysql 独有的不好做成通用的哈如果多层级有没可能先查询一个层级再查询一个层级形成 set 直接去 in
public LambdaQueryWrapperX<T> findInSetIfPresent(SFunction<T, ?> column, Object val) {
if (val != null) {
return (LambdaQueryWrapperX<T>) super.apply("FIND_IN_SET({0}, " + columnToString(column) + ")", val);
}
return this;
}
// ========== 重写父类方法方便链式调用 ==========
@Override

View File

@ -64,14 +64,14 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
@Override
public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return ${classNameVar}Mapper.selectById(id);
}
@Override
public List<${table.className}DO> get${simpleClassName}List(Collection<${primaryColumn.javaType}> ids) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return ${classNameVar}Mapper.selectBatchIds(ids);
}

View File

@ -31,7 +31,7 @@ public interface CombinationRecordApi {
boolean isCombinationRecordSuccess(Long userId, Long orderId);
/**
* 更新拼团状态为 成功
* 更新拼团状态为成功
*
* @param userId 用户编号
* @param orderId 订单编号
@ -39,7 +39,7 @@ public interface CombinationRecordApi {
void updateRecordStatusToSuccess(Long userId, Long orderId);
/**
* 更新拼团状态为 失败
* 更新拼团状态为失败
*
* @param userId 用户编号
* @param orderId 订单编号

View File

@ -7,6 +7,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill;
*/
public interface SeckillActivityApi {
// TODO @puhui999activityId 改成 id 好点哈
/**
* 更新秒杀库存
*

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
@ -25,6 +24,7 @@ import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "管理后台 - 砍价活动")
@RestController
@ -79,7 +79,9 @@ public class BargainActivityController {
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(pageResult.getList(), BargainActivityDO::getSpuId));
// 拼接数据
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, spuList));
}

View File

@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
@ -25,6 +24,7 @@ import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "用户 App - 砍价活动")
@RestController
@ -39,27 +39,27 @@ public class AppBargainActivityController {
@GetMapping("/page")
@Operation(summary = "获得砍价活动分页")
public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityAppPage(pageReqVO);
PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPageForApp(pageReqVO);
if (CollUtil.isEmpty(result.getList())) {
return success(PageResult.empty(result.getTotal()));
}
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(result.getList(), BargainActivityDO::getSpuId));
// 拼接数据
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(result.getList(), BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertAppPage(result, spuList));
}
// TODO 芋艿增加 Spring Cache
@GetMapping("/list")
@Operation(summary = "获得砍价活动列表", description = "用于小程序首页")
@Parameter(name = "count", description = "需要展示的数量", example = "6")
public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
@RequestParam(name = "count", defaultValue = "6") Integer count) {
List<BargainActivityDO> list = bargainActivityService.getBargainActivityAppList(count);
List<BargainActivityDO> list = bargainActivityService.getBargainActivityListForApp(count);
if (CollUtil.isEmpty(list)) {
return success(BargainActivityConvert.INSTANCE.convertAppList(list));
}
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(list, BargainActivityDO::getSpuId));
// TODO 芋艿增加 Spring Cache
// 拼接数据
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertAppList(list, spuList));
}
@ -71,9 +71,9 @@ public class AppBargainActivityController {
if (activity == null) {
return success(null);
}
// 拼接数据
ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId());
return success(BargainActivityConvert.INSTANCE.convert1(activity, spu));
return success(BargainActivityConvert.INSTANCE.convert(activity, spu));
}
}

View File

@ -53,19 +53,20 @@ public class AppSeckillActivityController {
@GetMapping("/get-now")
@Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用")
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
// 1获取当前时间处在哪个秒杀阶段
// 1. 获取当前时间处在哪个秒杀阶段
// TODO @puhui999可以考虑在 service 写个方法这样 controller 不用关注过多逻辑
List<SeckillConfigDO> configList = configService.getSeckillConfigList();
SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
// 11 时段不存在直接返回 null
if (filteredConfig == null) {
if (filteredConfig == null) { // 时段不存在直接返回 null
return success(null);
}
// 2查询满足当前阶段的活动
// 2. 查询满足当前阶段的活动
// TODO @puhui999最好直接返回开启的不多查询数据
List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
// 21 获取 spu 信息
// 3 获取 spu 信息
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(filteredList, SeckillActivityDO::getSpuId));
// TODO 芋艿需要增加 spring cache
return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
@ -74,9 +75,10 @@ public class AppSeckillActivityController {
@GetMapping("/page")
@Operation(summary = "获得秒杀活动分页")
public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
// 1查询满足当前阶段的活动
// 1. 查询满足当前阶段的活动
PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
// 11 获取 spu 信息
// 2. 拼接数据
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
}
@ -86,15 +88,15 @@ public class AppSeckillActivityController {
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
// 1获取当前时间处在哪个秒杀阶段
// TODO puhui999这里 58 行是雷同的
List<SeckillConfigDO> configList = configService.getSeckillConfigList();
SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
// 11 时段不存在直接返回 null
if (filteredConfig == null) {
if (filteredConfig == null) { // 时段不存在直接返回 null
return success(null);
}
// 2获取活动
// 2. 获取活动
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
if (seckillActivity == null) {
return success(null);
@ -103,7 +105,7 @@ public class AppSeckillActivityController {
throw exception(SECKILL_ACTIVITY_APP_STATUS_CLOSED);
}
// 3获取活动商品
// 3. 拼接数据
List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
}

View File

@ -32,19 +32,12 @@ public class AppSeckillConfigController {
@Operation(summary = "获得秒杀时间段列表")
public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
// TODO @puhui999如果这种不用判空也问题不大
if (CollectionUtil.isEmpty(list)) {
return success(Collections.emptyList());
}
return success(SeckillConfigConvert.INSTANCE.convertList2(list));
//return success(Arrays.asList(
// new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")
// .setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",
// "https://static.iocoder.cn/mall/132.jpeg")),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")
//));
}
}

View File

@ -42,9 +42,11 @@ public interface BargainActivityConvert {
default PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
PageResult<BargainActivityRespVO> result = convertPage(page);
// 拼接关联属性
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<BargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
// TODO @puhui999这里可以使用链式哈
item.setPicUrl(spu.getPicUrl());
item.setSpuName(spu.getName());
});
@ -56,7 +58,7 @@ public interface BargainActivityConvert {
AppBargainActivityDetailRespVO convert1(BargainActivityDO bean);
default AppBargainActivityDetailRespVO convert1(BargainActivityDO bean, ProductSpuRespDTO spu) {
default AppBargainActivityDetailRespVO convert(BargainActivityDO bean, ProductSpuRespDTO spu) {
AppBargainActivityDetailRespVO detail = convert1(bean);
if (spu != null) {
detail.setPicUrl(spu.getPicUrl());
@ -70,9 +72,11 @@ public interface BargainActivityConvert {
default PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
PageResult<AppBargainActivityRespVO> result = convertAppPage(page);
// 拼接关联属性
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<AppBargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
// TODO @puhui999这里可以使用链式哈
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
});
@ -89,6 +93,7 @@ public interface BargainActivityConvert {
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
return CollectionUtils.convertList(activityList, item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
// TODO @puhui999这里可以使用链式哈
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
});

View File

@ -97,8 +97,10 @@ public interface CombinationActivityConvert {
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
default CombinationRecordDO convert1(CombinationRecordCreateReqDTO reqDTO, CombinationActivityDO activity, MemberUserRespDTO user,
ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
CombinationActivityDO activity, MemberUserRespDTO user,
ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
// TODO @puhui999搞成链式的 set这样会更规整一点
CombinationRecordDO record = convert(reqDTO);
record.setVirtualGroup(false);
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));

View File

@ -98,6 +98,7 @@ public interface SeckillActivityConvert {
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
// TODO @puhui999可以尝试链式 set
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
@ -114,6 +115,7 @@ public interface SeckillActivityConvert {
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
// TODO @puhui999可以尝试链式 set
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
@ -131,6 +133,7 @@ public interface SeckillActivityConvert {
default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
AppSeckillActivityDetailRespVO respVO = convert2(seckillActivity);
respVO.setProducts(convertList1(products));
// TODO @puhui999可以尝试链式 set
respVO.setStartTime(buildTime(filteredConfig.getStartTime()));
respVO.setEndTime(buildTime(filteredConfig.getEndTime()));
return respVO;

View File

@ -41,7 +41,7 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
.eq(BargainActivityDO::getId, id)
.gt(BargainActivityDO::getStock, count)
.ge(BargainActivityDO::getStock, count)
.setSql("stock = stock - " + count));
}

View File

@ -52,6 +52,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
.eqIfPresent(SeckillActivityDO::getStatus, status)
// TODO 芋艿 find in set 的想法
.apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
}

View File

@ -63,20 +63,22 @@ public interface BargainActivityService {
*/
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
// TODO @puhui999这里可以改成进行中的活动尽量避免专门为 app 定制或者类似的名字哈mapper 那也是
/**
* 获取 APP 端活动分页数据
*
* @param pageReqVO 分页请求
* @return 砍价活动分页
*/
PageResult<BargainActivityDO> getBargainActivityAppPage(PageParam pageReqVO);
PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO);
/**
* 获取 APP 端活动展示数据
*
* @param count 需要的数量
* @return 活动列表
* @return 砍价活动分页
*/
List<BargainActivityDO> getBargainActivityAppList(Integer count);
List<BargainActivityDO> getBargainActivityListForApp(Integer count);
}

View File

@ -142,18 +142,20 @@ public class BargainActivityServiceImpl implements BargainActivityService {
}
@Override
public PageResult<BargainActivityDO> getBargainActivityAppPage(PageParam pageReqVO) {
public PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO) {
// 只查询进行中且在时间范围内的
return bargainActivityMapper.selectAppPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
}
@Override
public List<BargainActivityDO> getBargainActivityAppList(Integer count) {
public List<BargainActivityDO> getBargainActivityListForApp(Integer count) {
// TODO @puhui999这种 default count 的逻辑可以放到 controller 然后可以使用 ObjectUtils.default 方法
if (count == null) {
count = 6;
}
PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
// TODO @puhui999这种不要用 page会浪费一次 count
PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count),
CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
return result.getList();
}

View File

@ -75,6 +75,7 @@ public interface CombinationActivityService {
/**
* 校验是否满足拼团条件
* 如果不满足会抛出异常
*
* @param activityId 活动编号
* @param userId 用户编号

View File

@ -224,6 +224,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
}
// 1.3 校验是否超出单次限购数量
// TODO puhui999count > activity.getSingleLimitCount() 会更好理解点
if (activity.getSingleLimitCount() < count) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
}
@ -243,7 +244,6 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
if (activity.getTotalLimitCount() < countSum) {
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
}
}
@Override

View File

@ -132,7 +132,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
recordMapper.insert(CombinationActivityConvert.INSTANCE.convert1(reqDTO, activity, user, spu, sku));
recordMapper.insert(CombinationActivityConvert.INSTANCE.convert(reqDTO, activity, user, spu, sku));
}
@Override

View File

@ -1,52 +0,0 @@
package cn.iocoder.yudao.module.trade.api.brokerage;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
// TODO @疯狂是不是不需要这个啦
/**
* 分销 API 接口
*
* @author owen
*/
public interface BrokerageApi {
/**
* 获得分销用户
*
* @param userId 用户编号
* @return 分销用户信息
*/
BrokerageUserDTO getBrokerageUser(Long userId);
/**
* 会员绑定推广员
*
* @param userId 用户编号
* @param bindUserId 推广员编号
* @param registerTime 用户注册时间
* @return 是否绑定
*/
default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
// 注册时间在30秒内的都算新用户
// TODO @疯狂这个要不抽到 service 里哈
boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
return bindUser(userId, bindUserId, isNewUser);
}
/**
* 绑定推广员
*
* @param userId 用户编号
* @param bindUserId 推广员编号
* @param isNewUser 是否为新用户
* @return 是否绑定
*/
boolean bindUser(@NotNull(message = "用户编号不能为空") Long userId,
@NotNull(message = "推广员编号不能为空") Long bindUserId,
@NotNull Boolean isNewUser);
}

View File

@ -1,51 +0,0 @@
package cn.iocoder.yudao.module.trade.api.brokerage.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 分销用户 DTO
*
* @author owen
*/
@Data
public class BrokerageUserDTO {
/**
* 用户编号
* <p>
* 对应 MemberUserDO id 字段
*/
private Long id;
/**
* 推广员编号
* <p>
* 关联 MemberUserDO id 字段
*/
private Long bindUserId;
/**
* 推广员绑定时间
*/
private LocalDateTime bindUserTime;
/**
* 推广资格
*/
private Boolean brokerageEnabled;
/**
* 成为分销员时间
*/
private LocalDateTime brokerageTime;
/**
* 可用佣金
*/
private Integer price;
/**
* 冻结佣金
*/
private Integer frozenPrice;
}

View File

@ -88,4 +88,9 @@ public interface ErrorCodeConstants {
ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人");
ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级");
// ========== 分销提现 模块 1011008000 ==========
ErrorCode BROKERAGE_WITHDRAW_NOT_EXISTS = new ErrorCode(1011008000, "佣金提现记录不存在");
ErrorCode BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING = new ErrorCode(1011008001, "佣金提现记录状态不是审核中");
}

View File

@ -10,4 +10,7 @@ public interface MessageTemplateConstants {
String ORDER_DELIVERY = "order_delivery"; // 短信模版编号
String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现审核通过
String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现审核不通过
}

View File

@ -1,40 +0,0 @@
package cn.iocoder.yudao.module.trade.enums.brokerage;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
// TODO @疯狂是不是搞成层级类似 level 这样因为本质上它是 1 2 3 级这样的关系哈
/**
* 分销用户类型枚举
*
* @author owen
*/
@AllArgsConstructor
@Getter
public enum BrokerageUserTypeEnum implements IntArrayValuable {
ALL(0, "全部"),
FIRST(1, "一级推广人"),
SECOND(2, "二级推广人"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageUserTypeEnum::getType).toArray();
/**
* 类型
*/
private final Integer type;
/**
* 名字
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.trade.api.brokerage;
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 分销 API 接口实现类
*
* @author owen
*/
@Service
@Validated
public class BrokerageApiImpl implements BrokerageApi {
@Resource
private BrokerageUserService brokerageUserService;
@Override
public BrokerageUserDTO getBrokerageUser(Long userId) {
return BrokerageUserConvert.INSTANCE.convertDTO(brokerageUserService.getBrokerageUser(userId));
}
@Override
public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
return brokerageUserService.bindBrokerageUser(userId, bindUserId, isNewUser);
}
}

View File

@ -57,8 +57,8 @@ public class BrokerageRecordBaseVO {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime unfreezeTime;
@Schema(description = "来源用户类型")
private Integer sourceUserType;
@Schema(description = "来源用户等级")
private Integer sourceUserLevel;
@Schema(description = "来源用户编号")
private Long sourceUserId;

View File

@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -32,8 +30,7 @@ public class BrokerageRecordPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "用户类型")
@InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer sourceUserType;
@Schema(description = "用户类型", example = "1")
private Integer sourceUserLevel;
}

View File

@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@ -96,7 +95,7 @@ public class BrokerageUserController {
// 合计推广用户数量
Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
userId -> userId,
userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, BrokerageUserTypeEnum.ALL));
userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null));
// todo 合计提现

View File

@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -22,18 +20,18 @@ public class BrokerageUserPageReqVO extends PageParam {
@Schema(description = "推广员编号", example = "4587")
private Long bindUserId;
@Schema(description = "推广资格")
@Schema(description = "推广资格", example = "true")
private Boolean brokerageEnabled;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "用户类型")
@InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer userType;
@Schema(description = "用户等级", example = "1") // 注意这了不是用户的会员等级而是过滤推广的层级
private Integer level;
@Schema(description = "绑定时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] bindUserTime;
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRejectReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.withdraw.BrokerageWithdrawConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.withdraw.BrokerageWithdrawService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 佣金提现")
@RestController
@RequestMapping("/trade/brokerage-withdraw")
@Validated
public class BrokerageWithdrawController {
@Resource
private BrokerageWithdrawService brokerageWithdrawService;
@Resource
private MemberUserApi memberUserApi;
@PutMapping("/approve")
@Operation(summary = "通过申请")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) {
brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "");
return success(true);
}
@PutMapping("/reject")
@Operation(summary = "驳回申请")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
public CommonResult<Boolean> rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawRejectReqVO reqVO) {
brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason());
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得佣金提现")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) {
BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
}
@GetMapping("/page")
@Operation(summary = "获得佣金提现分页")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
public CommonResult<PageResult<BrokerageWithdrawRespVO>> getBrokerageWithdrawPage(@Valid BrokerageWithdrawPageReqVO pageVO) {
// 分页查询
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(pageVO);
// 拼接信息
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(
convertSet(pageResult.getList(), BrokerageWithdrawDO::getUserId));
return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap));
}
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 佣金提现 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class BrokerageWithdrawBaseVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11436")
@NotNull(message = "用户编号不能为空")
private Long userId;
@Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18781")
@NotNull(message = "提现金额不能为空")
private Integer price;
@Schema(description = "提现手续费", requiredMode = Schema.RequiredMode.REQUIRED, example = "11417")
@NotNull(message = "提现手续费不能为空")
private Integer feePrice;
@Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "18576")
@NotNull(message = "当前总佣金不能为空")
private Integer totalPrice;
@Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "提现类型不能为空")
private Integer type;
@Schema(description = "真实姓名", example = "赵六")
private String name;
@Schema(description = "账号", example = "88677912132")
private String accountNo;
@Schema(description = "银行名称", example = "1")
private String bankName;
@Schema(description = "开户地址", example = "海淀支行")
private String bankAddress;
@Schema(description = "收款码", example = "https://www.iocoder.cn")
private String accountQrCodeUrl;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
@Schema(description = "审核驳回原因", example = "不对")
private String auditReason;
@Schema(description = "审核时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime auditTime;
@Schema(description = "备注", example = "随便")
private String remark;
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 佣金提现分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BrokerageWithdrawPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "11436")
private Long userId;
@Schema(description = "提现类型", example = "1")
@InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现类型必须是 {value}")
private Integer type;
@Schema(description = "真实姓名", example = "赵六")
private String name;
@Schema(description = "账号", example = "886779132")
private String accountNo;
@Schema(description = "银行名称", example = "1")
private String bankName;
@Schema(description = "状态", example = "1")
@InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 驳回申请 Request VO")
@Data
@ToString(callSuper = true)
public class BrokerageWithdrawRejectReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
@NotNull(message = "编号不能为空")
private Integer id;
@Schema(description = "审核驳回原因", example = "不对")
@NotEmpty(message = "审核驳回原因不能为空")
private String auditReason;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 佣金提现 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
private Integer id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
private String userNickname;
}

View File

@ -35,7 +35,7 @@ public interface BrokerageRecordConvert {
default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
String title, Long sourceUserId, Integer sourceUserType) {
String title, Long sourceUserId, Integer sourceUserLevel) {
brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
// 不冻结时佣金直接就是结算状态
Integer status = brokerageFrozenDays > 0
@ -47,7 +47,7 @@ public interface BrokerageRecordConvert {
.setTitle(title)
.setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
.setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime)
.setSourceUserType(sourceUserType).setSourceUserId(sourceUserId);
.setSourceUserLevel(sourceUserLevel).setSourceUserId(sourceUserId);
}
default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.user;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
@ -56,6 +55,4 @@ public interface BrokerageUserConvert {
user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
return target;
}
BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser);
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.trade.convert.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRejectReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 佣金提现 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BrokerageWithdrawConvert {
BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class);
BrokerageWithdrawDO convert(BrokerageWithdrawRejectReqVO bean);
BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean);
List<BrokerageWithdrawRespVO> convertList(List<BrokerageWithdrawDO> list);
PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> page);
default PageResult<BrokerageWithdrawRespVO> convertPage(PageResult<BrokerageWithdrawDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
PageResult<BrokerageWithdrawRespVO> result = convertPage(pageResult);
for (BrokerageWithdrawRespVO vo : result.getList()) {
vo.setUserNickname(Optional.ofNullable(userMap.get(vo.getUserId())).map(MemberUserRespDTO::getNickname).orElse(null));
}
return result;
}
}

View File

@ -27,7 +27,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@ -274,10 +273,10 @@ public interface TradeOrderConvert {
TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
default BrokerageAddReqBO convert(MemberUserRespDTO user, TradeOrderItemDO item, ProductSkuRespDTO sku) {
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
.setBasePrice(item.getPayPrice() * item.getCount())
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂标题类似木晴冰雪成功购买云时代的JVM原理与实战茫农成功购买深入拆解消息队列47讲
.setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName()))
.setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice());
}
@ -292,6 +291,7 @@ public interface TradeOrderConvert {
@Mapping(target = "userId", source = "userId"),
@Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
})
TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO,
TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
}

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -83,11 +82,11 @@ public class BrokerageRecordDO extends BaseDO {
private LocalDateTime unfreezeTime;
/**
* 来源用户类型
* 来源用户等级
* <p>
* 枚举 {@link BrokerageUserTypeEnum}被推广用户和 {@link #userId} 的推广层级关系
* 被推广用户和 {@link #userId} 的推广层级关系
*/
private Integer sourceUserType;
private Integer sourceUserLevel;
/**
* 来源用户编号
* <p>

View File

@ -60,4 +60,12 @@ public class BrokerageUserDO extends BaseDO {
*/
private Integer frozenPrice;
/**
* 等级
*/
private Integer level;
/**
* 路径
*/
private String path;
}

View File

@ -0,0 +1,98 @@
package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 佣金提现 DO
*
* @author 芋道源码
*/
@TableName("trade_brokerage_withdraw")
@KeySequence("trade_brokerage_withdraw_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BrokerageWithdrawDO extends BaseDO {
/**
* 编号
*/
@TableId
private Integer id;
/**
* 用户编号
*
* 关联 MemberUserDO id 字段
*/
private Long userId;
/**
* 提现金额单位
*/
private Integer price;
/**
* 提现手续费单位
*/
private Integer feePrice;
/**
* 当前总佣金单位
*/
private Integer totalPrice;
/**
* 提现类型
* <p>
* 枚举 {@link BrokerageWithdrawTypeEnum}
*/
private Integer type;
/**
* 真实姓名
*/
private String name;
/**
* 账号
*/
private String accountNo;
/**
* 银行名称
*/
private String bankName;
/**
* 开户地址
*/
private String bankAddress;
/**
* 收款码
*/
private String accountQrCodeUrl;
/**
* 状态
* <p>
* 枚举 {@link BrokerageWithdrawStatusEnum}
*/
private Integer status;
/**
* 审核驳回原因
*/
private String auditReason;
/**
* 审核时间
*/
private LocalDateTime auditTime;
/**
* 备注
*/
private String remark;
}

View File

@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
@ -24,14 +23,12 @@ import java.util.List;
public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
!BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
// 分页查询
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
.eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
.eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType())
.eqIfPresent(BrokerageRecordDO::getSourceUserLevel, reqVO.getSourceUserLevel())
.betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BrokerageRecordDO::getId));
}
@ -59,4 +56,5 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
@Param("bizType") Integer bizType,
@Param("status") Integer status);
}

View File

@ -1,17 +1,15 @@
package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 分销用户 Mapper
@ -21,35 +19,16 @@ import org.apache.ibatis.annotations.Select;
@Mapper
public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) {
default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Integer> levels) {
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
.eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
.betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
.betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
.and(reqVO.getBindUserId() != null, w -> buildBindUserCondition(reqVO, w))
.findInSetIfPresent(BrokerageUserDO::getPath, reqVO.getBindUserId())
.inIfPresent(BrokerageUserDO::getLevel, levels)
.orderByDesc(BrokerageUserDO::getId));
}
static void buildBindUserCondition(BrokerageUserPageReqVO reqVO, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
if (BrokerageUserTypeEnum.FIRST.getType().equals(reqVO.getUserType())) {
buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
} else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);
} else {
// TODO @疯狂要不要把这个逻辑挪到 Service 算出子用户有哪些然后 IN
buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); // 通过 or 实现多个条件
}
}
static void buildFirstBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
}
static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
wrapper.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId));
}
/**
* 更新用户可用佣金增加
*
@ -128,7 +107,8 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
default void updateBindUserIdAndBindUserTimeToNull(Long id) {
update(null, new LambdaUpdateWrapper<BrokerageUserDO>()
.eq(BrokerageUserDO::getId, id)
.set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null));
.set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null)
.set(BrokerageUserDO::getLevel, 1).set(BrokerageUserDO::getPath, ""));
}
default void updateEnabledFalseAndBrokerageTimeToNull(Long id) {
@ -137,11 +117,10 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
.set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
}
default Long selectCountByBindUserId(Long bindUserId) {
return selectCount(BrokerageUserDO::getBindUserId, bindUserId);
default Long selectCountByBindUserIdAndLevelIn(Long bindUserId, List<Integer> levels) {
return selectCount(new LambdaQueryWrapperX<BrokerageUserDO>()
.findInSetIfPresent(BrokerageUserDO::getPath, bindUserId)
.inIfPresent(BrokerageUserDO::getLevel, levels));
}
@Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})")
Long selectCountByBindUserIdInBindUserId(Long bindUserId);
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 佣金提现 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO> {
default PageResult<BrokerageWithdrawDO> selectPage(BrokerageWithdrawPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageWithdrawDO>()
.eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType())
.likeIfPresent(BrokerageWithdrawDO::getName, reqVO.getName())
.eqIfPresent(BrokerageWithdrawDO::getAccountNo, reqVO.getAccountNo())
.likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName())
.eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus())
.betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime())
.orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId));
}
default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) {
return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>()
.eq(BrokerageWithdrawDO::getId, id)
.eq(BrokerageWithdrawDO::getStatus, status));
}
}

View File

@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@ -29,6 +28,7 @@ import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 佣金记录 Service 实现类
@ -74,7 +74,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
}
// 1.2 计算一级分佣
addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(),
bizType, BrokerageUserTypeEnum.FIRST);
bizType, 1);
// 2.1 获得二级推广员
if (firstUser.getBindUserId() == null) {
@ -86,7 +86,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
}
// 2.2 计算二级分佣
addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(),
bizType, BrokerageUserTypeEnum.SECOND);
bizType, 2);
}
@Override
@ -142,10 +142,10 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
* @param brokerageFrozenDays 冻结天数
* @param brokeragePercent 佣金比例
* @param bizType 业务类型
* @param sourceUserType 来源用户类型
* @param sourceUserLevel 来源用户等级
*/
private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) {
Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, Integer sourceUserLevel) {
// 1.1 处理冻结时间
LocalDateTime unfreezeTime = null;
if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
@ -157,12 +157,12 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
for (BrokerageAddReqBO item : list) {
// 计算金额
Integer fixedPrice;
if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) {
if (Objects.equals(sourceUserLevel, 1)) {
fixedPrice = item.getFirstFixedPrice();
} else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) {
} else if (Objects.equals(sourceUserLevel, 2)) {
fixedPrice = item.getSecondFixedPrice();
} else {
throw new IllegalArgumentException(StrUtil.format("来源用户({}) 不合法", sourceUserType));
throw new IllegalArgumentException(StrUtil.format("用户等级({}) 不合法", sourceUserLevel));
}
int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
if (brokeragePrice <= 0) {
@ -172,7 +172,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
// 创建记录实体
records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(),
item.getSourceUserId(), sourceUserType.getType()));
item.getSourceUserId(), sourceUserLevel));
}
if (CollUtil.isEmpty(records)) {
return;

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.trade.service.brokerage.user;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@ -91,10 +93,24 @@ public interface BrokerageUserService {
* 获得推广用户数量
*
* @param bindUserId 绑定的推广员编号
* @param userType 用户类型
* @param level 推广用户等级
* @return 推广用户数量
*/
Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType);
Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level);
/**
* 会员绑定推广员
*
* @param userId 用户编号
* @param bindUserId 推广员编号
* @param registerTime 用户注册时间
* @return 是否绑定
*/
default boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
// 注册时间在30秒内的都算新用户
boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
return bindBrokerageUser(userId, bindUserId, isNewUser);
}
/**
* 会员绑定推广员

View File

@ -1,7 +1,10 @@
package cn.iocoder.yudao.module.trade.service.brokerage.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
@ -9,17 +12,13 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -51,7 +50,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
@Override
public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
return brokerageUserMapper.selectPage(pageReqVO);
List<Integer> levels = buildUserQueryLevels(pageReqVO.getBindUserId(), pageReqVO.getLevel());
return brokerageUserMapper.selectPage(pageReqVO, levels);
}
@Override
@ -66,10 +66,15 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return;
}
// 绑定关系未发生变化
// TODO @疯狂这个放到情况一之前貌似也没关系
if (Objects.equals(brokerageUser.getBindUserId(), bindUserId)) {
return;
}
// 情况二修改推广员
validateCanBindUser(brokerageUser, bindUserId);
brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(id)));
}
@Override
@ -132,19 +137,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
}
@Override
public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
switch (userType) {
case ALL: // TODO @疯狂ALL 是不是不用搞个枚举默认为空就是不过滤哈~
Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);
Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
return firstCount + secondCount;
case FIRST:
return brokerageUserMapper.selectCountByBindUserId(bindUserId);
case SECOND:
return brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
default:
return 0L;
public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) {
List<Integer> levels = buildUserQueryLevels(bindUserId, level);
if (CollUtil.isEmpty(levels)) {
return 0L;
}
return brokerageUserMapper.selectCountByBindUserIdAndLevelIn(bindUserId, levels);
}
@Override
@ -171,14 +169,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now());
}
brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
brokerageUserMapper.insert(brokerageUser);
brokerageUserMapper.insert(fillBindUserData(bindUserId, brokerageUser));
} else {
brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(userId)));
}
return true;
}
private BrokerageUserDO fillBindUserData(Long bindUserId, BrokerageUserDO brokerageUser) {
BrokerageUserDO bindUser = getBrokerageUser(bindUserId);
Integer bindUserLevel = 0;
String bindUserPath = "";
if (bindUser != null) {
bindUserLevel = ObjectUtil.defaultIfNull(bindUser.getLevel(), 0);
bindUserPath = bindUser.getPath();
}
String path = StrUtil.isEmpty(bindUserPath)
? String.valueOf(bindUserId)
: String.format("%s,%s", bindUserPath, bindUserId);
return brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())
.setLevel(bindUserLevel + 1).setPath(path);
}
@Override
public Boolean getUserBrokerageEnabled(Long userId) {
// 全局分销功能是否开启
@ -231,11 +245,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
throw exception(BROKERAGE_BIND_SELF);
}
// TODO @疯狂这块是不是一直查询到根节点中间不允许出现自己就是不能形成环虽然目前是 2 但是未来可能会改多级 = = 环的话就会存在问题哈
// A->B->A下级不能绑定自己的上级, A->B->C->A可以!!
if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
// 下级不能绑定自己的上级
if (StrUtil.split(bindUser.getPath(), ",").contains(String.valueOf(user.getId()))) {
throw exception(BROKERAGE_BIND_LOOP);
}
}
// TODO @芋艿这个层级要微信讨论下
private List<Integer> buildUserQueryLevels(Long bindUserId, Integer level) {
List<Integer> levels = new ArrayList<>(2);
BrokerageUserDO bindUser = getBrokerageUser(bindUserId);
if (bindUser == null) {
return levels;
}
if (level == null) {
// 默认查两层
levels.add(bindUser.getLevel() + 1);
levels.add(bindUser.getLevel() + 2);
} else {
levels.add(bindUser.getLevel() + level);
}
return levels;
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
/**
* 佣金提现 Service 接口
*
* @author 芋道源码
*/
public interface BrokerageWithdrawService {
/**
* 审核佣金提现
*
* @param id 佣金编号
* @param status 审核状态
* @param auditReason 驳回原因
*/
void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason);
/**
* 获得佣金提现
*
* @param id 编号
* @return 佣金提现
*/
BrokerageWithdrawDO getBrokerageWithdraw(Integer id);
/**
* 获得佣金提现分页
*
* @param pageReqVO 分页查询
* @return 佣金提现分页
*/
PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO);
}

View File

@ -0,0 +1,104 @@
package cn.iocoder.yudao.module.trade.service.brokerage.withdraw;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw.BrokerageWithdrawMapper;
import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_NOT_EXISTS;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING;
/**
* 佣金提现 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
@Resource
private BrokerageWithdrawMapper brokerageWithdrawMapper;
@Resource
private BrokerageRecordService brokerageRecordService;
@Resource
private NotifyMessageSendApi notifyMessageSendApi;
@Override
@Transactional(rollbackFor = Exception.class)
public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason) {
// 1.1 校验存在
BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
// 1.2 校验状态为审核中
if (ObjectUtil.notEqual(BrokerageWithdrawStatusEnum.AUDITING.getStatus(), withdraw.getStatus())) {
throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
}
// 2. 更新
BrokerageWithdrawDO updateObj = new BrokerageWithdrawDO()
.setStatus(status.getStatus())
.setAuditReason(auditReason)
.setAuditTime(LocalDateTime.now());
int rows = brokerageWithdrawMapper.updateByIdAndStatus(id, BrokerageWithdrawStatusEnum.AUDITING.getStatus(), updateObj);
if (rows == 0) {
throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
}
// 3. 驳回时需要退还用户佣金
String templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE;
if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT;
// todo @owen
// brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW, withdraw.getPrice(), "");
}
// 4. 通知用户
Map<String, Object> templateParams = MapUtil.<String, Object>builder()
.put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime()))
.put("price", String.format("%.2f", withdraw.getPrice() / 100d))
.put("reason", withdraw.getAuditReason())
.build();
NotifySendSingleToUserReqDTO reqDTO = new NotifySendSingleToUserReqDTO()
.setUserId(withdraw.getUserId())
.setTemplateCode(templateCode).setTemplateParams(templateParams);
notifyMessageSendApi.sendSingleMessageToMember(reqDTO);
}
private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) {
BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id);
if (withdraw == null) {
throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS);
}
return withdraw;
}
@Override
public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) {
return brokerageWithdrawMapper.selectById(id);
}
@Override
public PageResult<BrokerageWithdrawDO> getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO) {
return brokerageWithdrawMapper.selectPage(pageReqVO);
}
}

View File

@ -12,6 +12,8 @@ import cn.iocoder.yudao.module.member.api.address.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@ -115,6 +117,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource
private BargainRecordApi bargainRecordApi;
@Resource
private MemberUserApi memberUserApi;
@Resource
private MemberLevelApi memberLevelApi;
@Resource
private MemberPointApi memberPointApi;
@ -782,9 +786,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Async
protected void addBrokerageAsync(Long userId, Long orderId) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
Assert.notNull(user);
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
List<BrokerageAddReqBO> list = convertList(orderItems,
item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId())));
item -> TradeOrderConvert.INSTANCE.convert(user, item, productSkuApi.getSku(item.getSkuId())));
brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list);
}

View File

@ -14,6 +14,8 @@ import javax.validation.constraints.NotNull;
@Data
public class TradeBeforeOrderCreateReqBO {
// TODO @puhui999注释也写下哈bo 还是写注释噢
@NotNull(message = "订单类型不能为空")
private Integer orderType;

View File

@ -0,0 +1,88 @@
package cn.iocoder.yudao.module.trade.service.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.withdraw.vo.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.withdraw.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.withdraw.BrokerageWithdrawMapper;
import cn.iocoder.yudao.module.trade.service.brokerage.withdraw.BrokerageWithdrawServiceImpl;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO 芋艿后续 review
/**
* {@link BrokerageWithdrawServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(BrokerageWithdrawServiceImpl.class)
public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest {
@Resource
private BrokerageWithdrawServiceImpl brokerageWithdrawService;
@Resource
private BrokerageWithdrawMapper brokerageWithdrawMapper;
@Test
@Disabled // TODO 请修改 null 为需要的值然后删除 @Disabled 注解
public void testGetBrokerageWithdrawPage() {
// mock 数据
BrokerageWithdrawDO dbBrokerageWithdraw = randomPojo(BrokerageWithdrawDO.class, o -> { // 等会查询到
o.setUserId(null);
o.setType(null);
o.setName(null);
o.setAccountNo(null);
o.setBankName(null);
o.setStatus(null);
o.setCreateTime(null);
});
brokerageWithdrawMapper.insert(dbBrokerageWithdraw);
// 测试 userId 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setUserId(null)));
// 测试 type 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setType(null)));
// 测试 name 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setName(null)));
// 测试 accountNo 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAccountNo(null)));
// 测试 bankName 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setBankName(null)));
// 测试 status 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setStatus(null)));
// 测试 auditReason 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditReason(null)));
// 测试 auditTime 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditTime(null)));
// 测试 remark 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setRemark(null)));
// 测试 createTime 不匹配
brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setCreateTime(null)));
// 准备参数
BrokerageWithdrawPageReqVO reqVO = new BrokerageWithdrawPageReqVO();
reqVO.setUserId(null);
reqVO.setType(null);
reqVO.setName(null);
reqVO.setAccountNo(null);
reqVO.setBankName(null);
reqVO.setStatus(null);
reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
// 调用
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbBrokerageWithdraw, pageResult.getList().get(0));
}
}

View File

@ -4,3 +4,4 @@ DELETE FROM trade_after_sale;
DELETE FROM trade_after_sale_log;
DELETE FROM trade_brokerage_user;
DELETE FROM trade_brokerage_record;
DELETE FROM "trade_brokerage_withdraw";

View File

@ -163,4 +163,29 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_record"
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '佣金记录';
) COMMENT '佣金记录';
CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw"
(
"id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"price" int NOT NULL,
"fee_price" int NOT NULL,
"total_price" int NOT NULL,
"type" varchar NOT NULL,
"name" varchar,
"account_no" varchar,
"bank_name" varchar,
"bank_address" varchar,
"account_qr_code_url" varchar,
"status" varchar NOT NULL,
"audit_reason" varchar,
"audit_time" varchar,
"remark" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '佣金提现';

View File

@ -44,31 +44,31 @@ spring:
primary: master
datasource:
master:
name: mall
url: jdbc:mysql://10.211.55.5:3308/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.master.name} # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例
username: root
password: 1qaz!QAZ
password: 123456
# username: sa
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
slave: # 模拟从库,可根据自己需要修改
name: mall
url: jdbc:mysql://10.211.55.5:3308/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.slave.name} # SQLServer 连接的示例
username: root
password: 1qaz!QAZ
password: 123456
# username: sa
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.211.55.5 # 地址
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: dev # 密码,建议生产环境开启