mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-02-20 19:20:32 +08:00
Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product
This commit is contained in:
commit
c880dbfa60
@ -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);
|
||||
|
@ -43,6 +43,17 @@ public class LocalDateTimeUtils {
|
||||
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param timeStr 时间字符串
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static LocalDateTime buildTime(String timeStr) {
|
||||
// TODO @puhui999:这个方法的实现,和 LocalDateTimeUtil.parse() 的差异点是啥呀
|
||||
return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
|
||||
}
|
||||
|
||||
public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
|
||||
int year2, int mouth2, int day2) {
|
||||
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
|
||||
@ -62,6 +73,22 @@ public class LocalDateTimeUtils {
|
||||
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前时间是否在该时间范围内
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isBetween(String startTime, String endTime) {
|
||||
if (startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
LocalDate nowDate = LocalDate.now();
|
||||
return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
|
||||
LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断时间段是否重叠
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ public interface ProductSkuApi {
|
||||
List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
|
||||
|
||||
/**
|
||||
* 更新 SKU 库存
|
||||
* 更新 SKU 库存(增加 or 减少)
|
||||
*
|
||||
* @param updateStockReqDTO 更新请求
|
||||
*/
|
||||
|
@ -59,14 +59,13 @@ public class ProductSkuRespDTO {
|
||||
* 商品体积,单位:m^3 平米
|
||||
*/
|
||||
private Double volume;
|
||||
// TODO @puhui999:firstBrokeragePrice ;尴尬,我当时打错了;secondBrokeragePrice
|
||||
/**
|
||||
* 一级分销的佣金,单位:分
|
||||
*/
|
||||
private Integer firstBrokerageRecord;
|
||||
private Integer firstBrokeragePrice;
|
||||
/**
|
||||
* 二级分销的佣金,单位:分
|
||||
*/
|
||||
private Integer secondBrokerageRecord;
|
||||
private Integer secondBrokeragePrice;
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.product.api.spu.dto;
|
||||
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
|
||||
import lombok.Data;
|
||||
|
||||
@ -31,6 +30,12 @@ public class ProductSpuRespDTO {
|
||||
* 关键字
|
||||
*/
|
||||
private String keyword;
|
||||
/**
|
||||
* 单位
|
||||
*
|
||||
* 对应 product_unit 数据字典
|
||||
*/
|
||||
private Integer unit;
|
||||
/**
|
||||
* 商品简介
|
||||
*/
|
||||
|
@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
|
||||
private Double volume;
|
||||
|
||||
@Schema(description = "一级分销的佣金,单位:分", example = "199")
|
||||
private Integer firstBrokerageRecord;
|
||||
private Integer firstBrokeragePrice;
|
||||
|
||||
@Schema(description = "二级分销的佣金,单位:分", example = "19")
|
||||
private Integer secondBrokerageRecord;
|
||||
private Integer secondBrokeragePrice;
|
||||
|
||||
@Schema(description = "属性数组")
|
||||
private List<Property> properties;
|
||||
|
@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
|
||||
/**
|
||||
* 一级分销的佣金,单位:分
|
||||
*/
|
||||
private Integer firstBrokerageRecord;
|
||||
private Integer firstBrokeragePrice;
|
||||
/**
|
||||
* 二级分销的佣金,单位:分
|
||||
*/
|
||||
private Integer secondBrokerageRecord;
|
||||
private Integer secondBrokeragePrice;
|
||||
|
||||
// ========== 营销相关字段 =========
|
||||
|
||||
|
@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
||||
o.setMarketPrice(generaInt());
|
||||
o.setStock(generaInt());
|
||||
o.setWarnStock(10);
|
||||
o.setFirstBrokerageRecord(generaInt());
|
||||
o.setSecondBrokerageRecord(generaInt());
|
||||
o.setFirstBrokeragePrice(generaInt());
|
||||
o.setSecondBrokeragePrice(generaInt());
|
||||
// 限制分数为两位数
|
||||
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||
@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
||||
o.setMarketPrice(generaInt());
|
||||
o.setStock(generaInt());
|
||||
o.setWarnStock(10);
|
||||
o.setFirstBrokerageRecord(generaInt());
|
||||
o.setSecondBrokerageRecord(generaInt());
|
||||
o.setFirstBrokeragePrice(generaInt());
|
||||
o.setSecondBrokeragePrice(generaInt());
|
||||
// 限制分数为两位数
|
||||
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||
|
@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
/**
|
||||
* 拼团活动 Api 接口
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface CombinationActivityApi {
|
||||
|
||||
/**
|
||||
* 校验是否满足拼团条件
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||
|
||||
// TODO @puhui999:是不是改成 CombinationActivityApi
|
||||
/**
|
||||
* 拼团活动 Api 接口
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface CombinationApi {
|
||||
|
||||
/**
|
||||
* 更新活动库存
|
||||
*
|
||||
* @param reqDTO 请求
|
||||
*/
|
||||
// TODO @puhui999:应该是更新哇?还是校验哈;
|
||||
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
|
||||
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
// TODO @芋艿:后面也再撸撸这几个接口
|
||||
|
||||
@ -33,26 +31,7 @@ public interface CombinationRecordApi {
|
||||
boolean isCombinationRecordSuccess(Long userId, Long orderId);
|
||||
|
||||
/**
|
||||
* 获取拼团记录
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param activityId 活动编号
|
||||
* @return 拼团记录列表
|
||||
*/
|
||||
List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
|
||||
|
||||
/**
|
||||
* 验证组合限制数
|
||||
* 校验是否满足限购要求
|
||||
*
|
||||
* @param count 本次购买数量
|
||||
* @param sumCount 已购买数量合计
|
||||
* @param activityId 活动编号
|
||||
*/
|
||||
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
|
||||
|
||||
/**
|
||||
* 更新拼团状态为成功
|
||||
* 更新拼团状态为【成功】
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param orderId 订单编号
|
||||
@ -60,7 +39,7 @@ public interface CombinationRecordApi {
|
||||
void updateRecordStatusToSuccess(Long userId, Long orderId);
|
||||
|
||||
/**
|
||||
* 更新拼团状态为失败
|
||||
* 更新拼团状态为【失败】
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param orderId 订单编号
|
||||
|
@ -1,42 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 拼团活动更新活动库存 Request DTO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class CombinationActivityUpdateStockReqDTO {
|
||||
|
||||
// TODO @puhui999:是不是一个 activityId、count、skuId 参数就完事啦。
|
||||
|
||||
@NotNull(message = "活动编号不能为空")
|
||||
private Long activityId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
@NotNull(message = "活动商品不能为空")
|
||||
private Item item;
|
||||
|
||||
@Data
|
||||
@Valid
|
||||
public static class Item {
|
||||
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -13,26 +13,39 @@ import javax.validation.constraints.NotNull;
|
||||
@Data
|
||||
public class CombinationRecordCreateReqDTO {
|
||||
|
||||
// TODO @puhui999:注释还是要的哈
|
||||
|
||||
/**
|
||||
* 拼团活动编号
|
||||
*/
|
||||
@NotNull(message = "拼团活动编号不能为空")
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* spu 编号
|
||||
*/
|
||||
@NotNull(message = "spu 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
/**
|
||||
* sku 编号
|
||||
*/
|
||||
@NotNull(message = "sku 编号不能为空")
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
@NotNull(message = "订单编号不能为空")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 团长编号
|
||||
*/
|
||||
@NotNull(message = "团长编号不能为空")
|
||||
private Long headId;
|
||||
|
||||
/**
|
||||
* 拼团商品单价
|
||||
*/
|
||||
@NotNull(message = "拼团商品单价不能为空")
|
||||
private Integer combinationPrice;
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.seckill;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||
|
||||
/**
|
||||
* 秒杀活动 API 接口
|
||||
*
|
||||
@ -9,11 +7,14 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateSt
|
||||
*/
|
||||
public interface SeckillActivityApi {
|
||||
|
||||
// TODO @puhui999:activityId 改成 id 好点哈;
|
||||
/**
|
||||
* 更新秒杀库存
|
||||
*
|
||||
* @param updateStockReqDTO 请求
|
||||
* @param activityId 活动编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
|
||||
void updateSeckillStock(Long activityId, Long skuId, Integer count);
|
||||
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.seckill.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 更新秒杀库存 request DTO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class SeckillActivityUpdateStockReqDTO {
|
||||
|
||||
// TODO @puhui999:可以不用 dto,直接 activityId、skuId、count 即可
|
||||
|
||||
@NotNull(message = "活动编号不能为空")
|
||||
private Long activityId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
@NotNull(message = "活动商品不能为空")
|
||||
private Item item;
|
||||
|
||||
@Data
|
||||
@Valid
|
||||
public static class Item {
|
||||
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -56,6 +56,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
|
||||
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
|
||||
ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
|
||||
ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
|
||||
|
||||
// ========== 秒杀时段 1013009000 ==========
|
||||
ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
|
||||
|
@ -77,6 +77,10 @@
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -1,9 +1,7 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@ -13,15 +11,14 @@ import javax.annotation.Resource;
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class CombinationApiImpl implements CombinationApi {
|
||||
public class CombinationActivityApiImpl implements CombinationActivityApi {
|
||||
|
||||
@Resource
|
||||
private CombinationActivityService activityService;
|
||||
|
||||
@Override
|
||||
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
|
||||
activityService.validateCombination(reqDTO);
|
||||
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
activityService.validateCombination(activityId, userId, skuId, count);
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,12 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 拼团活动 API 实现类
|
||||
@ -32,16 +29,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
|
||||
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {
|
||||
return CombinationActivityConvert.INSTANCE.convert(recordService.getRecordListByUserIdAndActivityId(userId, activityId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
|
||||
recordService.validateCombinationLimitCount(activityId, count, sumCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecordStatusToSuccess(Long userId, Long orderId) {
|
||||
recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.seckill;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
|
||||
private SeckillActivityService activityService;
|
||||
|
||||
@Override
|
||||
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
|
||||
activityService.updateSeckillStock(updateStockReqDTO);
|
||||
public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
|
||||
activityService.updateSeckillStock(activityId, skuId, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ 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.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;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
|
||||
@ -19,8 +21,10 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
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
|
||||
@ -30,6 +34,8 @@ public class BargainActivityController {
|
||||
|
||||
@Resource
|
||||
private BargainActivityService activityService;
|
||||
@Resource
|
||||
private ProductSpuApi spuApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建砍价活动")
|
||||
@ -73,7 +79,10 @@ public class BargainActivityController {
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
|
||||
|
||||
// 拼接数据
|
||||
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), BargainActivityDO::getSpuId));
|
||||
return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, spuList));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,18 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.bargain;
|
||||
|
||||
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.date.LocalDateTimeUtils;
|
||||
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;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
|
||||
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.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -14,97 +20,60 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
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
|
||||
@RequestMapping("/promotion/bargain-activity")
|
||||
@Validated
|
||||
public class AppBargainActivityController {
|
||||
@Resource
|
||||
private BargainActivityService bargainActivityService;
|
||||
@Resource
|
||||
private ProductSpuApi spuApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得砍价活动活动") // TODO 芋艿:只查询进行中,且在时间范围内的
|
||||
// TODO 芋艿:缺少 swagger 注解
|
||||
@Operation(summary = "获得砍价活动分页")
|
||||
public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
|
||||
List<AppBargainActivityRespVO> activityList = new ArrayList<>();
|
||||
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();
|
||||
activity1.setId(1L);
|
||||
activity1.setName("618 大砍价");
|
||||
activity1.setSpuId(2048L);
|
||||
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
|
||||
activity1.setMarketPrice(50);
|
||||
activity1.setBargainPrice(100);
|
||||
activity1.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
|
||||
activity1.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));
|
||||
activity1.setStock(10);
|
||||
activityList.add(activity1);
|
||||
|
||||
AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();
|
||||
activity2.setId(2L);
|
||||
activity2.setName("双十一砍价");
|
||||
activity2.setSpuId(4096L);
|
||||
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
|
||||
activity2.setMarketPrice(100);
|
||||
activity2.setBargainPrice(200);
|
||||
activity2.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
|
||||
activity2.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));
|
||||
activity2.setStock(0);
|
||||
activityList.add(activity2);
|
||||
|
||||
return success(new PageResult<>(activityList, 10L));
|
||||
PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPageForApp(pageReqVO);
|
||||
if (CollUtil.isEmpty(result.getList())) {
|
||||
return success(PageResult.empty(result.getTotal()));
|
||||
}
|
||||
// 拼接数据
|
||||
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 = "用于小程序首页")
|
||||
// TODO 芋艿:增加 Spring Cache
|
||||
// TODO 芋艿:缺少 swagger 注解
|
||||
@Parameter(name = "count", description = "需要展示的数量", example = "6")
|
||||
public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
|
||||
@RequestParam(name = "count", defaultValue = "6") Integer count) {
|
||||
List<AppBargainActivityRespVO> activityList = new ArrayList<>();
|
||||
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();
|
||||
activity1.setId(1L);
|
||||
activity1.setName("618 大砍价");
|
||||
activity1.setSpuId(2048L);
|
||||
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
|
||||
activity1.setMarketPrice(50);
|
||||
activity1.setBargainPrice(100);
|
||||
activityList.add(activity1);
|
||||
|
||||
AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();
|
||||
activity2.setId(2L);
|
||||
activity2.setName("双十一砍价");
|
||||
activity2.setSpuId(4096L);
|
||||
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
|
||||
activity2.setMarketPrice(100);
|
||||
activity2.setBargainPrice(200);
|
||||
activityList.add(activity2);
|
||||
|
||||
return success(activityList);
|
||||
List<BargainActivityDO> list = bargainActivityService.getBargainActivityListForApp(count);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return success(BargainActivityConvert.INSTANCE.convertAppList(list));
|
||||
}
|
||||
// 拼接数据
|
||||
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, BargainActivityDO::getSpuId));
|
||||
return success(BargainActivityConvert.INSTANCE.convertAppList(list, spuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得砍价活动详情")
|
||||
// TODO 芋艿:缺少 swagger 注解
|
||||
@Parameter(name = "id", description = "活动编号", example = "1")
|
||||
public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) {
|
||||
AppBargainActivityDetailRespVO activity = new AppBargainActivityDetailRespVO();
|
||||
activity.setId(2L);
|
||||
activity.setName("618 大砍价");
|
||||
activity.setSpuId(2048L);
|
||||
activity.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
|
||||
activity.setMarketPrice(50);
|
||||
activity.setBargainPrice(100);
|
||||
activity.setStock(10);
|
||||
activity.setUnitName("件");
|
||||
activity.setPrice(40);
|
||||
activity.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
|
||||
activity.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(-10)));
|
||||
activity.setDescription("我吃西红柿");
|
||||
activity.setSuccessCount(10);
|
||||
return success(activity);
|
||||
BargainActivityDO activity = bargainActivityService.getBargainActivity(id);
|
||||
if (activity == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 拼接数据
|
||||
ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId());
|
||||
return success(BargainActivityConvert.INSTANCE.convert(activity, spu));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class AppBargainActivityDetailRespVO {
|
||||
@Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价
|
||||
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
|
||||
private Integer bargainPrice;
|
||||
|
||||
@Schema(description = "砍价成功数量", required = true, example = "100")
|
||||
|
@ -36,7 +36,7 @@ public class AppBargainActivityRespVO {
|
||||
@Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价
|
||||
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
|
||||
private Integer bargainPrice;
|
||||
|
||||
}
|
||||
|
@ -1,136 +1,115 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.seckill;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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.seckill.vo.activity.AppSeckillActivityDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
|
||||
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.context.annotation.Lazy;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_FAIL_STATUS_CLOSED;
|
||||
|
||||
@Tag(name = "用户 App - 秒杀活动")
|
||||
@RestController
|
||||
@RequestMapping("/promotion/seckill-activity")
|
||||
@Validated
|
||||
public class AppSeckillActivityController {
|
||||
@Resource
|
||||
private SeckillActivityService activityService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private SeckillConfigService configService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi spuApi;
|
||||
|
||||
@GetMapping("/get-now")
|
||||
@Operation(summary = "获得当前秒杀活动") // 提供给首页使用
|
||||
// TODO 芋艿:需要增加 spring cache
|
||||
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
|
||||
AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
|
||||
respVO.setConfig(new AppSeckillConfigRespVO().setId(10L).setStartTime("01:00").setEndTime("09:59"));
|
||||
List<AppSeckillActivityRespVO> activityList = new ArrayList<>();
|
||||
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();
|
||||
activity1.setId(1L);
|
||||
activity1.setName("618 大秒杀");
|
||||
activity1.setSpuId(2048L);
|
||||
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
|
||||
activity1.setMarketPrice(50);
|
||||
activity1.setSeckillPrice(100);
|
||||
activityList.add(activity1);
|
||||
// 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()));
|
||||
if (filteredConfig == null) { // 时段不存在直接返回 null
|
||||
return success(null);
|
||||
}
|
||||
|
||||
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();
|
||||
activity2.setId(2L);
|
||||
activity2.setName("双十一大秒杀");
|
||||
activity2.setSpuId(4096L);
|
||||
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
|
||||
activity2.setMarketPrice(100);
|
||||
activity2.setSeckillPrice(200);
|
||||
activityList.add(activity2);
|
||||
respVO.setActivities(activityList);
|
||||
return success(respVO);
|
||||
// 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()));
|
||||
|
||||
// 3. 拼接数据
|
||||
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(filteredList, SeckillActivityDO::getSpuId));
|
||||
return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得秒杀活动分页")
|
||||
// TODO @芋艿:分页参数
|
||||
public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
|
||||
List<AppSeckillActivityRespVO> activityList = new ArrayList<>();
|
||||
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();
|
||||
activity1.setId(1L);
|
||||
activity1.setName("618 大秒杀");
|
||||
activity1.setSpuId(2048L);
|
||||
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
|
||||
activity1.setMarketPrice(50);
|
||||
activity1.setSeckillPrice(100);
|
||||
activity1.setUnitName("个");
|
||||
activity1.setStock(1);
|
||||
activity1.setTotalStock(2);
|
||||
activityList.add(activity1);
|
||||
// 1. 查询满足当前阶段的活动
|
||||
PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
|
||||
|
||||
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();
|
||||
activity2.setId(2L);
|
||||
activity2.setName("双十一大秒杀");
|
||||
activity2.setSpuId(4096L);
|
||||
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
|
||||
activity2.setMarketPrice(100);
|
||||
activity2.setSeckillPrice(200);
|
||||
activity2.setUnitName("套");
|
||||
activity2.setStock(2);
|
||||
activity2.setTotalStock(3);
|
||||
activityList.add(activity2);
|
||||
return success(new PageResult<>(activityList, 100L));
|
||||
// 2. 拼接数据
|
||||
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
|
||||
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得秒杀活动明细")
|
||||
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
|
||||
public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
|
||||
// TODO 芋艿:如果禁用的时候,需要抛出异常;
|
||||
AppSeckillActivityDetailRespVO obj = new AppSeckillActivityDetailRespVO();
|
||||
// 设置其属性的值
|
||||
obj.setId(id);
|
||||
obj.setName("晚九点限时秒杀");
|
||||
obj.setStatus(1);
|
||||
obj.setStartTime(LocalDateTime.of(2023, 6, 16, 0, 0, 0));
|
||||
obj.setEndTime(LocalDateTime.of(2023, 6, 20, 23, 59, 0));
|
||||
obj.setSpuId(633L);
|
||||
obj.setSingleLimitCount(2);
|
||||
obj.setTotalLimitCount(3);
|
||||
obj.setStock(100);
|
||||
obj.setTotalStock(200);
|
||||
// 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()));
|
||||
if (filteredConfig == null) { // 时段不存在直接返回 null
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 创建一个Product对象的列表
|
||||
List<AppSeckillActivityDetailRespVO.Product> productList = new ArrayList<>();
|
||||
// 创建三个新的Product对象并设置其属性的值
|
||||
AppSeckillActivityDetailRespVO.Product product1 = new AppSeckillActivityDetailRespVO.Product();
|
||||
product1.setSkuId(1L);
|
||||
product1.setSeckillPrice(100);
|
||||
product1.setStock(50);
|
||||
// 将第一个Product对象添加到列表中
|
||||
productList.add(product1);
|
||||
// 创建第二个Product对象并设置其属性的值
|
||||
AppSeckillActivityDetailRespVO.Product product2 = new AppSeckillActivityDetailRespVO.Product();
|
||||
product2.setSkuId(2L);
|
||||
product2.setSeckillPrice(200);
|
||||
product2.setStock(100);
|
||||
// 将第二个Product对象添加到列表中
|
||||
productList.add(product2);
|
||||
// 创建第三个Product对象并设置其属性的值
|
||||
AppSeckillActivityDetailRespVO.Product product3 = new AppSeckillActivityDetailRespVO.Product();
|
||||
product3.setSkuId(3L);
|
||||
product3.setSeckillPrice(300);
|
||||
product3.setStock(150);
|
||||
// 将第三个Product对象添加到列表中
|
||||
productList.add(product3);
|
||||
// 将Product列表设置为对象的属性值
|
||||
obj.setProducts(productList);
|
||||
return success(obj);
|
||||
// 2. 获取活动
|
||||
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
|
||||
if (seckillActivity == null) {
|
||||
return success(null);
|
||||
}
|
||||
// TODO 芋艿:如果禁用的时候,需要抛出异常;
|
||||
if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
|
||||
}
|
||||
|
||||
// 3. 拼接数据
|
||||
List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
|
||||
return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.seckill;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@ -19,18 +25,19 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@RequestMapping("/promotion/seckill-config")
|
||||
@Validated
|
||||
public class AppSeckillConfigController {
|
||||
@Resource
|
||||
private SeckillConfigService configService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得秒杀时间段列表")
|
||||
public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
|
||||
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")
|
||||
));
|
||||
List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
// TODO @puhui999:如果这种,不用判空也问题不大;
|
||||
if (CollectionUtil.isEmpty(list)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
|
||||
return success(SeckillConfigConvert.INSTANCE.convertList2(list));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO {
|
||||
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
// TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
|
||||
// TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
|
||||
|
||||
@Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime startTime;
|
||||
|
@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO {
|
||||
private Integer totalStock;
|
||||
|
||||
@Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
// 从秒杀商品里取最低价
|
||||
private Integer seckillPrice;
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,24 @@
|
||||
package cn.iocoder.yudao.module.promotion.convert.bargain;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
|
||||
/**
|
||||
* 拼团活动 Convert
|
||||
@ -30,4 +40,65 @@ public interface BargainActivityConvert {
|
||||
|
||||
PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page);
|
||||
|
||||
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());
|
||||
});
|
||||
return item;
|
||||
});
|
||||
result.setList(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
AppBargainActivityDetailRespVO convert1(BargainActivityDO bean);
|
||||
|
||||
default AppBargainActivityDetailRespVO convert(BargainActivityDO bean, ProductSpuRespDTO spu) {
|
||||
AppBargainActivityDetailRespVO detail = convert1(bean);
|
||||
if (spu != null) {
|
||||
detail.setPicUrl(spu.getPicUrl());
|
||||
detail.setMarketPrice(spu.getMarketPrice());
|
||||
detail.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
|
||||
PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page);
|
||||
|
||||
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());
|
||||
});
|
||||
return item;
|
||||
});
|
||||
result.setList(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list);
|
||||
|
||||
default List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list, List<ProductSpuRespDTO> spuList) {
|
||||
List<AppBargainActivityRespVO> activityList = convertAppList(list);
|
||||
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());
|
||||
});
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.convert.combination;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
|
||||
@ -92,6 +94,21 @@ public interface CombinationActivityConvert {
|
||||
|
||||
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
|
||||
|
||||
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()));
|
||||
record.setUserSize(activity.getUserSize());
|
||||
record.setNickname(user.getNickname());
|
||||
record.setAvatar(user.getAvatar());
|
||||
record.setSpuName(spu.getName());
|
||||
record.setPicUrl(sku.getPicUrl());
|
||||
return record;
|
||||
}
|
||||
|
||||
List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
|
||||
|
||||
}
|
||||
|
@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
|
||||
|
||||
/**
|
||||
* 秒杀活动 Convert
|
||||
*
|
||||
@ -79,4 +90,53 @@ public interface SeckillActivityConvert {
|
||||
|
||||
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list);
|
||||
|
||||
List<AppSeckillActivityRespVO> convertList3(List<SeckillActivityDO> activityList);
|
||||
|
||||
default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList, List<ProductSpuRespDTO> spuList) {
|
||||
AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
|
||||
respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig));
|
||||
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()));
|
||||
});
|
||||
return item;
|
||||
}));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
PageResult<AppSeckillActivityRespVO> convertPage1(PageResult<SeckillActivityDO> pageResult);
|
||||
|
||||
default PageResult<AppSeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> pageResult, List<ProductSpuRespDTO> spuList) {
|
||||
PageResult<AppSeckillActivityRespVO> result = convertPage1(pageResult);
|
||||
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()));
|
||||
});
|
||||
return item;
|
||||
});
|
||||
result.setList(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
AppSeckillActivityDetailRespVO convert2(SeckillActivityDO seckillActivity);
|
||||
|
||||
List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
@ -33,4 +34,7 @@ public interface SeckillConfigConvert {
|
||||
|
||||
PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page);
|
||||
|
||||
List<AppSeckillConfigRespVO> convertList2(List<SeckillConfigDO> list);
|
||||
|
||||
AppSeckillConfigRespVO convert1(SeckillConfigDO filteredConfig);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO {
|
||||
*/
|
||||
private Integer singleLimitCount;
|
||||
/**
|
||||
* 秒杀库存
|
||||
* 秒杀库存(剩余库存秒杀时扣减)
|
||||
*/
|
||||
private Integer stock;
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
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;
|
||||
@ -8,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -39,8 +41,15 @@ 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, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
|
||||
.ge(BargainActivityDO::getStock, count)
|
||||
.setSql("stock = stock - " + count));
|
||||
}
|
||||
|
||||
default PageResult<BargainActivityDO> selectAppPage(PageParam pageReqVO, Integer status, LocalDateTime now) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<BargainActivityDO>()
|
||||
.eq(BargainActivityDO::getStatus, status)
|
||||
.le(BargainActivityDO::getStartTime, now)
|
||||
.ge(BargainActivityDO::getEndTime, now));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ 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.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
|
||||
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
|
||||
.apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0")
|
||||
.apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0")
|
||||
.orderByDesc(SeckillActivityDO::getId));
|
||||
}
|
||||
|
||||
@ -48,4 +49,11 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||
.setSql("totalStock = totalStock - " + count));
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
|
||||
default int updateActivityStock(Long id, int count) {
|
||||
return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
|
||||
.eq(SeckillProductDO::getId, id)
|
||||
.gt(SeckillProductDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
|
||||
.gt(SeckillProductDO::getStock, count)
|
||||
.setSql("stock = stock - " + count));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.bargain;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
|
||||
@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActi
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 砍价活动 Service 接口
|
||||
@ -61,4 +63,22 @@ public interface BargainActivityService {
|
||||
*/
|
||||
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
|
||||
|
||||
// TODO @puhui999:这里可以改成进行中的活动;尽量避免专门为 app 定制,或者类似的名字哈;mapper 那也是
|
||||
|
||||
/**
|
||||
* 获取 APP 端活动分页数据
|
||||
*
|
||||
* @param pageReqVO 分页请求
|
||||
* @return 砍价活动分页
|
||||
*/
|
||||
PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO);
|
||||
|
||||
/**
|
||||
* 获取 APP 端活动展示数据
|
||||
*
|
||||
* @param count 需要的数量
|
||||
* @return 砍价活动分页
|
||||
*/
|
||||
List<BargainActivityDO> getBargainActivityListForApp(Integer count);
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@ -113,9 +115,9 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
||||
// 校验存在
|
||||
BargainActivityDO activityDO = validateBargainActivityExists(id);
|
||||
// 校验状态
|
||||
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
|
||||
}
|
||||
//if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
// throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
|
||||
//}
|
||||
|
||||
// 删除
|
||||
bargainActivityMapper.deleteById(id);
|
||||
@ -139,4 +141,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
||||
return bargainActivityMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO) {
|
||||
// 只查询进行中,且在时间范围内的
|
||||
return bargainActivityMapper.selectAppPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BargainActivityDO> getBargainActivityListForApp(Integer count) {
|
||||
// TODO @puhui999:这种 default count 的逻辑,可以放到 controller 哈;然后可以使用 ObjectUtils.default 方法
|
||||
if (count == null) {
|
||||
count = 6;
|
||||
}
|
||||
// TODO @puhui999:这种不要用 page;会浪费一次 count;
|
||||
PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count),
|
||||
CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
|
||||
return result.getList();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.combination;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
||||
@ -74,10 +73,14 @@ public interface CombinationActivityService {
|
||||
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
|
||||
|
||||
/**
|
||||
* 更新拼图活动库存
|
||||
* 校验是否满足拼团条件
|
||||
* 如果不满足,会抛出异常
|
||||
*
|
||||
* @param reqDTO 请求
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
|
||||
void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
||||
@ -34,7 +33,6 @@ import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
@ -88,7 +86,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
/**
|
||||
* 校验拼团商品参与的活动是否存在冲突
|
||||
*
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param activityId 拼团活动编号
|
||||
*/
|
||||
private void validateProductConflict(Long spuId, Long activityId) {
|
||||
@ -107,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
/**
|
||||
* 校验拼团商品是否都存在
|
||||
*
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param products 拼团商品
|
||||
*/
|
||||
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
|
||||
@ -152,7 +150,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
* 更新拼团商品
|
||||
*
|
||||
* @param activity 拼团活动
|
||||
* @param products 该活动的最新商品配置
|
||||
* @param products 该活动的最新商品配置
|
||||
*/
|
||||
private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
|
||||
// 第一步,对比新老数据,获得添加、修改、删除的列表
|
||||
@ -217,34 +215,33 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
|
||||
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
// 1.1 校验拼团活动是否存在
|
||||
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
|
||||
CombinationActivityDO activity = validateCombinationActivityExists(activityId);
|
||||
// 1.2 校验活动是否开启
|
||||
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
|
||||
}
|
||||
// 1.3 校验是否超出单次限购数量
|
||||
if (activity.getSingleLimitCount() < reqDTO.getCount()) {
|
||||
// TODO puhui999:count > activity.getSingleLimitCount() 会更好理解点;
|
||||
if (activity.getSingleLimitCount() < count) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
|
||||
// 2. 校验是否超出总限购数量
|
||||
// TODO @puhui999:userId 应该接口传递哈;要保证 service 无状态
|
||||
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(
|
||||
getLoginUserId(), reqDTO.getActivityId());
|
||||
// TODO @puhui999:最好 if true return;减少括号层数
|
||||
if (CollUtil.isNotEmpty(recordList)) {
|
||||
// 过滤出拼团成功的
|
||||
// TODO @puhui999:count 要不存一个在 record 里?
|
||||
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
|
||||
Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
|
||||
CombinationRecordDO::getOrderId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
|
||||
if (activity.getTotalLimitCount() < countSum) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
|
||||
if (CollUtil.isEmpty(recordList)) {
|
||||
return;
|
||||
}
|
||||
// 过滤出拼团成功的
|
||||
// TODO @puhui999:count 要不存一个在 record 里?
|
||||
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
|
||||
Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
|
||||
CombinationRecordDO::getOrderId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
|
||||
if (activity.getTotalLimitCount() < countSum) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,14 +57,4 @@ public interface CombinationRecordService {
|
||||
*/
|
||||
List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
|
||||
|
||||
/**
|
||||
* 验证组合限制数
|
||||
* 校验是否满足限购要求
|
||||
*
|
||||
* @param count 本次购买数量
|
||||
* @param sumCount 已购买数量合计
|
||||
* @param activityId 活动编号
|
||||
*/
|
||||
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
|
||||
|
||||
}
|
||||
|
@ -129,19 +129,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
}
|
||||
|
||||
// 2. 创建拼团记录
|
||||
// TODO @puhui999:可以把 user、spu、sku 一起放 convert 里哈;
|
||||
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
|
||||
record.setVirtualGroup(false);
|
||||
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
|
||||
record.setUserSize(activity.getUserSize());
|
||||
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
|
||||
record.setNickname(user.getNickname());
|
||||
record.setAvatar(user.getAvatar());
|
||||
ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
|
||||
record.setSpuName(spu.getName());
|
||||
ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
|
||||
record.setPicUrl(sku.getPicUrl());
|
||||
recordMapper.insert(record);
|
||||
ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
|
||||
ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
|
||||
recordMapper.insert(CombinationActivityConvert.INSTANCE.convert(reqDTO, activity, user, spu, sku));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -154,20 +145,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||
return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
|
||||
// 1.1 校验拼团活动
|
||||
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
|
||||
// 校验是否达到限购总限购标准
|
||||
if ((sumCount + count) > activity.getTotalLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
// 单次购买是否达到限购标准
|
||||
if (count > activity.getSingleLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* APP 端获取开团记录
|
||||
*
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.seckill;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
||||
|
||||
@ -37,9 +37,11 @@ public interface SeckillActivityService {
|
||||
/**
|
||||
* 更新秒杀库存
|
||||
*
|
||||
* @param updateStockReqDTO 更新信息
|
||||
* @param activityId 活动编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
|
||||
void updateSeckillStock(Long activityId, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 关闭秒杀活动
|
||||
@ -87,4 +89,20 @@ public interface SeckillActivityService {
|
||||
*/
|
||||
List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
|
||||
|
||||
/**
|
||||
* 通过活动时段获取秒杀活动
|
||||
*
|
||||
* @param ids 时段配置编号
|
||||
* @return 秒杀活动列表
|
||||
*/
|
||||
List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 通过活动时段获取秒杀活动
|
||||
*
|
||||
* @param pageReqVO 请求
|
||||
* @return 秒杀活动列表
|
||||
*/
|
||||
PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
|
@ -3,15 +3,16 @@ package cn.iocoder.yudao.module.promotion.service.seckill;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
||||
@ -147,32 +148,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
|
||||
public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
|
||||
// 1、校验秒杀活动是否存在
|
||||
SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
|
||||
SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
|
||||
// 1.1、校验库存是否充足
|
||||
if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
|
||||
if (seckillActivity.getTotalStock() < count) {
|
||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||
}
|
||||
|
||||
// 2、获取活动商品
|
||||
List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
|
||||
List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
|
||||
// 2.1、过滤出购买的商品
|
||||
SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId()));
|
||||
SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(skuId, item.getSkuId()));
|
||||
// 2.2、检查活动商品库存是否充足
|
||||
boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0);
|
||||
boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < count) || (product.getStock() - count) < 0);
|
||||
if (isSufficient) {
|
||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||
}
|
||||
|
||||
// 3、更新活动商品库存
|
||||
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
|
||||
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), count);
|
||||
if (updateCount == 0) {
|
||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||
}
|
||||
|
||||
// 4、更新活动库存
|
||||
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
|
||||
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), count);
|
||||
if (updateCount == 0) {
|
||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||
}
|
||||
@ -265,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
return seckillProductMapper.selectListByActivityId(activityIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
|
||||
return CollectionUtils.filterList(seckillActivityMapper.selectList(),
|
||||
item -> CollectionUtils.anyMatch(item.getConfigIds(), ids::contains));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
|
||||
return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -58,8 +58,9 @@ public interface ErrorCodeConstants {
|
||||
|
||||
// ========== Price 相关 1011003000 ============
|
||||
ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0");
|
||||
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空");
|
||||
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空");
|
||||
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板");
|
||||
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_PICK_UP_STORE_IS_EMPTY = new ErrorCode(1011003003, "计算快递运费异常,自提点为空");
|
||||
|
||||
// ========== 物流 Express 模块 1011004000 ==========
|
||||
ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在");
|
||||
@ -88,4 +89,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, "佣金提现记录状态不是审核中");
|
||||
|
||||
}
|
||||
|
@ -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"; // 佣金提现(审核不通过)
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -15,16 +15,15 @@ import java.util.Arrays;
|
||||
@AllArgsConstructor
|
||||
public enum DeliveryTypeEnum implements IntArrayValuable {
|
||||
|
||||
NULL(0, "无需物流"),
|
||||
EXPRESS(1, "快递发货"),
|
||||
PICK_UP(2, "用户自提"),;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryTypeEnum::getMode).toArray();
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryTypeEnum::getType).toArray();
|
||||
|
||||
/**
|
||||
* 配送方式
|
||||
*/
|
||||
private final Integer mode;
|
||||
private final Integer type;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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 合计提现
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -8,14 +8,15 @@ GET {{appApi}}/trade/order/settlement?type=0&items[0].cartId=50&couponId=1
|
||||
Authorization: Bearer {{appToken}}
|
||||
tenant-id: {{appTenentId}}
|
||||
|
||||
### /trade-order/create 创建订单(基于商品)
|
||||
### /trade-order/create 创建订单(基于商品)【快递】
|
||||
POST {{appApi}}/trade/order/create
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{appToken}}
|
||||
tenant-id: {{appTenentId}}
|
||||
|
||||
{
|
||||
"type": 0,
|
||||
"pointStatus": true,
|
||||
"deliveryType": 1,
|
||||
"addressId": 21,
|
||||
"items": [
|
||||
{
|
||||
@ -26,6 +27,27 @@ tenant-id: {{appTenentId}}
|
||||
"remark": "我是备注"
|
||||
}
|
||||
|
||||
### /trade-order/create 创建订单(基于商品)【自提】
|
||||
POST {{appApi}}/trade/order/create
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{appToken}}
|
||||
tenant-id: {{appTenentId}}
|
||||
|
||||
{
|
||||
"pointStatus": true,
|
||||
"deliveryType": 2,
|
||||
"pickUpStoreId": 1,
|
||||
"items": [
|
||||
{
|
||||
"skuId": 1,
|
||||
"count": 2
|
||||
}
|
||||
],
|
||||
"remark": "我是备注",
|
||||
"receiverName": "土豆",
|
||||
"receiverMobile": "15601691300"
|
||||
}
|
||||
|
||||
### 获得订单交易的分页
|
||||
GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10
|
||||
Authorization: Bearer {{appToken}}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.app.order;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
@ -12,11 +11,8 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||
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.order.TradeOrderOperateTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||
@ -65,10 +61,7 @@ public class AppTradeOrderController {
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建订单")
|
||||
@PreAuthenticated
|
||||
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST)
|
||||
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
|
||||
TradeOrderLogUtils.setOrderInfo(10L, 1, 2,
|
||||
MapUtil.<String, Object>builder().put("nickname", "小明").put("thing", "种土豆").build());
|
||||
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
|
||||
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
|
||||
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
|
||||
@Schema(description = "用户 App - 交易订单创建 Request VO")
|
||||
@Data
|
||||
public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
|
||||
@ -10,4 +13,10 @@ public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
|
||||
@Schema(description = "备注", example = "这个是我的订单哟")
|
||||
private String remark;
|
||||
|
||||
@AssertTrue(message = "配送方式不能为空")
|
||||
@JsonIgnore
|
||||
public boolean isDeliveryTypeNotNull() {
|
||||
return getDeliveryType() != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class AppTradeOrderSettlementReqVO {
|
||||
private Boolean pointStatus;
|
||||
|
||||
// ========== 配送相关相关字段 ==========
|
||||
@Schema(description = "配送方式", required = true, example = "1")
|
||||
@Schema(description = "配送方式", example = "1")
|
||||
@InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确")
|
||||
private Integer deliveryType;
|
||||
|
||||
@ -62,6 +62,8 @@ public class AppTradeOrderSettlementReqVO {
|
||||
@Schema(description = "砍价活动编号", example = "123")
|
||||
private Long bargainActivityId;
|
||||
|
||||
// TODO @puhui999:可以写个参数校验,如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况,items 应该只有一个
|
||||
|
||||
@Data
|
||||
@Schema(description = "用户 App - 商品项")
|
||||
@Valid
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -14,9 +14,7 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
|
||||
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
|
||||
@ -29,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;
|
||||
@ -59,6 +56,7 @@ public interface TradeOrderConvert {
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "id", ignore = true),
|
||||
@Mapping(source = "userId", target = "userId"),
|
||||
@Mapping(source = "createReqVO.couponId", target = "couponId"),
|
||||
@Mapping(target = "remark", ignore = true),
|
||||
@Mapping(source = "createReqVO.remark", target = "userRemark"),
|
||||
@ -67,14 +65,10 @@ public interface TradeOrderConvert {
|
||||
@Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
|
||||
@Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"),
|
||||
@Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"),
|
||||
@Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"),
|
||||
@Mapping(source = "address.name", target = "receiverName"),
|
||||
@Mapping(source = "address.mobile", target = "receiverMobile"),
|
||||
@Mapping(source = "address.areaId", target = "receiverAreaId"),
|
||||
@Mapping(source = "address.detailAddress", target = "receiverDetailAddress"),
|
||||
@Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice")
|
||||
})
|
||||
TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address);
|
||||
TradePriceCalculateRespBO calculateRespBO);
|
||||
|
||||
TradeOrderRespDTO convert(TradeOrderDO orderDO);
|
||||
|
||||
@ -92,22 +86,15 @@ public interface TradeOrderConvert {
|
||||
TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);
|
||||
|
||||
default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) {
|
||||
return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
default ProductSkuUpdateStockReqDTO convertNegative(List<TradeOrderItemDO> list) {
|
||||
List<ProductSkuUpdateStockReqDTO.Item> items = TradeOrderConvert.INSTANCE.convertList(list);
|
||||
items.forEach(item -> item.setIncrCount(-item.getIncrCount()));
|
||||
List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
|
||||
new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
|
||||
return new ProductSkuUpdateStockReqDTO(items);
|
||||
}
|
||||
default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
|
||||
List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
|
||||
new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
|
||||
return new ProductSkuUpdateStockReqDTO(items);
|
||||
}
|
||||
|
||||
List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(source = "skuId", target = "id"),
|
||||
@Mapping(source = "count", target = "incrCount"),
|
||||
})
|
||||
ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);
|
||||
|
||||
default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
|
||||
TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) {
|
||||
@ -221,8 +208,10 @@ public interface TradeOrderConvert {
|
||||
|
||||
default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
|
||||
List<CartDO> cartList) {
|
||||
TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();
|
||||
reqBO.setUserId(userId).setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId())
|
||||
TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId)
|
||||
.setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus())
|
||||
.setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId())
|
||||
.setPickUpStoreId(settlementReqVO.getPickUpStoreId())
|
||||
.setItems(new ArrayList<>(settlementReqVO.getItems().size()));
|
||||
// 商品项的构建
|
||||
Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
|
||||
@ -276,19 +265,13 @@ 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讲
|
||||
.setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord());
|
||||
.setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName()))
|
||||
.setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice());
|
||||
}
|
||||
|
||||
@Mapping(target = "activityId", source = "reqBO.seckillActivityId")
|
||||
SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
|
||||
|
||||
@Mapping(target = "activityId", source = "reqBO.combinationActivityId")
|
||||
CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
|
||||
|
||||
TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
|
||||
|
||||
@Mappings({
|
||||
@ -300,6 +283,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);
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -60,4 +60,12 @@ public class BrokerageUserDO extends BaseDO {
|
||||
*/
|
||||
private Integer frozenPrice;
|
||||
|
||||
/**
|
||||
* 等级
|
||||
*/
|
||||
private Integer level;
|
||||
/**
|
||||
* 路径
|
||||
*/
|
||||
private String path;
|
||||
}
|
||||
|
@ -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") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 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;
|
||||
|
||||
}
|
@ -224,6 +224,10 @@ public class TradeOrderDO extends BaseDO {
|
||||
* 关联 {@link DeliveryPickUpStoreDO#getId()}
|
||||
*/
|
||||
private Long pickUpStoreId;
|
||||
/**
|
||||
* 自提核销码
|
||||
*/
|
||||
private String pickUpVerifyCode;
|
||||
|
||||
// ========== 售后基本信息 ==========
|
||||
/**
|
||||
@ -251,12 +255,19 @@ public class TradeOrderDO extends BaseDO {
|
||||
* 对应 taobao 的 trade.coupon_fee 字段
|
||||
*/
|
||||
private Integer couponPrice;
|
||||
// TODO 芋艿:需要记录使用的积分;
|
||||
/**
|
||||
* 使用的积分
|
||||
*/
|
||||
private Integer usePoint;
|
||||
/**
|
||||
* 积分抵扣的金额,单位:分
|
||||
*
|
||||
* 对应 taobao 的 trade.point_fee 字段
|
||||
*/
|
||||
private Integer pointPrice;
|
||||
// /**
|
||||
// * 奖励的积分 TODO 疯狂:可以使用这个字段哈;
|
||||
// */
|
||||
// private Integer rewardPoint;
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 【会员】绑定推广员
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.order;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
@ -12,6 +13,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;
|
||||
@ -40,11 +43,11 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
||||
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
|
||||
import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.*;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
|
||||
import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
||||
@ -115,6 +118,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
@Resource
|
||||
private BargainRecordApi bargainRecordApi;
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
@Resource
|
||||
private MemberLevelApi memberLevelApi;
|
||||
@Resource
|
||||
private MemberPointApi memberPointApi;
|
||||
@ -178,140 +183,127 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
|
||||
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
|
||||
// 1、执行订单创建前置处理器
|
||||
// TODO @puhui999:最好也抽个 beforeOrderCreate 方法;
|
||||
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
|
||||
beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
|
||||
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
|
||||
// TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
|
||||
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
|
||||
|
||||
// 2. 价格计算
|
||||
// 0. 价格计算
|
||||
TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
|
||||
|
||||
// 1. 订单创建前的逻辑
|
||||
beforeCreateTradeOrder(userId, createReqVO, calculateRespBO);
|
||||
|
||||
// 2.1 插入 TradeOrderDO 订单
|
||||
TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO);
|
||||
// 2.2 插入 TradeOrderItemDO 订单项
|
||||
List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO);
|
||||
|
||||
// 3. 订单创建完后的逻辑
|
||||
// 3. 订单创建后的逻辑
|
||||
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
|
||||
|
||||
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
// TODO @puhui999:订单超时,自动取消;
|
||||
|
||||
/**
|
||||
* 校验收件地址是否存在
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param addressId 收件地址编号
|
||||
* @return 收件地址
|
||||
*/
|
||||
private AddressRespDTO validateAddress(Long userId, Long addressId) {
|
||||
AddressRespDTO address = addressApi.getAddress(addressId, userId);
|
||||
if (address == null) {
|
||||
throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 用户选择物流配送的时候才需要填写收货地址
|
||||
AddressRespDTO address = new AddressRespDTO();
|
||||
if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) {
|
||||
// 用户收件地址的校验
|
||||
address = validateAddress(userId, createReqVO.getAddressId());
|
||||
}
|
||||
TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
|
||||
String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
|
||||
order.setType(validateActivity(createReqVO));
|
||||
order.setNo(no);
|
||||
TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO);
|
||||
order.setType(calculateRespBO.getType());
|
||||
order.setNo(orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX));
|
||||
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
|
||||
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
|
||||
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
|
||||
order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
|
||||
// 支付信息
|
||||
// 支付 + 退款信息
|
||||
order.setAdjustPrice(0).setPayStatus(false);
|
||||
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
|
||||
// 物流信息
|
||||
order.setDeliveryType(createReqVO.getDeliveryType());
|
||||
// 退款信息
|
||||
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
|
||||
if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
|
||||
AddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
|
||||
Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算
|
||||
order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile())
|
||||
.setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress());
|
||||
} else if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.PICK_UP.getType())) {
|
||||
order.setReceiverName(createReqVO.getReceiverName()).setReceiverMobile(createReqVO.getReceiverMobile());
|
||||
order.setPickUpVerifyCode(RandomUtil.randomNumbers(8)); // 随机一个核销码,长度为 8 位
|
||||
}
|
||||
tradeOrderMapper.insert(order);
|
||||
// TODO @puhui999:如果是门店订单,则需要生成核销码;
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验活动,并返回订单类型
|
||||
*
|
||||
* @param createReqVO 请求参数
|
||||
* @return 订单类型
|
||||
*/
|
||||
private Integer validateActivity(AppTradeOrderCreateReqVO createReqVO) {
|
||||
if (createReqVO.getSeckillActivityId() != null) {
|
||||
return TradeOrderTypeEnum.SECKILL.getType();
|
||||
}
|
||||
if (createReqVO.getCombinationActivityId() != null) {
|
||||
return TradeOrderTypeEnum.COMBINATION.getType();
|
||||
}
|
||||
// TODO 砍价敬请期待
|
||||
return TradeOrderTypeEnum.NORMAL.getType();
|
||||
}
|
||||
|
||||
private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
|
||||
private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO);
|
||||
tradeOrderItemMapper.insertBatch(orderItems);
|
||||
return orderItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行创建完创建完订单后的逻辑
|
||||
* 订单创建前,执行前置逻辑
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param createReqVO 创建订单请求
|
||||
* @param calculateRespBO 订单价格计算结果
|
||||
*/
|
||||
private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 1. 执行订单创建前置处理器
|
||||
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
|
||||
beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
|
||||
beforeOrderCreateReqBO.setUserId(userId);
|
||||
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
|
||||
// TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
|
||||
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
|
||||
|
||||
// 2. 下单时扣减商品库存
|
||||
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单创建后,执行后置逻辑
|
||||
*
|
||||
* 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param createReqVO 创建订单请求
|
||||
* @param tradeOrderDO 交易订单
|
||||
* @param order 交易订单
|
||||
* @param calculateRespBO 订单价格计算结果
|
||||
*/
|
||||
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
|
||||
TradeOrderDO order, List<TradeOrderItemDO> orderItems,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 执行订单创建后置处理器
|
||||
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
|
||||
// 1. 执行订单创建后置处理器
|
||||
// TODO @puhui999:从通用性来说,应该不用 orderItems.get(0)
|
||||
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
|
||||
TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
|
||||
|
||||
// 扣减积分 TODO 芋艿:待实现,需要前置;
|
||||
// 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
|
||||
|
||||
// 有使用优惠券时更新 TODO 芋艿:需要前置;
|
||||
// 2. 有使用优惠券时更新
|
||||
// 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
|
||||
if (createReqVO.getCouponId() != null) {
|
||||
couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId)
|
||||
.setOrderId(tradeOrderDO.getId()));
|
||||
.setOrderId(order.getId()));
|
||||
}
|
||||
|
||||
// 下单时扣减商品库存
|
||||
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
|
||||
// 3. 扣减积分
|
||||
// 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务
|
||||
if (order.getUsePoint() != null && order.getUsePoint() > 0) {
|
||||
memberPointApi.reducePoint(userId, calculateRespBO.getUsePoint(),
|
||||
MemberPointBizTypeEnum.ORDER_USE.getType(), String.valueOf(order.getId()));
|
||||
}
|
||||
|
||||
// 删除购物车商品
|
||||
// 4. 删除购物车商品
|
||||
Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
|
||||
if (CollUtil.isNotEmpty(cartIds)) {
|
||||
cartService.deleteCart(userId, cartIds);
|
||||
}
|
||||
|
||||
// 生成预支付
|
||||
createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
|
||||
// 5. 生成预支付
|
||||
createPayOrder(order, orderItems, calculateRespBO);
|
||||
|
||||
// 增加订单日志 TODO 芋艿:待实现
|
||||
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
|
||||
}
|
||||
|
||||
|
||||
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
|
||||
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 创建支付单,用于后续的支付
|
||||
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
|
||||
order, orderItems, calculateRespBO, tradeOrderProperties);
|
||||
@ -339,6 +331,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
}
|
||||
// 校验活动
|
||||
// 1、拼团活动
|
||||
// TODO @puhui999:这块也抽象到 handler 里
|
||||
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
||||
// 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
|
||||
combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
|
||||
@ -416,7 +409,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
// 1.1 校验并获得交易订单(可发货)
|
||||
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
|
||||
// 1.2 校验 deliveryType 是否为快递,是快递才可以发货
|
||||
if (ObjectUtil.notEqual(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) {
|
||||
if (ObjectUtil.notEqual(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
|
||||
throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS);
|
||||
}
|
||||
|
||||
@ -726,7 +719,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
}
|
||||
|
||||
// TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
|
||||
tradeOrderHandlers.forEach(handler -> handler.rollbackStock());
|
||||
tradeOrderHandlers.forEach(handler -> handler.rollback());
|
||||
|
||||
// 2.回滚库存
|
||||
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
||||
@ -736,6 +729,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
couponApi.returnUsedCoupon(order.getCouponId());
|
||||
|
||||
// 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择;
|
||||
// TODO @疯狂:有赞是可配置(支付 or 确认收货),我们按照支付好列;然后这里的退积分,指的是下单时的积分抵扣。
|
||||
|
||||
// TODO 芋艿:OrderLog
|
||||
|
||||
@ -768,22 +762,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
|
||||
@Async
|
||||
protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) {
|
||||
int bizType = MemberPointBizTypeEnum.ORDER_BUY.getType();
|
||||
// TODO @疯狂:具体多少积分,需要分成 2 不分:1. 支付金额;2. 商品金额
|
||||
int bizType = MemberPointBizTypeEnum.ORDER_REWARD.getType();
|
||||
memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId));
|
||||
}
|
||||
|
||||
@Async
|
||||
protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) {
|
||||
// TODO @疯狂:退款时,按照金额比例,退还积分;https://help.youzan.com/displaylist/detail_4_4-1-49185
|
||||
int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType();
|
||||
memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
|
||||
}
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
// TODO 芋艿:在想想这些参数的定义
|
||||
@ -15,6 +14,8 @@ import javax.validation.constraints.NotNull;
|
||||
@Data
|
||||
public class TradeBeforeOrderCreateReqBO {
|
||||
|
||||
// TODO @puhui999:注释也写下哈;bo 还是写注释噢
|
||||
|
||||
@NotNull(message = "订单类型不能为空")
|
||||
private Integer orderType;
|
||||
|
||||
@ -34,25 +35,16 @@ public class TradeBeforeOrderCreateReqBO {
|
||||
@Schema(description = "砍价活动编号", example = "123")
|
||||
private Long bargainActivityId;
|
||||
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
@NotNull(message = "活动商品不能为空")
|
||||
private Item item;
|
||||
|
||||
@Data
|
||||
@Valid
|
||||
public static class Item {
|
||||
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
|
||||
|
||||
@Override
|
||||
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||
// 如果是秒杀订单
|
||||
// 如果是砍价订单
|
||||
if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
@ -37,7 +37,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackStock() {
|
||||
public void rollback() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
||||
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
@ -20,7 +20,7 @@ import javax.annotation.Resource;
|
||||
public class TradeCombinationHandler implements TradeOrderHandler {
|
||||
|
||||
@Resource
|
||||
private CombinationApi combinationApi;
|
||||
private CombinationActivityApi combinationActivityApi;
|
||||
@Resource
|
||||
private CombinationRecordApi combinationRecordApi;
|
||||
|
||||
@ -32,17 +32,22 @@ public class TradeCombinationHandler implements TradeOrderHandler {
|
||||
}
|
||||
|
||||
// 校验是否满足拼团活动相关限制
|
||||
combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
|
||||
combinationActivityApi.validateCombination(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||
// TODO @puhui999:需要判断下;
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建砍价记录
|
||||
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackStock() {
|
||||
public void rollback() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ public interface TradeOrderHandler {
|
||||
void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
|
||||
|
||||
/**
|
||||
* 回滚活动相关库存
|
||||
* 回滚
|
||||
*/
|
||||
void rollbackStock();
|
||||
void rollback();
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
||||
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
|
||||
seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackStock() {
|
||||
public void rollback() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price.bo;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
@ -17,13 +16,6 @@ import java.util.List;
|
||||
@Data
|
||||
public class TradePriceCalculateReqBO {
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
*
|
||||
* 枚举 {@link TradeOrderTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
@ -37,13 +29,12 @@ public class TradePriceCalculateReqBO {
|
||||
* 对应 CouponDO 的 id 编号
|
||||
*/
|
||||
private Long couponId;
|
||||
|
||||
// TODO @疯狂:需要增加一个 PriceCalculator 实现积分扣减的计算;写回到 TradePriceCalculateRespBO 的 usePoint
|
||||
/**
|
||||
* 收货地址编号
|
||||
*
|
||||
* 对应 MemberAddressDO 的 id 编号
|
||||
* 是否使用积分
|
||||
*/
|
||||
private Long addressId;
|
||||
@NotNull(message = "是否使用积分不能为空")
|
||||
private Boolean pointStatus;
|
||||
|
||||
/**
|
||||
* 配送方式
|
||||
@ -51,6 +42,18 @@ public class TradePriceCalculateReqBO {
|
||||
* 枚举 {@link DeliveryTypeEnum}
|
||||
*/
|
||||
private Integer deliveryType;
|
||||
/**
|
||||
* 收货地址编号
|
||||
*
|
||||
* 对应 MemberAddressDO 的 id 编号
|
||||
*/
|
||||
private Long addressId;
|
||||
/**
|
||||
* 自提门店编号
|
||||
*
|
||||
* 对应 PickUpStoreDO 的 id 编号
|
||||
*/
|
||||
private Long pickUpStoreId;
|
||||
|
||||
/**
|
||||
* 商品 SKU 数组
|
||||
@ -58,6 +61,30 @@ public class TradePriceCalculateReqBO {
|
||||
@NotNull(message = "商品数组不能为空")
|
||||
private List<Item> items;
|
||||
|
||||
// ========== 秒杀活动相关字段 ==========
|
||||
/**
|
||||
* 秒杀活动编号
|
||||
*/
|
||||
private Long seckillActivityId;
|
||||
|
||||
// ========== 拼团活动相关字段 ==========
|
||||
// TODO @puhui999:是不是拼团记录的编号哈?
|
||||
/**
|
||||
* 拼团活动编号
|
||||
*/
|
||||
private Long combinationActivityId;
|
||||
|
||||
/**
|
||||
* 拼团团长编号
|
||||
*/
|
||||
private Long combinationHeadId;
|
||||
|
||||
// ========== 砍价活动相关字段 ==========
|
||||
/**
|
||||
* 砍价活动编号
|
||||
*/
|
||||
private Long bargainActivityId;
|
||||
|
||||
/**
|
||||
* 商品 SKU
|
||||
*/
|
||||
|
@ -48,6 +48,11 @@ public class TradePriceCalculateRespBO {
|
||||
*/
|
||||
private Long couponId;
|
||||
|
||||
/**
|
||||
* 使用的积分
|
||||
*/
|
||||
private Integer usePoint;
|
||||
|
||||
/**
|
||||
* 订单价格
|
||||
*/
|
||||
|
@ -2,11 +2,14 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.module.member.api.address.AddressApi;
|
||||
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
@ -22,8 +25,7 @@ import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 运费的 {@link TradePriceCalculator} 实现类
|
||||
@ -37,20 +39,41 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
|
||||
|
||||
@Resource
|
||||
private AddressApi addressApi;
|
||||
|
||||
@Resource
|
||||
private DeliveryPickUpStoreService deliveryPickUpStoreService;
|
||||
@Resource
|
||||
private DeliveryExpressTemplateService deliveryExpressTemplateService;
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// TODO @芋艿:如果门店自提,需要校验是否开启;
|
||||
// 1.1 判断配送方式
|
||||
if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) {
|
||||
if (param.getDeliveryType() == null) {
|
||||
return;
|
||||
}
|
||||
if (param.getAddressId() == null) {
|
||||
throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY);
|
||||
if (DeliveryTypeEnum.PICK_UP.getType().equals(param.getDeliveryType())) {
|
||||
calculateByPickUp(param, result);
|
||||
} else if (DeliveryTypeEnum.EXPRESS.getType().equals(param.getDeliveryType())) {
|
||||
calculateExpress(param, result);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateByPickUp(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
if (param.getPickUpStoreId() == null) {
|
||||
throw exception(PRICE_CALCULATE_DELIVERY_PRICE_PICK_UP_STORE_IS_EMPTY);
|
||||
}
|
||||
DeliveryPickUpStoreDO pickUpStore = deliveryPickUpStoreService.getDeliveryPickUpStore(param.getPickUpStoreId());
|
||||
if (pickUpStore == null || CommonStatusEnum.DISABLE.getStatus().equals(pickUpStore.getStatus())) {
|
||||
throw exception(PICK_UP_STORE_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
// ========= 快递发货 ==========
|
||||
|
||||
private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 1. 得到收件地址区域
|
||||
if (param.getAddressId() == null) {
|
||||
throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
|
||||
}
|
||||
// 1.2 得到收件地址区域
|
||||
AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
|
||||
Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
|
||||
|
||||
@ -89,8 +112,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
|
||||
for (OrderItem orderItem : orderItems) {
|
||||
totalCount += orderItem.getCount();
|
||||
totalPrice += orderItem.getPayPrice();
|
||||
totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount();
|
||||
totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount();
|
||||
if (orderItem.getWeight() != null) {
|
||||
totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount();
|
||||
}
|
||||
if (orderItem.getVolume() != null) {
|
||||
totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount();
|
||||
}
|
||||
}
|
||||
// 优先判断是否包邮. 如果包邮不计算快递运费
|
||||
if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
|
||||
|
@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 使用积分的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Component
|
||||
@Order(TradePriceCalculator.ORDER_POINT_USE)
|
||||
@Slf4j
|
||||
public class TradePointUsePriceCalculator implements TradePriceCalculator {
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// TODO 疯狂:待实现,嘿嘿;
|
||||
if (param.getPointStatus()) {
|
||||
result.setUsePoint(10);
|
||||
} else {
|
||||
result.setUsePoint(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
/**
|
||||
* 价格计算的计算器接口
|
||||
*
|
||||
* 优惠计算顺序:
|
||||
* 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-53316">积分抵现、会员价、优惠券、粉丝专享价、满减送哪个优先计算?</>
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface TradePriceCalculator {
|
||||
@ -13,12 +16,13 @@ public interface TradePriceCalculator {
|
||||
int ORDER_DISCOUNT_ACTIVITY = 10;
|
||||
int ORDER_REWARD_ACTIVITY = 20;
|
||||
int ORDER_COUPON = 30;
|
||||
int ORDER_POINT_USE = 40;
|
||||
/**
|
||||
* 快递运费的计算
|
||||
*
|
||||
* 放在各种营销活动、优惠劵后面 TODO
|
||||
*/
|
||||
int ORDER_DELIVERY = 40;
|
||||
int ORDER_DELIVERY = 50;
|
||||
|
||||
void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result);
|
||||
|
||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
|
||||
@ -28,7 +29,7 @@ public class TradePriceCalculatorHelper {
|
||||
List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
|
||||
// 创建 PriceCalculateRespDTO 对象
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
|
||||
result.setType(param.getType());
|
||||
result.setType(getOrderType(param));
|
||||
result.setPromotions(new ArrayList<>());
|
||||
|
||||
// 创建它的 OrderItem 属性
|
||||
@ -69,6 +70,23 @@ public class TradePriceCalculatorHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算订单类型
|
||||
*
|
||||
* @param param 计算参数
|
||||
* @return 订单类型
|
||||
*/
|
||||
private static Integer getOrderType(TradePriceCalculateReqBO param) {
|
||||
if (param.getSeckillActivityId() != null) {
|
||||
return TradeOrderTypeEnum.SECKILL.getType();
|
||||
}
|
||||
if (param.getCombinationActivityId() != null) {
|
||||
return TradeOrderTypeEnum.COMBINATION.getType();
|
||||
}
|
||||
// TODO 砍价敬请期待
|
||||
return TradeOrderTypeEnum.NORMAL.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于订单项,重新计算 price 总价
|
||||
*
|
||||
|
@ -45,7 +45,7 @@ public class TradePriceServiceImplTest extends BaseMockitoUnitTest {
|
||||
public void testCalculatePrice() {
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType()).setUserId(10L)
|
||||
.setUserId(10L)
|
||||
.setCouponId(20L).setAddressId(30L)
|
||||
.setItems(Arrays.asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true),
|
||||
|
@ -50,7 +50,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
|
||||
public void init(){
|
||||
// 准备参数
|
||||
reqBO = new TradePriceCalculateReqBO()
|
||||
.setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode())
|
||||
.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType())
|
||||
.setAddressId(10L)
|
||||
.setUserId(1L)
|
||||
.setItems(asList(
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
|
@ -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 '佣金提现';
|
@ -21,6 +21,13 @@
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user