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

plp
jason 3 years ago
commit c880dbfa60

@ -2,41 +2,50 @@
create table trade_config create table trade_config
( (
id bigint auto_increment comment '' primary key, id bigint auto_increment comment '' primary key,
brokerage_enabled bit default 1 not null comment '', brokerage_enabled bit default 1 not null comment '',
brokerage_enabled_condition tinyint default 0 not null comment '1- 2-', brokerage_enabled_condition tinyint default 0 not null comment '1- 2-',
brokerage_bind_mode tinyint default 0 not null comment ': 1-广2-, 3-', brokerage_bind_mode tinyint default 0 not null comment ': 1-广2-, 3-',
brokerage_post_urls varchar(2000) default '' null comment '', brokerage_post_urls varchar(2000) default '' null comment '',
brokerage_first_percent int default 0 not null comment '', brokerage_first_percent int default 0 not null comment '',
brokerage_second_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_withdraw_min_price int default 0 not null comment '',
brokerage_bank_names varchar(200) default '' not null comment '=brokerage_bank_name', brokerage_bank_names varchar(200) default '' not null comment '=brokerage_bank_name',
brokerage_frozen_days int default 7 not null comment '()', 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-', 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 '', creator varchar(64) default '' null comment '',
create_time datetime default CURRENT_TIMESTAMP not null comment '', create_time datetime default CURRENT_TIMESTAMP not null comment '',
updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '', updater varchar(64) default '' null comment '',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '', update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '',
deleted bit default b'0' not null comment '', deleted bit default b'0' not null comment '',
tenant_id bigint default 0 not null comment '' tenant_id bigint default 0 not null comment ''
) 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 create table trade_brokerage_user
( (
id bigint auto_increment comment '' primary key, id bigint auto_increment comment '' primary key,
bind_user_id bigint null comment '广', bind_user_id bigint null comment '广',
bind_user_time datetime null comment '广', bind_user_time datetime null comment '广',
brokerage_enabled bit default 1 not null comment '广', brokerage_enabled bit default 1 not null comment '广',
brokerage_time datetime null comment '', brokerage_time datetime null comment '',
price int default 0 not null comment '', price int default 0 not null comment '',
frozen_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 '', level int default 1 not null comment '',
create_time datetime default CURRENT_TIMESTAMP not null comment '', path varchar(2000) null comment '',
updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '', creator varchar(64) default '' null comment '',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '', create_time datetime default CURRENT_TIMESTAMP not null comment '',
deleted bit default b'0' not null comment '', updater varchar(64) default '' null comment '',
tenant_id bigint default 0 not null comment '' update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '',
) 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_invite_user_id on trade_brokerage_user (bind_user_id) comment '广';
create index idx_agent on trade_brokerage_user (brokerage_enabled) 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 create table trade_brokerage_record
( (
id int auto_increment comment '' id int auto_increment comment ''
primary key, primary key,
user_id bigint not null comment '', user_id bigint not null comment '',
biz_id varchar(64) default '' not null comment '', biz_id varchar(64) default '' not null comment '',
biz_type tinyint default 0 not null comment '1-2-', biz_type tinyint default 0 not null comment '1-2-',
title varchar(64) default '' not null comment '', title varchar(64) default '' not null comment '',
price int default 0 not null comment '', price int default 0 not null comment '',
total_price int default 0 not null comment '', total_price int default 0 not null comment '',
description varchar(500) default '' not null comment '', description varchar(500) default '' not null comment '',
status tinyint default 0 not null comment '0-1-2-', status tinyint default 0 not null comment '0-1-2-',
frozen_days int default 0 not null comment '', frozen_days int default 0 not null comment '',
unfreeze_time datetime null comment '', unfreeze_time datetime null comment '',
source_user_type tinyint not null comment '1-广2-广', source_user_level int not null comment '',
source_user_id bigint not null comment '', source_user_id bigint not null comment '',
creator varchar(64) collate utf8mb4_general_ci default '' null comment '', creator varchar(64) default '' null comment '',
create_time datetime default CURRENT_TIMESTAMP not null comment '', create_time datetime default CURRENT_TIMESTAMP not null comment '',
updater varchar(64) collate utf8mb4_general_ci default '' null comment '', updater varchar(64) default '' null comment '',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '', update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '',
deleted bit default b'0' not null comment '', deleted bit default b'0' not null comment '',
tenant_id bigint default 0 not null comment '' tenant_id bigint default 0 not null comment ''
) )
comment ''; comment '';
@ -76,26 +85,26 @@ create table trade_brokerage_withdraw
( (
id int auto_increment comment '' id int auto_increment comment ''
primary key, primary key,
user_id bigint not null comment '', user_id bigint not null comment '',
price int default 0 not null comment '', price int default 0 not null comment '',
fee_price int default 0 not null comment '', fee_price int default 0 not null comment '',
total_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-', type tinyint default 0 not null comment '1-2-3-4-',
name varchar(64) null comment '', name varchar(64) null comment '',
account_no varchar(64) null comment '', account_no varchar(64) null comment '',
bank_name varchar(100) null comment '', bank_name varchar(100) null comment '',
bank_address varchar(200) null comment '', bank_address varchar(200) null comment '',
account_qr_code_url varchar(512) null comment '', account_qr_code_url varchar(512) null comment '',
status tinyint(2) default 0 not null comment '0-10- 20-11 - 21-', status tinyint(2) default 0 not null comment '0-10- 20-11 - 21-',
audit_reason varchar(128) null comment '', audit_reason varchar(128) null comment '',
audit_time datetime null comment '', audit_time datetime null comment '',
remark varchar(500) null comment '', remark varchar(500) null comment '',
creator varchar(64) collate utf8mb4_general_ci default '' null comment '', creator varchar(64) default '' null comment '',
create_time datetime default CURRENT_TIMESTAMP not null comment '', create_time datetime default CURRENT_TIMESTAMP not null comment '',
updater varchar(64) collate utf8mb4_general_ci default '' null comment '', updater varchar(64) default '' null comment '',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '', update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '',
deleted bit default b'0' not null comment '', deleted bit default b'0' not null comment '',
tenant_id bigint default 0 not null comment '' tenant_id bigint default 0 not null comment ''
) )
comment ''; comment '';
@ -139,12 +148,12 @@ values ('brokerage_record_status', '待结算', 0, 0),
insert into system_dict_type(type, name) insert into system_dict_type(type, name)
values ('brokerage_withdraw_status', ''); values ('brokerage_withdraw_status', '');
insert into system_dict_data(dict_type, label, value, sort) insert into system_dict_data(dict_type, label, value, sort, color_type)
values ('brokerage_withdraw_status', '', 0, 0), values ('brokerage_withdraw_status', '', 0, 0, ''),
('brokerage_withdraw_status', '', 10, 10), ('brokerage_withdraw_status', '', 10, 10, 'success'),
('brokerage_withdraw_status', '', 11, 11), ('brokerage_withdraw_status', '', 11, 11, 'success'),
('brokerage_withdraw_status', '', 20, 20), ('brokerage_withdraw_status', '', 20, 20, 'danger'),
('brokerage_withdraw_status', '', 21, 21); ('brokerage_withdraw_status', '', 21, 21, 'danger');
insert into system_dict_type(type, name) insert into system_dict_type(type, name)
values ('brokerage_bank_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) INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0); VALUES ('', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) 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); 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, public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
int year2, int mouth2, int day2) { int year2, int mouth2, int day2) {
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, 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); 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); 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 @Override

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

@ -39,7 +39,7 @@ public interface ProductSkuApi {
List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds); List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
/** /**
* SKU * SKU or
* *
* @param updateStockReqDTO * @param updateStockReqDTO
*/ */

@ -59,14 +59,13 @@ public class ProductSkuRespDTO {
* m^3 * m^3
*/ */
private Double volume; private Double volume;
// TODO @puhui999firstBrokeragePrice 尴尬我当时打错了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; 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 cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import lombok.Data; import lombok.Data;
@ -31,6 +30,12 @@ public class ProductSpuRespDTO {
* *
*/ */
private String keyword; private String keyword;
/**
*
*
* product_unit
*/
private Integer unit;
/** /**
* *
*/ */

@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
private Double volume; private Double volume;
@Schema(description = "一级分销的佣金,单位:分", example = "199") @Schema(description = "一级分销的佣金,单位:分", example = "199")
private Integer firstBrokerageRecord; private Integer firstBrokeragePrice;
@Schema(description = "二级分销的佣金,单位:分", example = "19") @Schema(description = "二级分销的佣金,单位:分", example = "19")
private Integer secondBrokerageRecord; private Integer secondBrokeragePrice;
@Schema(description = "属性数组") @Schema(description = "属性数组")
private List<Property> properties; 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.setMarketPrice(generaInt());
o.setStock(generaInt()); o.setStock(generaInt());
o.setWarnStock(10); o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt()); o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokerageRecord(generaInt()); o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数 // 限制分数为两位数
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
o.setVolume(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.setMarketPrice(generaInt());
o.setStock(generaInt()); o.setStock(generaInt());
o.setWarnStock(10); o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt()); o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokerageRecord(generaInt()); o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数 // 限制分数为两位数
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
o.setVolume(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; 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.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
// TODO @芋艿:后面也再撸撸这几个接口 // TODO @芋艿:后面也再撸撸这几个接口
@ -33,26 +31,7 @@ public interface CombinationRecordApi {
boolean isCombinationRecordSuccess(Long userId, Long orderId); 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 userId
* @param orderId * @param orderId
@ -60,7 +39,7 @@ public interface CombinationRecordApi {
void updateRecordStatusToSuccess(Long userId, Long orderId); void updateRecordStatusToSuccess(Long userId, Long orderId);
/** /**
* *
* *
* @param userId * @param userId
* @param orderId * @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 @Data
public class CombinationRecordCreateReqDTO { public class CombinationRecordCreateReqDTO {
// TODO @puhui999注释还是要的哈 /**
*
*/
@NotNull(message = "拼团活动编号不能为空") @NotNull(message = "拼团活动编号不能为空")
private Long activityId; private Long activityId;
/**
* spu
*/
@NotNull(message = "spu 编号不能为空") @NotNull(message = "spu 编号不能为空")
private Long spuId; private Long spuId;
/**
* sku
*/
@NotNull(message = "sku 编号不能为空") @NotNull(message = "sku 编号不能为空")
private Long skuId; private Long skuId;
/**
*
*/
@NotNull(message = "订单编号不能为空") @NotNull(message = "订单编号不能为空")
private Long orderId; private Long orderId;
/**
*
*/
@NotNull(message = "用户编号不能为空") @NotNull(message = "用户编号不能为空")
private Long userId; private Long userId;
/**
*
*/
@NotNull(message = "团长编号不能为空") @NotNull(message = "团长编号不能为空")
private Long headId; private Long headId;
/**
*
*/
@NotNull(message = "拼团商品单价不能为空") @NotNull(message = "拼团商品单价不能为空")
private Integer combinationPrice; private Integer combinationPrice;

@ -1,7 +1,5 @@
package cn.iocoder.yudao.module.promotion.api.seckill; package cn.iocoder.yudao.module.promotion.api.seckill;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
/** /**
* API * API
* *
@ -9,11 +7,14 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateSt
*/ */
public interface SeckillActivityApi { public interface SeckillActivityApi {
// TODO @puhui999activityId 改成 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_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足"); ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
// ========== 秒杀时段 1013009000 ========== // ========== 秒杀时段 1013009000 ==========
ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");

@ -77,6 +77,10 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId> <artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -1,9 +1,7 @@
package cn.iocoder.yudao.module.promotion.api.combination; 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 cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -13,15 +11,14 @@ import javax.annotation.Resource;
* @author HUIHUI * @author HUIHUI
*/ */
@Service @Service
@Validated public class CombinationActivityApiImpl implements CombinationActivityApi {
public class CombinationApiImpl implements CombinationApi {
@Resource @Resource
private CombinationActivityService activityService; private CombinationActivityService activityService;
@Override @Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) { public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
activityService.validateCombination(reqDTO); activityService.validateCombination(activityId, userId, skuId, count);
} }
} }

@ -1,15 +1,12 @@
package cn.iocoder.yudao.module.promotion.api.combination; 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.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.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/** /**
* API * API
@ -32,16 +29,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus()); 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 @Override
public void updateRecordStatusToSuccess(Long userId, Long orderId) { public void updateRecordStatusToSuccess(Long userId, Long orderId) {
recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId); recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.api.seckill; 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 cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
private SeckillActivityService activityService; private SeckillActivityService activityService;
@Override @Override
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
activityService.updateSeckillStock(updateStockReqDTO); 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.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO; 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.annotation.Resource;
import javax.validation.Valid; 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.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "管理后台 - 砍价活动") @Tag(name = "管理后台 - 砍价活动")
@RestController @RestController
@ -30,6 +34,8 @@ public class BargainActivityController {
@Resource @Resource
private BargainActivityService activityService; private BargainActivityService activityService;
@Resource
private ProductSpuApi spuApi;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建砍价活动") @Operation(summary = "创建砍价活动")
@ -73,7 +79,10 @@ public class BargainActivityController {
if (CollUtil.isEmpty(pageResult.getList())) { if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal())); 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; 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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.AppBargainActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO; 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.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; 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.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.time.Duration; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "用户 App - 砍价活动") @Tag(name = "用户 App - 砍价活动")
@RestController @RestController
@RequestMapping("/promotion/bargain-activity") @RequestMapping("/promotion/bargain-activity")
@Validated @Validated
public class AppBargainActivityController { public class AppBargainActivityController {
@Resource
private BargainActivityService bargainActivityService;
@Resource
private ProductSpuApi spuApi;
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得砍价活动活动") // TODO 芋艿:只查询进行中,且在时间范围内的 @Operation(summary = "获得砍价活动分页")
// TODO 芋艿:缺少 swagger 注解
public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) { public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
List<AppBargainActivityRespVO> activityList = new ArrayList<>(); PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPageForApp(pageReqVO);
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO(); if (CollUtil.isEmpty(result.getList())) {
activity1.setId(1L); return success(PageResult.empty(result.getTotal()));
activity1.setName("618 大砍价"); }
activity1.setSpuId(2048L); // 拼接数据
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(result.getList(), BargainActivityDO::getSpuId));
activity1.setMarketPrice(50); return success(BargainActivityConvert.INSTANCE.convertAppPage(result, spuList));
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));
} }
// TODO 芋艿:增加 Spring Cache
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "获得砍价活动列表", description = "用于小程序首页") @Operation(summary = "获得砍价活动列表", description = "用于小程序首页")
// TODO 芋艿:增加 Spring Cache @Parameter(name = "count", description = "需要展示的数量", example = "6")
// TODO 芋艿:缺少 swagger 注解
public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList( public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
@RequestParam(name = "count", defaultValue = "6") Integer count) { @RequestParam(name = "count", defaultValue = "6") Integer count) {
List<AppBargainActivityRespVO> activityList = new ArrayList<>(); List<BargainActivityDO> list = bargainActivityService.getBargainActivityListForApp(count);
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO(); if (CollUtil.isEmpty(list)) {
activity1.setId(1L); return success(BargainActivityConvert.INSTANCE.convertAppList(list));
activity1.setName("618 大砍价"); }
activity1.setSpuId(2048L); // 拼接数据
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, BargainActivityDO::getSpuId));
activity1.setMarketPrice(50); return success(BargainActivityConvert.INSTANCE.convertAppList(list, spuList));
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);
} }
@GetMapping("/get-detail") @GetMapping("/get-detail")
@Operation(summary = "获得砍价活动详情") @Operation(summary = "获得砍价活动详情")
// TODO 芋艿:缺少 swagger 注解 @Parameter(name = "id", description = "活动编号", example = "1")
public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) { public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) {
AppBargainActivityDetailRespVO activity = new AppBargainActivityDetailRespVO(); BargainActivityDO activity = bargainActivityService.getBargainActivity(id);
activity.setId(2L); if (activity == null) {
activity.setName("618 大砍价"); return success(null);
activity.setSpuId(2048L); }
activity.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); // 拼接数据
activity.setMarketPrice(50); ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId());
activity.setBargainPrice(100); return success(BargainActivityConvert.INSTANCE.convert(activity, spu));
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);
} }
} }

@ -45,7 +45,7 @@ public class AppBargainActivityDetailRespVO {
@Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换 @Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换
private String unitName; private String unitName;
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价 @Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
private Integer bargainPrice; private Integer bargainPrice;
@Schema(description = "砍价成功数量", required = true, example = "100") @Schema(description = "砍价成功数量", required = true, example = "100")

@ -36,7 +36,7 @@ public class AppBargainActivityRespVO {
@Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取 @Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取
private Integer marketPrice; private Integer marketPrice;
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价 @Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
private Integer bargainPrice; private Integer bargainPrice;
} }

@ -1,136 +1,115 @@
package cn.iocoder.yudao.module.promotion.controller.app.seckill; 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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.AppSeckillActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; 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.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; 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.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; 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.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 - 秒杀活动") @Tag(name = "用户 App - 秒杀活动")
@RestController @RestController
@RequestMapping("/promotion/seckill-activity") @RequestMapping("/promotion/seckill-activity")
@Validated @Validated
public class AppSeckillActivityController { public class AppSeckillActivityController {
@Resource
private SeckillActivityService activityService;
@Resource
@Lazy
private SeckillConfigService configService;
@Resource
private ProductSpuApi spuApi;
@GetMapping("/get-now") @GetMapping("/get-now")
@Operation(summary = "获得当前秒杀活动") // 提供给首页使用 @Operation(summary = "获得当前秒杀活动") // 提供给首页使用
// TODO 芋艿:需要增加 spring cache // TODO 芋艿:需要增加 spring cache
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() { public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO(); // 1. 获取当前时间处在哪个秒杀阶段
respVO.setConfig(new AppSeckillConfigRespVO().setId(10L).setStartTime("01:00").setEndTime("09:59")); // TODO @puhui999可以考虑在 service 写个方法;这样 controller 不用关注过多逻辑
List<AppSeckillActivityRespVO> activityList = new ArrayList<>(); List<SeckillConfigDO> configList = configService.getSeckillConfigList();
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO(); SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
activity1.setId(1L); CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
activity1.setName("618 大秒杀"); if (filteredConfig == null) { // 时段不存在直接返回 null
activity1.setSpuId(2048L); return success(null);
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"); }
activity1.setMarketPrice(50);
activity1.setSeckillPrice(100); // 2. 查询满足当前阶段的活动
activityList.add(activity1); // TODO @puhui999最好直接返回开启的不多查询数据
List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO(); // 3. 拼接数据
activity2.setId(2L); List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(filteredList, SeckillActivityDO::getSpuId));
activity2.setName("双十一大秒杀"); return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
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);
} }
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得秒杀活动分页") @Operation(summary = "获得秒杀活动分页")
// TODO @芋艿:分页参数
public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) { public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
List<AppSeckillActivityRespVO> activityList = new ArrayList<>(); // 1. 查询满足当前阶段的活动
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO(); PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
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);
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO(); // 2. 拼接数据
activity2.setId(2L); List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
activity2.setName("双十一大秒杀"); return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
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));
} }
@GetMapping("/get-detail") @GetMapping("/get-detail")
@Operation(summary = "获得秒杀活动明细") @Operation(summary = "获得秒杀活动明细")
@Parameter(name = "id", description = "活动编号", required = true, example = "1024") @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) { public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
// 1、获取当前时间处在哪个秒杀阶段
// TODO puhui999这里和 58 行是雷同的
List<SeckillConfigDO> configList = configService.getSeckillConfigList();
SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
if (filteredConfig == null) { // 时段不存在直接返回 null
return success(null);
}
// 2. 获取活动
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
if (seckillActivity == null) {
return success(null);
}
// TODO 芋艿:如果禁用的时候,需要抛出异常; // TODO 芋艿:如果禁用的时候,需要抛出异常;
AppSeckillActivityDetailRespVO obj = new AppSeckillActivityDetailRespVO(); if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
// 设置其属性的值 throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
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);
// 创建一个Product对象的列表 // 3. 拼接数据
List<AppSeckillActivityDetailRespVO.Product> productList = new ArrayList<>(); List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
// 创建三个新的Product对象并设置其属性的值 return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
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);
} }
} }

@ -1,7 +1,12 @@
package cn.iocoder.yudao.module.promotion.controller.app.seckill; 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.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays; import javax.annotation.Resource;
import java.util.Collections;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 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") @RequestMapping("/promotion/seckill-config")
@Validated @Validated
public class AppSeckillConfigController { public class AppSeckillConfigController {
@Resource
private SeckillConfigService configService;
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "获得秒杀时间段列表") @Operation(summary = "获得秒杀时间段列表")
public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() { public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
return success(Arrays.asList( List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59") // TODO @puhui999如果这种不用判空也问题不大
.setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg", if (CollectionUtil.isEmpty(list)) {
"https://static.iocoder.cn/mall/132.jpeg")), return success(Collections.emptyList());
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") return success(SeckillConfigConvert.INSTANCE.convertList2(list));
));
} }
} }

@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO {
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status; private Integer status;
// TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈 // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
@Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime startTime; private LocalDateTime startTime;

@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO {
private Integer totalStock; private Integer totalStock;
@Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
// 从秒杀商品里取最低价
private Integer seckillPrice; private Integer seckillPrice;
} }

@ -1,14 +1,24 @@
package cn.iocoder.yudao.module.promotion.convert.bargain; package cn.iocoder.yudao.module.promotion.convert.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO; 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.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 cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List; 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 * Convert
@ -30,4 +40,65 @@ public interface BargainActivityConvert {
PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page); 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 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.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 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.api.combination.dto.CombinationRecordRespDTO;
@ -92,6 +94,21 @@ public interface CombinationActivityConvert {
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO); 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); 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 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.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.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 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.SeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 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.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; 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.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 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.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
import java.util.Map; 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 * Convert
* *
@ -79,4 +90,53 @@ public interface SeckillActivityConvert {
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list); 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.SeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO; 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.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 cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@ -33,4 +34,7 @@ public interface SeckillConfigConvert {
PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page); 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 singleLimitCount;
/** /**
* * ()
*/ */
private Integer stock; private Integer stock;
/** /**

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain; 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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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 com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@ -39,8 +41,15 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default int updateActivityStock(Long id, int count) { default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<BargainActivityDO>() return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
.eq(BargainActivityDO::getId, id) .eq(BargainActivityDO::getId, id)
.gt(BargainActivityDO::getStock, 0) // TODO @puhui999不是 > 0是要大于 count 哈 .ge(BargainActivityDO::getStock, count)
.setSql("stock = stock - " + 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.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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.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 cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName()) .likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus()) .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime()) .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)); .orderByDesc(SeckillActivityDO::getId));
} }
@ -48,4 +49,11 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
.setSql("totalStock = totalStock - " + count)); .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) { default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<SeckillProductDO>() return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
.eq(SeckillProductDO::getId, id) .eq(SeckillProductDO::getId, id)
.gt(SeckillProductDO::getStock, 0) // TODO @puhui999不是 > 0是要大于 count 哈 .gt(SeckillProductDO::getStock, count)
.setSql("stock = stock - " + count)); .setSql("stock = stock - " + count));
} }

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.bargain; 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.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.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO; 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 cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
/** /**
* Service * Service
@ -61,4 +63,22 @@ public interface BargainActivityService {
*/ */
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO); 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.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 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.sku.dto.ProductSkuRespDTO;
@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -113,9 +115,9 @@ public class BargainActivityServiceImpl implements BargainActivityService {
// 校验存在 // 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(id); BargainActivityDO activityDO = validateBargainActivityExists(id);
// 校验状态 // 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { //if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); // throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
} //}
// 删除 // 删除
bargainActivityMapper.deleteById(id); bargainActivityMapper.deleteById(id);
@ -139,4 +141,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
return bargainActivityMapper.selectPage(pageReqVO); 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; package cn.iocoder.yudao.module.promotion.service.combination;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 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); 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.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 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.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 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.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 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 * @param activityId
*/ */
private void validateProductConflict(Long spuId, Long 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 * @param products
*/ */
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) { private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
@ -152,7 +150,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
* *
* *
* @param activity * @param activity
* @param products * @param products
*/ */
private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) { private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
// 第一步,对比新老数据,获得添加、修改、删除的列表 // 第一步,对比新老数据,获得添加、修改、删除的列表
@ -217,34 +215,33 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
} }
@Override @Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) { public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
// 1.1 校验拼团活动是否存在 // 1.1 校验拼团活动是否存在
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId()); CombinationActivityDO activity = validateCombinationActivityExists(activityId);
// 1.2 校验活动是否开启 // 1.2 校验活动是否开启
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
} }
// 1.3 校验是否超出单次限购数量 // 1.3 校验是否超出单次限购数量
if (activity.getSingleLimitCount() < reqDTO.getCount()) { // TODO puhui999count > activity.getSingleLimitCount() 会更好理解点;
if (activity.getSingleLimitCount() < count) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
} }
// 2. 校验是否超出总限购数量 // 2. 校验是否超出总限购数量
// TODO @puhui999userId 应该接口传递哈;要保证 service 无状态 List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId( if (CollUtil.isEmpty(recordList)) {
getLoginUserId(), reqDTO.getActivityId()); return;
// TODO @puhui999最好 if true return减少括号层数 }
if (CollUtil.isNotEmpty(recordList)) { // 过滤出拼团成功的
// 过滤出拼团成功的 // TODO @puhui999count 要不存一个在 record 里?
// TODO @puhui999count 要不存一个在 record 里? List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList, CombinationRecordDO::getOrderId,
CombinationRecordDO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); if (activity.getTotalLimitCount() < countSum) {
if (activity.getTotalLimitCount() < countSum) { throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
}
} }
} }

@ -57,14 +57,4 @@ public interface CombinationRecordService {
*/ */
List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId); 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. 创建拼团记录 // 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()); MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
record.setNickname(user.getNickname()); ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
record.setAvatar(user.getAvatar()); ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId()); recordMapper.insert(CombinationActivityConvert.INSTANCE.convert(reqDTO, activity, user, spu, sku));
record.setSpuName(spu.getName());
ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
record.setPicUrl(sku.getPicUrl());
recordMapper.insert(record);
} }
@Override @Override
@ -154,20 +145,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return recordMapper.selectListByUserIdAndActivityId(userId, activityId); 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 * APP
* *

@ -1,10 +1,10 @@
package cn.iocoder.yudao.module.promotion.service.seckill; package cn.iocoder.yudao.module.promotion.service.seckill;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 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.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.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 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); 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.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 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.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 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.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 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.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.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.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.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@ -147,32 +148,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
// 1、校验秒杀活动是否存在 // 1、校验秒杀活动是否存在
SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId()); SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
// 1.1、校验库存是否充足 // 1.1、校验库存是否充足
if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) { if (seckillActivity.getTotalStock() < count) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 2、获取活动商品 // 2、获取活动商品
List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId()); List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
// 2.1、过滤出购买的商品 // 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、检查活动商品库存是否充足 // 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) { if (isSufficient) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 3、更新活动商品库存 // 3、更新活动商品库存
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount()); int updateCount = seckillProductMapper.updateActivityStock(product.getId(), count);
if (updateCount == 0) { if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 4、更新活动库存 // 4、更新活动库存
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount()); updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), count);
if (updateCount == 0) { if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
@ -265,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
return seckillProductMapper.selectListByActivityId(activityIds); 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 ============ // ========== Price 相关 1011003000 ============
ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0"); 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_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板");
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_PICK_UP_STORE_IS_EMPTY = new ErrorCode(1011003003, "计算快递运费异常,自提点为空");
// ========== 物流 Express 模块 1011004000 ========== // ========== 物流 Express 模块 1011004000 ==========
ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(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_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人");
ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级"); 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 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 @AllArgsConstructor
public enum DeliveryTypeEnum implements IntArrayValuable { public enum DeliveryTypeEnum implements IntArrayValuable {
NULL(0, "无需物流"),
EXPRESS(1, "快递发货"), EXPRESS(1, "快递发货"),
PICK_UP(2, "用户自提"),; 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) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime unfreezeTime; private LocalDateTime unfreezeTime;
@Schema(description = "来源用户类型") @Schema(description = "来源用户等级")
private Integer sourceUserType; private Integer sourceUserLevel;
@Schema(description = "来源用户编号") @Schema(description = "来源用户编号")
private Long sourceUserId; private Long sourceUserId;

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

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

@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo; 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.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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -22,18 +20,18 @@ public class BrokerageUserPageReqVO extends PageParam {
@Schema(description = "推广员编号", example = "4587") @Schema(description = "推广员编号", example = "4587")
private Long bindUserId; private Long bindUserId;
@Schema(description = "推广资格") @Schema(description = "推广资格", example = "true")
private Boolean brokerageEnabled; private Boolean brokerageEnabled;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@Schema(description = "用户类型") @Schema(description = "用户等级", example = "1") // 注意,这了不是用户的会员等级,而是过滤推广的层级
@InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}") private Integer level;
private Integer userType;
@Schema(description = "绑定时间") @Schema(description = "绑定时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] bindUserTime; 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}} Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}} tenant-id: {{appTenentId}}
### /trade-order/create 创建订单(基于商品) ### /trade-order/create 创建订单(基于商品)【快递】
POST {{appApi}}/trade/order/create POST {{appApi}}/trade/order/create
Content-Type: application/json Content-Type: application/json
Authorization: Bearer {{appToken}} Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}} tenant-id: {{appTenentId}}
{ {
"type": 0, "pointStatus": true,
"deliveryType": 1,
"addressId": 21, "addressId": 21,
"items": [ "items": [
{ {
@ -26,6 +27,27 @@ tenant-id: {{appTenentId}}
"remark": "我是备注" "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 GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10
Authorization: Bearer {{appToken}} Authorization: Bearer {{appToken}}

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.trade.controller.app.order; 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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 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.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.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.enums.order.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 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.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
@ -65,10 +61,7 @@ public class AppTradeOrderController {
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建订单") @Operation(summary = "创建订单")
@PreAuthenticated @PreAuthenticated
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST) public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
TradeOrderLogUtils.setOrderInfo(10L, 1, 2,
MapUtil.<String, Object>builder().put("nickname", "小明").put("thing", "种土豆").build());
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO); TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
} }

@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo; 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.AssertTrue;
@Schema(description = "用户 App - 交易订单创建 Request VO") @Schema(description = "用户 App - 交易订单创建 Request VO")
@Data @Data
public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO { public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
@ -10,4 +13,10 @@ public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
@Schema(description = "备注", example = "这个是我的订单哟") @Schema(description = "备注", example = "这个是我的订单哟")
private String remark; private String remark;
@AssertTrue(message = "配送方式不能为空")
@JsonIgnore
public boolean isDeliveryTypeNotNull() {
return getDeliveryType() != null;
}
} }

@ -30,7 +30,7 @@ public class AppTradeOrderSettlementReqVO {
private Boolean pointStatus; private Boolean pointStatus;
// ========== 配送相关相关字段 ========== // ========== 配送相关相关字段 ==========
@Schema(description = "配送方式", required = true, example = "1") @Schema(description = "配送方式", example = "1")
@InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确") @InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确")
private Integer deliveryType; private Integer deliveryType;
@ -62,6 +62,8 @@ public class AppTradeOrderSettlementReqVO {
@Schema(description = "砍价活动编号", example = "123") @Schema(description = "砍价活动编号", example = "123")
private Long bargainActivityId; private Long bargainActivityId;
// TODO @puhui999可以写个参数校验如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况items 应该只有一个
@Data @Data
@Schema(description = "用户 App - 商品项") @Schema(description = "用户 App - 商品项")
@Valid @Valid

@ -35,7 +35,7 @@ public interface BrokerageRecordConvert {
default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
String title, Long sourceUserId, Integer sourceUserType) { String title, Long sourceUserId, Integer sourceUserLevel) {
brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
// 不冻结时,佣金直接就是结算状态 // 不冻结时,佣金直接就是结算状态
Integer status = brokerageFrozenDays > 0 Integer status = brokerageFrozenDays > 0
@ -47,7 +47,7 @@ public interface BrokerageRecordConvert {
.setTitle(title) .setTitle(title)
.setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d))) .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
.setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime) .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) { 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.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 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.controller.admin.brokerage.user.vo.BrokerageUserRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; 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())); user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
return target; 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.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 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.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.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.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.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; 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.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.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.enums.order.TradeOrderItemAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@ -59,6 +56,7 @@ public interface TradeOrderConvert {
@Mappings({ @Mappings({
@Mapping(target = "id", ignore = true), @Mapping(target = "id", ignore = true),
@Mapping(source = "userId", target = "userId"),
@Mapping(source = "createReqVO.couponId", target = "couponId"), @Mapping(source = "createReqVO.couponId", target = "couponId"),
@Mapping(target = "remark", ignore = true), @Mapping(target = "remark", ignore = true),
@Mapping(source = "createReqVO.remark", target = "userRemark"), @Mapping(source = "createReqVO.remark", target = "userRemark"),
@ -67,14 +65,10 @@ public interface TradeOrderConvert {
@Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"), @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
@Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"), @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"),
@Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"), @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"),
@Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"), @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"),
}) })
TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address); TradePriceCalculateRespBO calculateRespBO);
TradeOrderRespDTO convert(TradeOrderDO orderDO); TradeOrderRespDTO convert(TradeOrderDO orderDO);
@ -92,23 +86,16 @@ public interface TradeOrderConvert {
TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item); TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);
default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) { default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) {
return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list)); 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) {
default ProductSkuUpdateStockReqDTO convertNegative(List<TradeOrderItemDO> list) { List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
List<ProductSkuUpdateStockReqDTO.Item> items = TradeOrderConvert.INSTANCE.convertList(list); new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
items.forEach(item -> item.setIncrCount(-item.getIncrCount()));
return new ProductSkuUpdateStockReqDTO(items); 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, default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) { TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) {
PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO()
@ -221,8 +208,10 @@ public interface TradeOrderConvert {
default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
List<CartDO> cartList) { List<CartDO> cartList) {
TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO(); TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId)
reqBO.setUserId(userId).setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId()) .setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus())
.setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId())
.setPickUpStoreId(settlementReqVO.getPickUpStoreId())
.setItems(new ArrayList<>(settlementReqVO.getItems().size())); .setItems(new ArrayList<>(settlementReqVO.getItems().size()));
// 商品项的构建 // 商品项的构建
Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
@ -276,19 +265,13 @@ public interface TradeOrderConvert {
TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); 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()) return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
.setBasePrice(item.getPayPrice() * item.getCount()) .setBasePrice(item.getPayPrice() * item.getCount())
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂标题类似木晴冰雪成功购买云时代的JVM原理与实战茫农成功购买深入拆解消息队列47讲 .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName()))
.setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord()); .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); TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
@Mappings({ @Mappings({
@ -300,6 +283,7 @@ public interface TradeOrderConvert {
@Mapping(target = "userId", source = "userId"), @Mapping(target = "userId", source = "userId"),
@Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"), @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.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 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.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -83,11 +82,11 @@ public class BrokerageRecordDO extends BaseDO {
private LocalDateTime unfreezeTime; private LocalDateTime unfreezeTime;
/** /**
* *
* <p> * <p>
* {@link BrokerageUserTypeEnum}广 {@link #userId} 广 * 广 {@link #userId} 广
*/ */
private Integer sourceUserType; private Integer sourceUserLevel;
/** /**
* *
* <p> * <p>

@ -60,4 +60,12 @@ public class BrokerageUserDO extends BaseDO {
*/ */
private Integer frozenPrice; 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()} * {@link DeliveryPickUpStoreDO#getId()}
*/ */
private Long pickUpStoreId; private Long pickUpStoreId;
/**
*
*/
private String pickUpVerifyCode;
// ========== 售后基本信息 ========== // ========== 售后基本信息 ==========
/** /**
@ -251,12 +255,19 @@ public class TradeOrderDO extends BaseDO {
* taobao trade.coupon_fee * taobao trade.coupon_fee
*/ */
private Integer couponPrice; private Integer couponPrice;
// TODO 芋艿:需要记录使用的积分; /**
* 使
*/
private Integer usePoint;
/** /**
* *
* *
* taobao trade.point_fee * taobao trade.point_fee
*/ */
private Integer pointPrice; 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.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; 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.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 cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -24,14 +23,12 @@ import java.util.List;
public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) { default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
!BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
// 分页查询 // 分页查询
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>() return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
.eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
.eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType()) .eqIfPresent(BrokerageRecordDO::getSourceUserLevel, reqVO.getSourceUserLevel())
.betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BrokerageRecordDO::getId)); .orderByDesc(BrokerageRecordDO::getId));
} }
@ -59,4 +56,5 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
@Param("bizType") Integer bizType, @Param("bizType") Integer bizType,
@Param("status") Integer status); @Param("status") Integer status);
} }

@ -1,17 +1,15 @@
package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user; package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
import cn.hutool.core.lang.Assert; 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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 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 com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/** /**
* Mapper * Mapper
@ -21,35 +19,16 @@ import org.apache.ibatis.annotations.Select;
@Mapper @Mapper
public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> { 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>() return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
.eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
.betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
.betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime()) .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)); .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) { default void updateBindUserIdAndBindUserTimeToNull(Long id) {
update(null, new LambdaUpdateWrapper<BrokerageUserDO>() update(null, new LambdaUpdateWrapper<BrokerageUserDO>()
.eq(BrokerageUserDO::getId, id) .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) { default void updateEnabledFalseAndBrokerageTimeToNull(Long id) {
@ -137,11 +117,10 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
.set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
} }
default Long selectCountByBindUserId(Long bindUserId) { default Long selectCountByBindUserIdAndLevelIn(Long bindUserId, List<Integer> levels) {
return selectCount(BrokerageUserDO::getBindUserId, bindUserId); 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.dal.mysql.brokerage.record.BrokerageRecordMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 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.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.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@ -29,6 +28,7 @@ import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Service * Service
@ -74,7 +74,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
} }
// 1.2 计算一级分佣 // 1.2 计算一级分佣
addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(),
bizType, BrokerageUserTypeEnum.FIRST); bizType, 1);
// 2.1 获得二级推广员 // 2.1 获得二级推广员
if (firstUser.getBindUserId() == null) { if (firstUser.getBindUserId() == null) {
@ -86,7 +86,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
} }
// 2.2 计算二级分佣 // 2.2 计算二级分佣
addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(),
bizType, BrokerageUserTypeEnum.SECOND); bizType, 2);
} }
@Override @Override
@ -142,10 +142,10 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
* @param brokerageFrozenDays * @param brokerageFrozenDays
* @param brokeragePercent * @param brokeragePercent
* @param bizType * @param bizType
* @param sourceUserType * @param sourceUserLevel
*/ */
private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays, private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) { Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, Integer sourceUserLevel) {
// 1.1 处理冻结时间 // 1.1 处理冻结时间
LocalDateTime unfreezeTime = null; LocalDateTime unfreezeTime = null;
if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
@ -157,12 +157,12 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
for (BrokerageAddReqBO item : list) { for (BrokerageAddReqBO item : list) {
// 计算金额 // 计算金额
Integer fixedPrice; Integer fixedPrice;
if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) { if (Objects.equals(sourceUserLevel, 1)) {
fixedPrice = item.getFirstFixedPrice(); fixedPrice = item.getFirstFixedPrice();
} else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) { } else if (Objects.equals(sourceUserLevel, 2)) {
fixedPrice = item.getSecondFixedPrice(); fixedPrice = item.getSecondFixedPrice();
} else { } else {
throw new IllegalArgumentException(StrUtil.format("来源用户({}) 不合法", sourceUserType)); throw new IllegalArgumentException(StrUtil.format("用户等级({}) 不合法", sourceUserLevel));
} }
int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice); int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
if (brokeragePrice <= 0) { if (brokeragePrice <= 0) {
@ -172,7 +172,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
// 创建记录实体 // 创建记录实体
records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(), brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(),
item.getSourceUserId(), sourceUserType.getType())); item.getSourceUserId(), sourceUserLevel));
} }
if (CollUtil.isEmpty(records)) { if (CollUtil.isEmpty(records)) {
return; return;

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.trade.service.brokerage.user; package cn.iocoder.yudao.module.trade.service.brokerage.user;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 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.Collection;
import java.util.List; import java.util.List;
@ -91,10 +93,24 @@ public interface BrokerageUserService {
* 广 * 广
* *
* @param bindUserId 广 * @param bindUserId 广
* @param userType * @param level 广
* @return 广 * @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; 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.lang.Assert;
import cn.hutool.core.util.BooleanUtil; 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.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 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.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.dal.mysql.brokerage.user.BrokerageUserMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; 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.BrokerageEnabledConditionEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.*;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -51,7 +50,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
@Override @Override
public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) { public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
return brokerageUserMapper.selectPage(pageReqVO); List<Integer> levels = buildUserQueryLevels(pageReqVO.getBindUserId(), pageReqVO.getLevel());
return brokerageUserMapper.selectPage(pageReqVO, levels);
} }
@Override @Override
@ -66,10 +66,15 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return; return;
} }
// 绑定关系未发生变化
// TODO @疯狂:这个放到“情况一”之前,貌似也没关系?
if (Objects.equals(brokerageUser.getBindUserId(), bindUserId)) {
return;
}
// 情况二:修改推广员 // 情况二:修改推广员
validateCanBindUser(brokerageUser, bindUserId); validateCanBindUser(brokerageUser, bindUserId);
brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(id)));
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
} }
@Override @Override
@ -132,19 +137,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
} }
@Override @Override
public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) { public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) {
switch (userType) { List<Integer> levels = buildUserQueryLevels(bindUserId, level);
case ALL: // TODO @疯狂ALL 是不是不用搞个枚举,默认为空就是不过滤哈~ if (CollUtil.isEmpty(levels)) {
Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId); return 0L;
Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
return firstCount + secondCount;
case FIRST:
return brokerageUserMapper.selectCountByBindUserId(bindUserId);
case SECOND:
return brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
default:
return 0L;
} }
return brokerageUserMapper.selectCountByBindUserIdAndLevelIn(bindUserId, levels);
} }
@Override @Override
@ -171,14 +169,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now()); brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now());
} }
brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()); brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
brokerageUserMapper.insert(brokerageUser); brokerageUserMapper.insert(fillBindUserData(bindUserId, brokerageUser));
} else { } else {
brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(userId)));
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
} }
return true; 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 @Override
public Boolean getUserBrokerageEnabled(Long userId) { public Boolean getUserBrokerageEnabled(Long userId) {
// 全局分销功能是否开启 // 全局分销功能是否开启
@ -231,11 +245,30 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
throw exception(BROKERAGE_BIND_SELF); throw exception(BROKERAGE_BIND_SELF);
} }
// TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈 // 下级不能绑定自己的上级
// A->B->A下级不能绑定自己的上级, A->B->C->A可以!! if (StrUtil.split(bindUser.getPath(), ",").contains(String.valueOf(user.getId()))) {
if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
throw exception(BROKERAGE_BIND_LOOP); 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.collection.CollUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue; 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.address.dto.AddressRespDTO;
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; 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.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.MemberExperienceBizTypeEnum;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 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.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 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.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.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*; 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.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.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
import cn.iocoder.yudao.module.trade.service.cart.CartService; import cn.iocoder.yudao.module.trade.service.cart.CartService;
@ -115,6 +118,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource @Resource
private BargainRecordApi bargainRecordApi; private BargainRecordApi bargainRecordApi;
@Resource @Resource
private MemberUserApi memberUserApi;
@Resource
private MemberLevelApi memberLevelApi; private MemberLevelApi memberLevelApi;
@Resource @Resource
private MemberPointApi memberPointApi; private MemberPointApi memberPointApi;
@ -178,140 +183,127 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 1、执行订单创建前置处理器 // 0. 价格计算
// 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. 价格计算
TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
// 1. 订单创建前的逻辑
beforeCreateTradeOrder(userId, createReqVO, calculateRespBO);
// 2.1 插入 TradeOrderDO 订单 // 2.1 插入 TradeOrderDO 订单
TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO); TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO);
// 2.2 插入 TradeOrderItemDO 订单项 // 2.2 插入 TradeOrderItemDO 订单项
List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO); List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO);
// 3. 订单创建后的逻辑 // 3. 订单创建后的逻辑
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO); afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
return order; return order;
} }
// TODO @puhui999订单超时自动取消 // 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, private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
TradePriceCalculateRespBO calculateRespBO) { TradePriceCalculateRespBO calculateRespBO) {
// 用户选择物流配送的时候才需要填写收货地址 TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO);
AddressRespDTO address = new AddressRespDTO(); order.setType(calculateRespBO.getType());
if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) { order.setNo(orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX));
// 用户收件地址的校验
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);
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
// 支付信息 // 支付 + 退款信息
order.setAdjustPrice(0).setPayStatus(false); order.setAdjustPrice(0).setPayStatus(false);
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
// 物流信息 // 物流信息
order.setDeliveryType(createReqVO.getDeliveryType()); order.setDeliveryType(createReqVO.getDeliveryType());
// 退款信息 if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); 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); tradeOrderMapper.insert(order);
// TODO @puhui999如果是门店订单则需要生成核销码
return order; return order;
} }
private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO,
TradePriceCalculateRespBO calculateRespBO) {
List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO);
tradeOrderItemMapper.insertBatch(orderItems);
return orderItems;
}
/** /**
* *
* *
* @param createReqVO * @param userId
* @return * @param createReqVO
* @param calculateRespBO
*/ */
private Integer validateActivity(AppTradeOrderCreateReqVO createReqVO) { private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
if (createReqVO.getSeckillActivityId() != null) { TradePriceCalculateRespBO calculateRespBO) {
return TradeOrderTypeEnum.SECKILL.getType(); // 1. 执行订单创建前置处理器
} TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
if (createReqVO.getCombinationActivityId() != null) { beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
return TradeOrderTypeEnum.COMBINATION.getType(); beforeOrderCreateReqBO.setUserId(userId);
} beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
// TODO 砍价敬请期待 // TODO @puhui999这里有个纠结点handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler类似可以处理优惠劵等等
return TradeOrderTypeEnum.NORMAL.getType(); tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
}
private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { // 2. 下单时扣减商品库存
List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO); productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
tradeOrderItemMapper.insertBatch(orderItems);
return orderItems;
} }
/** /**
* *
* *
* *
* *
* @param userId * @param userId
* @param createReqVO * @param createReqVO
* @param tradeOrderDO * @param order
* @param calculateRespBO * @param calculateRespBO
*/ */
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, TradeOrderDO order, List<TradeOrderItemDO> orderItems,
TradePriceCalculateRespBO calculateRespBO) { TradePriceCalculateRespBO calculateRespBO) {
// 执行订单创建后置处理器 // 1. 执行订单创建后置处理器
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0)))); // TODO @puhui999从通用性来说应该不用 orderItems.get(0)
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
// 扣减积分 TODO 芋艿:待实现,需要前置; TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
// 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
// 有使用优惠券时更新 TODO 芋艿:需要前置; // 2. 有使用优惠券时更新
// 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
if (createReqVO.getCouponId() != null) { if (createReqVO.getCouponId() != null) {
couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId) couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId)
.setOrderId(tradeOrderDO.getId())); .setOrderId(order.getId()));
} }
// 下单时扣减商品库存 // 3. 扣减积分
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); // 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务
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); Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
if (CollUtil.isNotEmpty(cartIds)) { if (CollUtil.isNotEmpty(cartIds)) {
cartService.deleteCart(userId, cartIds); cartService.deleteCart(userId, cartIds);
} }
// 生成预支付 // 5. 生成预支付
createPayOrder(tradeOrderDO, orderItems, calculateRespBO); createPayOrder(order, orderItems, calculateRespBO);
// 增加订单日志 TODO 芋艿:待实现 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
} }
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) { TradePriceCalculateRespBO calculateRespBO) {
// 创建支付单,用于后续的支付 // 创建支付单,用于后续的支付
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
order, orderItems, calculateRespBO, tradeOrderProperties); order, orderItems, calculateRespBO, tradeOrderProperties);
@ -339,6 +331,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
} }
// 校验活动 // 校验活动
// 1、拼团活动 // 1、拼团活动
// TODO @puhui999这块也抽象到 handler 里
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
// 更新拼团状态 TODO puhui999订单支付失败或订单支付过期删除这条拼团记录 // 更新拼团状态 TODO puhui999订单支付失败或订单支付过期删除这条拼团记录
combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
@ -416,7 +409,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// 1.1 校验并获得交易订单(可发货) // 1.1 校验并获得交易订单(可发货)
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId()); TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
// 1.2 校验 deliveryType 是否为快递,是快递才可以发货 // 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); throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS);
} }
@ -726,7 +719,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
} }
// TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来 // TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来
tradeOrderHandlers.forEach(handler -> handler.rollbackStock()); tradeOrderHandlers.forEach(handler -> handler.rollback());
// 2.回滚库存 // 2.回滚库存
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
@ -736,6 +729,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
couponApi.returnUsedCoupon(order.getCouponId()); couponApi.returnUsedCoupon(order.getCouponId());
// 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择; // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择;
// TODO @疯狂:有赞是可配置(支付 or 确认收货),我们按照支付好列;然后这里的退积分,指的是下单时的积分抵扣。
// TODO 芋艿OrderLog // TODO 芋艿OrderLog
@ -768,22 +762,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Async @Async
protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) { 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)); memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId));
} }
@Async @Async
protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) { 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(); int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType();
memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
} }
@Async @Async
protected void addBrokerageAsync(Long userId, Long orderId) { protected void addBrokerageAsync(Long userId, Long orderId) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
Assert.notNull(user);
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId); List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
List<BrokerageAddReqBO> list = convertList(orderItems, 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); 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
// TODO 芋艿:在想想这些参数的定义 // TODO 芋艿:在想想这些参数的定义
@ -15,6 +14,8 @@ import javax.validation.constraints.NotNull;
@Data @Data
public class TradeBeforeOrderCreateReqBO { public class TradeBeforeOrderCreateReqBO {
// TODO @puhui999注释也写下哈bo 还是写注释噢
@NotNull(message = "订单类型不能为空") @NotNull(message = "订单类型不能为空")
private Integer orderType; private Integer orderType;
@ -34,25 +35,16 @@ public class TradeBeforeOrderCreateReqBO {
@Schema(description = "砍价活动编号", example = "123") @Schema(description = "砍价活动编号", example = "123")
private Long bargainActivityId; private Long bargainActivityId;
@NotNull(message = "购买数量不能为空") @NotNull(message = "SPU 编号不能为空")
private Integer count; private Long spuId;
@NotNull(message = "活动商品不能为空")
private Item item;
@Data @NotNull(message = "SKU 编号活动商品不能为空")
@Valid private Long skuId;
public static class Item {
@NotNull(message = "SPU 编号不能为空") @NotNull(message = "用户编号不能为空")
private Long spuId; private Long userId;
@NotNull(message = "SKU 编号活动商品不能为空") @NotNull(message = "购买数量不能为空")
private Long skuId; private Integer count;
@NotNull(message = "购买数量不能为空")
private Integer count;
}
} }

@ -22,7 +22,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
@Override @Override
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) { public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
// 如果是秒杀订单 // 如果是砍价订单
if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) { if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
return; return;
} }
@ -37,7 +37,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.trade.service.order.handler; package cn.iocoder.yudao.module.trade.service.order.handler;
import cn.hutool.core.util.ObjectUtil; 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.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
@ -20,7 +20,7 @@ import javax.annotation.Resource;
public class TradeCombinationHandler implements TradeOrderHandler { public class TradeCombinationHandler implements TradeOrderHandler {
@Resource @Resource
private CombinationApi combinationApi; private CombinationActivityApi combinationActivityApi;
@Resource @Resource
private CombinationRecordApi combinationRecordApi; 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 @Override
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) { public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
// TODO @puhui999需要判断下
if (true) {
return;
}
// 创建砍价记录 // 创建砍价记录
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO)); combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }

@ -25,8 +25,8 @@ public interface TradeOrderHandler {
void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO); 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.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; 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.enums.order.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO; import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO; import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
return; return;
} }
seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO)); seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
} }
@Override @Override
@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.trade.service.price.bo; 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.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import lombok.Data; import lombok.Data;
import javax.validation.Valid; import javax.validation.Valid;
@ -17,13 +16,6 @@ import java.util.List;
@Data @Data
public class TradePriceCalculateReqBO { public class TradePriceCalculateReqBO {
/**
*
*
* {@link TradeOrderTypeEnum}
*/
private Integer type;
/** /**
* *
* *
@ -37,20 +29,31 @@ public class TradePriceCalculateReqBO {
* CouponDO id * CouponDO id
*/ */
private Long couponId; private Long couponId;
// TODO @疯狂:需要增加一个 PriceCalculator 实现积分扣减的计算;写回到 TradePriceCalculateRespBO 的 usePoint
/**
* 使
*/
@NotNull(message = "是否使用积分不能为空")
private Boolean pointStatus;
/**
*
*
* {@link DeliveryTypeEnum}
*/
private Integer deliveryType;
/** /**
* *
* *
* MemberAddressDO id * MemberAddressDO id
*/ */
private Long addressId; private Long addressId;
/** /**
* *
* *
* {@link DeliveryTypeEnum} * PickUpStoreDO id
*/ */
private Integer deliveryType; private Long pickUpStoreId;
/** /**
* SKU * SKU
@ -58,6 +61,30 @@ public class TradePriceCalculateReqBO {
@NotNull(message = "商品数组不能为空") @NotNull(message = "商品数组不能为空")
private List<Item> items; private List<Item> items;
// ========== 秒杀活动相关字段 ==========
/**
*
*/
private Long seckillActivityId;
// ========== 拼团活动相关字段 ==========
// TODO @puhui999是不是拼团记录的编号哈
/**
*
*/
private Long combinationActivityId;
/**
*
*/
private Long combinationHeadId;
// ========== 砍价活动相关字段 ==========
/**
*
*/
private Long bargainActivityId;
/** /**
* SKU * SKU
*/ */

@ -48,6 +48,11 @@ public class TradePriceCalculateRespBO {
*/ */
private Long couponId; 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.collection.CollUtil;
import cn.hutool.core.lang.Assert; 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.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 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.DeliveryExpressChargeModeEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 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.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.delivery.bo.DeliveryExpressTemplateRespBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 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.*;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND;
/** /**
* {@link TradePriceCalculator} * {@link TradePriceCalculator}
@ -37,20 +39,41 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
@Resource @Resource
private AddressApi addressApi; private AddressApi addressApi;
@Resource
private DeliveryPickUpStoreService deliveryPickUpStoreService;
@Resource @Resource
private DeliveryExpressTemplateService deliveryExpressTemplateService; private DeliveryExpressTemplateService deliveryExpressTemplateService;
@Override @Override
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
// TODO @芋艿:如果门店自提,需要校验是否开启; if (param.getDeliveryType() == null) {
// 1.1 判断配送方式
if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) {
return; return;
} }
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) { if (param.getAddressId() == null) {
throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY); throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
} }
// 1.2 得到收件地址区域
AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
@ -89,8 +112,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
for (OrderItem orderItem : orderItems) { for (OrderItem orderItem : orderItems) {
totalCount += orderItem.getCount(); totalCount += orderItem.getCount();
totalPrice += orderItem.getPayPrice(); totalPrice += orderItem.getPayPrice();
totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount(); if (orderItem.getWeight() != null) {
totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount(); totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount();
}
if (orderItem.getVolume() != null) {
totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount();
}
} }
// 优先判断是否包邮. 如果包邮不计算快递运费 // 优先判断是否包邮. 如果包邮不计算快递运费
if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, 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 * @author
*/ */
public interface TradePriceCalculator { public interface TradePriceCalculator {
@ -13,12 +16,13 @@ public interface TradePriceCalculator {
int ORDER_DISCOUNT_ACTIVITY = 10; int ORDER_DISCOUNT_ACTIVITY = 10;
int ORDER_REWARD_ACTIVITY = 20; int ORDER_REWARD_ACTIVITY = 20;
int ORDER_COUPON = 30; int ORDER_COUPON = 30;
int ORDER_POINT_USE = 40;
/** /**
* *
* *
* TODO * TODO
*/ */
int ORDER_DELIVERY = 40; int ORDER_DELIVERY = 50;
void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); 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.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 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.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.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@ -28,7 +29,7 @@ public class TradePriceCalculatorHelper {
List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
// 创建 PriceCalculateRespDTO 对象 // 创建 PriceCalculateRespDTO 对象
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
result.setType(param.getType()); result.setType(getOrderType(param));
result.setPromotions(new ArrayList<>()); result.setPromotions(new ArrayList<>());
// 创建它的 OrderItem 属性 // 创建它的 OrderItem 属性
@ -69,6 +70,23 @@ public class TradePriceCalculatorHelper {
return result; 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 * price
* *

@ -45,7 +45,7 @@ public class TradePriceServiceImplTest extends BaseMockitoUnitTest {
public void testCalculatePrice() { public void testCalculatePrice() {
// 准备参数 // 准备参数
TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO() TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO()
.setType(TradeOrderTypeEnum.NORMAL.getType()).setUserId(10L) .setUserId(10L)
.setCouponId(20L).setAddressId(30L) .setCouponId(20L).setAddressId(30L)
.setItems(Arrays.asList( .setItems(Arrays.asList(
new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true), new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true),

@ -50,7 +50,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
public void init(){ public void init(){
// 准备参数 // 准备参数
reqBO = new TradePriceCalculateReqBO() reqBO = new TradePriceCalculateReqBO()
.setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode()) .setDeliveryType(DeliveryTypeEnum.EXPRESS.getType())
.setAddressId(10L) .setAddressId(10L)
.setUserId(1L) .setUserId(1L)
.setItems(asList( .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_after_sale_log;
DELETE FROM trade_brokerage_user; DELETE FROM trade_brokerage_user;
DELETE FROM trade_brokerage_record; 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, "deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0', "tenant_id" bigint not null default '0',
PRIMARY KEY ("id") 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> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId> <artifactId>yudao-common</artifactId>
</dependency> </dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
</project> </project>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save