code review:订单分佣

This commit is contained in:
YunaiV 2023-09-08 00:29:25 +08:00
parent b8a4d8cab2
commit 5808f77ade
26 changed files with 108 additions and 53 deletions

View File

@ -27,7 +27,7 @@
<mybatis-plus.version>3.5.3.2</mybatis-plus.version> <mybatis-plus.version>3.5.3.2</mybatis-plus.version>
<mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version> <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version>
<dynamic-datasource.version>3.6.1</dynamic-datasource.version> <dynamic-datasource.version>3.6.1</dynamic-datasource.version>
<mybatis-plus-join-boot-starter.version>1.4.5</mybatis-plus-join-boot-starter.version> <mybatis-plus-join.version>1.4.6</mybatis-plus-join.version>
<redisson.version>3.18.0</redisson.version> <redisson.version>3.18.0</redisson.version>
<dm8.jdbc.version>8.1.2.141</dm8.jdbc.version> <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version>
<!-- 服务保障相关 --> <!-- 服务保障相关 -->
@ -220,7 +220,7 @@
<dependency> <dependency>
<groupId>com.github.yulichang</groupId> <groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
<version>${mybatis-plus-join-boot-starter.version}</version> <version>${mybatis-plus-join.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.Db; import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.Collection; import java.util.Collection;
@ -18,8 +19,11 @@ import java.util.List;
/** /**
* MyBatis Plus BaseMapper 的基础上拓展提供更多的能力 * MyBatis Plus BaseMapper 的基础上拓展提供更多的能力
*
* 1. {@link BaseMapper} MyBatis Plus 的基础接口提供基础的 CRUD 能力
* 2. {@link MPJBaseMapper} MyBatis Plus Join 的基础接口提供连表 Join 能力
*/ */
public interface BaseMapperX<T> extends BaseMapper<T> { public interface BaseMapperX<T> extends MPJBaseMapper<T> {
default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) { default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
// MyBatis Plus 查询 // MyBatis Plus 查询

View File

@ -60,6 +60,7 @@ public class ProductSkuRespDTO {
*/ */
private Double volume; private Double volume;
// TODO @puhui 2 字段需要改下firstBrokerageRecordsecondBrokerageRecord和分佣保持一致
/** /**
* 一级分销的佣金单位 * 一级分销的佣金单位
*/ */

View File

@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/ */
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
// ========== Order 模块 1011000000 ========== // ========== Order 模块 1011000000 ==========
ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在"); ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在");
ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖"); ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖");
ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足"); ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足");
@ -35,7 +35,7 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递"); ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态"); ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
// ========== After Sale 模块 1011000100 ========== // ========== After Sale 模块 1011000100 ==========
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1011000101, "申请退款金额错误"); ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1011000101, "申请退款金额错误");
ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1011000102, "订单已关闭,无法申请售后"); ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1011000102, "订单已关闭,无法申请售后");
@ -50,7 +50,7 @@ public interface ErrorCodeConstants {
ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY = ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY =
new ErrorCode(1011000111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】"); new ErrorCode(1011000111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】");
// ========== Cart 模块 1011002000 ========== // ========== Cart 模块 1011002000 ==========
ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在");
// ========== Price 相关 1011003000 ============ // ========== Price 相关 1011003000 ============
@ -58,7 +58,7 @@ public interface ErrorCodeConstants {
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空"); ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_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, "计算快递运费异常,找不到对应的运费模板");
// ========== 物流 Express 模块 1011004000 ========== // ========== 物流 Express 模块 1011004000 ==========
ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在"); ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在");
ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011004001, "已经存在该编码的快递公司"); ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011004001, "已经存在该编码的快递公司");
ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1011004002, "需要接入快递服务商比如【快递100】"); ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1011004002, "需要接入快递服务商比如【快递100】");
@ -67,15 +67,15 @@ public interface ErrorCodeConstants {
ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011004101, "快递查询接口异常"); ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011004101, "快递查询接口异常");
ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011004102, "快递查询返回失败,原因:{}"); ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011004102, "快递查询返回失败,原因:{}");
// ========== 物流 Template 模块 1011005000 ========== // ========== 物流 Template 模块 1011005000 ==========
ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011005000, "已经存在该运费模板名"); ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011005000, "已经存在该运费模板名");
ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011005001, "运费模板不存在"); ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011005001, "运费模板不存在");
// ========== 物流 PICK_UP 模块 1011006000 ========== // ========== 物流 PICK_UP 模块 1011006000 ==========
ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011006000, "自提门店不存在"); ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011006000, "自提门店不存在");
// ========== 分销 分销用户 模块 1011007000 ========== // ========== 分销用户 模块 1011007000 ==========
ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在"); ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在");
} }

View File

@ -15,6 +15,7 @@ import java.util.Arrays;
@Getter @Getter
public enum BrokerageBindModeEnum implements IntArrayValuable { public enum BrokerageBindModeEnum implements IntArrayValuable {
// TODO @疯狂要不从 1 开始
/** /**
* 只要用户没有推广人随时都可以绑定分销关系 * 只要用户没有推广人随时都可以绑定分销关系
*/ */
@ -23,6 +24,7 @@ public enum BrokerageBindModeEnum implements IntArrayValuable {
* 仅新用户注册时才能绑定推广关系 * 仅新用户注册时才能绑定推广关系
*/ */
REGISTER(1, "新用户"), REGISTER(1, "新用户"),
// TODO @疯狂要加个 2每次扫码都覆盖
; ;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray();

View File

@ -15,6 +15,7 @@ import java.util.Arrays;
@Getter @Getter
public enum BrokerageEnabledConditionEnum implements IntArrayValuable { public enum BrokerageEnabledConditionEnum implements IntArrayValuable {
// TODO @疯狂这个也从 1 开始哇
/** /**
* 所有用户都可以分销 * 所有用户都可以分销
*/ */

View File

@ -15,6 +15,7 @@ import java.util.Arrays;
@Getter @Getter
public enum BrokerageRecordBizTypeEnum implements IntArrayValuable { public enum BrokerageRecordBizTypeEnum implements IntArrayValuable {
// TODO @疯狂这个也从 1 开始哇
ORDER(0, "获得推广佣金", "获得推广佣金 {}", true), ORDER(0, "获得推广佣金", "获得推广佣金 {}", true),
WITHDRAW(1, "提现申请", "提现申请扣除佣金 {}", false), WITHDRAW(1, "提现申请", "提现申请扣除佣金 {}", false),
; ;

View File

@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -21,7 +22,7 @@ public class TradeBrokerageRecordBaseVO {
private Long userId; private Long userId;
@Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353") @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353")
@NotNull(message = "业务编号不能为空") @NotEmpty(message = "业务编号不能为空")
private String bizId; private String bizId;
@Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ -29,7 +30,7 @@ public class TradeBrokerageRecordBaseVO {
private Integer bizType; private Integer bizType;
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "标题不能为空") @NotEmpty(message = "标题不能为空")
private String title; private String title;
@Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731") @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731")

View File

@ -15,6 +15,8 @@ public class TradeBrokerageUserUpdateBrokerageEnabledReqVO {
@NotNull(message = "用户编号不能为空") @NotNull(message = "用户编号不能为空")
private Long id; private Long id;
// TODO @疯狂是不是这个字段可以改成 enabled
@Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "推广资格不能为空") @NotNull(message = "推广资格不能为空")
private Boolean brokerageEnabled; private Boolean brokerageEnabled;

View File

@ -54,6 +54,7 @@ public class TradeConfigBaseVO {
@PositiveOrZero(message = "用户提现最低金额不能是负数") @PositiveOrZero(message = "用户提现最低金额不能是负数")
private Integer brokerageWithdrawMinPrice; private Integer brokerageWithdrawMinPrice;
// TODO @疯狂要不要做成字典按道理都可以体现对哇感觉是全局的配置哈
@Schema(description = "提现银行", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") @Schema(description = "提现银行", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
@NotEmpty(message = "提现银行不能为空") @NotEmpty(message = "提现银行不能为空")
private List<Integer> brokerageBankNames; private List<Integer> brokerageBankNames;

View File

@ -40,7 +40,7 @@ public interface TradeBrokerageRecordConvert {
.setBizId(bizId) .setBizId(bizId)
.setPrice(brokerage) .setPrice(brokerage)
.setTotalPrice(user.getBrokeragePrice()) .setTotalPrice(user.getBrokeragePrice())
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂可能 title 不是很固化会存在类似沐晴成功购买XXX JVM 实战
.setDescription(StrUtil.format(BrokerageRecordBizTypeEnum.ORDER.getDescription(), String.valueOf(brokerage / 100.0))) .setDescription(StrUtil.format(BrokerageRecordBizTypeEnum.ORDER.getDescription(), String.valueOf(brokerage / 100.0)))
.setStatus(status) .setStatus(status)
.setFrozenDays(brokerageFrozenDays) .setFrozenDays(brokerageFrozenDays)

View File

@ -41,13 +41,19 @@ public class TradeBrokerageRecordDO extends BaseDO {
/** /**
* 业务类型 * 业务类型
* <p> * <p>
* 枚举 {@link BrokerageRecordBizTypeEnum 对应的类} * 枚举 {@link BrokerageRecordBizTypeEnum}
*/ */
private Integer bizType; private Integer bizType;
/** /**
* 标题 * 标题
*/ */
private String title; private String title;
/**
* 说明
*/
private String description;
/** /**
* 金额 * 金额
*/ */
@ -56,16 +62,14 @@ public class TradeBrokerageRecordDO extends BaseDO {
* 当前总佣金 * 当前总佣金
*/ */
private Integer totalPrice; private Integer totalPrice;
/**
* 说明
*/
private String description;
/** /**
* 状态 * 状态
* <p> * <p>
* 枚举 {@link BrokerageRecordStatusEnum 对应的类} * 枚举 {@link BrokerageRecordStatusEnum}
*/ */
private Integer status; private Integer status;
/** /**
* 冻结时间 * 冻结时间
*/ */

View File

@ -8,6 +8,7 @@ import lombok.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
// TODO @疯狂因为独立了表是不是可以把字段的 brokerage 去掉了哈
/** /**
* 分销用户 DO * 分销用户 DO
* *
@ -28,14 +29,19 @@ public class TradeBrokerageUserDO extends BaseDO {
*/ */
@TableId @TableId
private Long id; private Long id;
// TODO @疯狂貌似改成 bindUserId更明确
/** /**
* 推广员编号 * 推广员编号
*
* 关联 MemberUserDO id 字段
*/ */
private Long brokerageUserId; private Long brokerageUserId;
/** /**
* 推广员绑定时间 * 推广员绑定时间
*/ */
private LocalDateTime brokerageBindTime; private LocalDateTime brokerageBindTime;
/** /**
* 推广资格 * 推广资格
*/ */
@ -44,6 +50,7 @@ public class TradeBrokerageUserDO extends BaseDO {
* 成为分销员时间 * 成为分销员时间
*/ */
private LocalDateTime brokerageTime; private LocalDateTime brokerageTime;
/** /**
* 可用佣金 * 可用佣金
*/ */

View File

@ -40,8 +40,10 @@ public interface TradeBrokerageRecordMapper extends BaseMapperX<TradeBrokerageRe
.eq(TradeBrokerageRecordDO::getStatus, status)); .eq(TradeBrokerageRecordDO::getStatus, status));
} }
// TODO @疯狂userId???
default TradeBrokerageRecordDO selectByUserIdAndBizTypeAndBizId(Integer bizType, String bizId) { default TradeBrokerageRecordDO selectByUserIdAndBizTypeAndBizId(Integer bizType, String bizId) {
return selectOne(TradeBrokerageRecordDO::getBizType, bizType, return selectOne(TradeBrokerageRecordDO::getBizType, bizType,
TradeBrokerageRecordDO::getBizId, bizId); TradeBrokerageRecordDO::getBizId, bizId);
} }
} }

View File

@ -0,0 +1,4 @@
/**
* 占位文件无特殊用途
*/
package cn.iocoder.yudao.module.trade.job;

View File

@ -30,6 +30,7 @@ public interface TradeBrokerageRecordService {
*/ */
PageResult<TradeBrokerageRecordDO> getBrokerageRecordPage(TradeBrokerageRecordPageReqVO pageReqVO); PageResult<TradeBrokerageRecordDO> getBrokerageRecordPage(TradeBrokerageRecordPageReqVO pageReqVO);
// TODO @疯狂是不是 bizType 得加下方便未来拓展哈
/** /**
* 增加佣金 * 增加佣金
* *
@ -38,8 +39,10 @@ public interface TradeBrokerageRecordService {
*/ */
void addBrokerage(Long userId, List<BrokerageAddReqBO> list); void addBrokerage(Long userId, List<BrokerageAddReqBO> list);
// TODO @疯狂是不是 bizType 得加下方便未来拓展哈
/** /**
* 取消佣金将佣金记录状态修改为已失效 * 取消佣金将佣金记录状态修改为已失效
*
* @param userId 会员编号 * @param userId 会员编号
* @param bizId 业务编号 * @param bizId 业务编号
*/ */
@ -51,4 +54,5 @@ public interface TradeBrokerageRecordService {
* @return 解冻佣金的数量 * @return 解冻佣金的数量
*/ */
int unfreezeRecord(); int unfreezeRecord();
} }

View File

@ -6,15 +6,15 @@ import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
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.record.vo.TradeBrokerageRecordPageReqVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.record.TradeBrokerageRecordConvert; import cn.iocoder.yudao.module.trade.convert.brokerage.record.TradeBrokerageRecordConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
import cn.iocoder.yudao.module.trade.service.brokerage.record.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.TradeBrokerageRecordMapper; import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.TradeBrokerageRecordMapper;
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.service.brokerage.record.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.user.TradeBrokerageUserService; import cn.iocoder.yudao.module.trade.service.brokerage.user.TradeBrokerageUserService;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -56,11 +56,13 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
return tradeBrokerageRecordMapper.selectPage(pageReqVO); return tradeBrokerageRecordMapper.selectPage(pageReqVO);
} }
// TODO @疯狂buyerId 要不要统一改成 userId
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void addBrokerage(Long buyerId, List<BrokerageAddReqBO> list) { public void addBrokerage(Long buyerId, List<BrokerageAddReqBO> list) {
TradeConfigDO memberConfig = tradeConfigService.getTradeConfig(); TradeConfigDO memberConfig = tradeConfigService.getTradeConfig();
// 0 未启用分销功能 // 0 未启用分销功能
// TODO @疯狂BooleanUtil.isFalse()逻辑里尽量不做 !取反这样要多思考一层
if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) { if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) {
log.warn("[addBrokerage][增加佣金失败brokerageEnabled 未配置buyerId({})", buyerId); log.warn("[addBrokerage][增加佣金失败brokerageEnabled 未配置buyerId({})", buyerId);
return; return;
@ -72,11 +74,11 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
return; return;
} }
// 1.2 计算一级分佣 // 1.2 计算一级分佣 // TODO 疯狂类似 1.1 1.2 的空行可以去掉一般在代码里的空行是为了逻辑分块但是分块如果太多就会导致代码里都是空行哈
addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getSkuFirstBrokeragePrice); addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getSkuFirstBrokeragePrice);
// 2.1 获得二级推广员 // 2.1 获得二级推广员
// TODO @疯狂这里可以加个 firstUser.getBrokerageUserId() 为空的判断 return
TradeBrokerageUserDO secondUser = tradeBrokerageUserService.getBrokerageUser(firstUser.getBrokerageUserId()); TradeBrokerageUserDO secondUser = tradeBrokerageUserService.getBrokerageUser(firstUser.getBrokerageUserId());
if (secondUser == null || !BooleanUtil.isTrue(secondUser.getBrokerageEnabled())) { if (secondUser == null || !BooleanUtil.isTrue(secondUser.getBrokerageEnabled())) {
return; return;
@ -95,6 +97,7 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
return; return;
} }
// 1. 更新佣金记录为已失效
TradeBrokerageRecordDO updateObj = new TradeBrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus()); TradeBrokerageRecordDO updateObj = new TradeBrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus());
int updateRows = tradeBrokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); int updateRows = tradeBrokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
if (updateRows == 0) { if (updateRows == 0) {
@ -102,6 +105,7 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
return; return;
} }
// 2. 更新用户的佣金
if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) { if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) {
tradeBrokerageUserService.updateUserFrozenBrokeragePrice(userId, -record.getPrice()); tradeBrokerageUserService.updateUserFrozenBrokeragePrice(userId, -record.getPrice());
} else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) { } else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) {
@ -109,6 +113,7 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
} }
} }
// TODO @疯狂是不是 calculateBrokeragePrice
/** /**
* 计算佣金 * 计算佣金
* *
@ -122,12 +127,11 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
if (skuBrokeragePrice != null && skuBrokeragePrice > 0) { if (skuBrokeragePrice != null && skuBrokeragePrice > 0) {
return ObjectUtil.defaultIfNull(skuBrokeragePrice, 0); return ObjectUtil.defaultIfNull(skuBrokeragePrice, 0);
} }
// 2. 根据订单支付金额计算佣金 // 2. 根据订单支付金额计算佣金
// TODO @疯狂要不要把 MoneyUtils 抽到 common 然后这里也使用这个类的方法
if (payPrice != null && payPrice > 0 && percent != null && percent > 0) { if (payPrice != null && payPrice > 0 && percent != null && percent > 0) {
return NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue(); return NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue();
} }
return 0; return 0;
} }
@ -142,37 +146,35 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
*/ */
private void addBrokerage(TradeBrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays, private void addBrokerage(TradeBrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> skuBrokeragePriceFun) { Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> skuBrokeragePriceFun) {
// 处理冻结时间 // 1.1 处理冻结时间
// TODO @疯狂是不是 brokerageFrozenDays != null && brokerageFrozenDays > 0 然后计算更简洁一点
brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
LocalDateTime unfreezeTime = null; LocalDateTime unfreezeTime = null;
if (brokerageFrozenDays > 0) { if (brokerageFrozenDays > 0) {
unfreezeTime = LocalDateTime.now().plusDays(brokerageFrozenDays); unfreezeTime = LocalDateTime.now().plusDays(brokerageFrozenDays);
} }
// 1.2 计算分佣
// 计算分佣
int totalBrokerage = 0; int totalBrokerage = 0;
List<TradeBrokerageRecordDO> records = new ArrayList<>(); List<TradeBrokerageRecordDO> records = new ArrayList<>();
for (BrokerageAddReqBO dto : list) { for (BrokerageAddReqBO item : list) {
int brokeragePerItem = calculateBrokerage(dto.getPayPrice(), brokeragePercent, skuBrokeragePriceFun.apply(dto)); int brokeragePerItem = calculateBrokerage(item.getPayPrice(), brokeragePercent, skuBrokeragePriceFun.apply(item));
// TODO @疯狂其实可以 brokeragePerItem <= 0 continue这样 { 层级更少代码更简洁}
if (brokeragePerItem > 0) { if (brokeragePerItem > 0) {
int brokerage = brokeragePerItem * dto.getCount(); int brokerage = brokeragePerItem * item.getCount();
records.add(TradeBrokerageRecordConvert.INSTANCE.convert(user, dto.getBizId(), brokerageFrozenDays, brokerage, unfreezeTime)); records.add(TradeBrokerageRecordConvert.INSTANCE.convert(user, item.getBizId(), brokerageFrozenDays, brokerage, unfreezeTime));
totalBrokerage += brokerage; totalBrokerage += brokerage;
} }
} }
if (CollUtil.isEmpty(records)) {
if (records.isEmpty()) {
return; return;
} }
// 1.3 保存佣金记录
// 保存佣金记录
tradeBrokerageRecordMapper.insertBatch(records); tradeBrokerageRecordMapper.insertBatch(records);
if (brokerageFrozenDays > 0) { // 2. 更新用户佣金
// 更新用户冻结佣金 if (brokerageFrozenDays > 0) { // 更新用户冻结佣金
tradeBrokerageUserService.updateUserFrozenBrokeragePrice(user.getId(), totalBrokerage); tradeBrokerageUserService.updateUserFrozenBrokeragePrice(user.getId(), totalBrokerage);
} else { } else { // 更新用户可用佣金
// 更新用户可用佣金
tradeBrokerageUserService.updateUserBrokeragePrice(user.getId(), totalBrokerage); tradeBrokerageUserService.updateUserBrokeragePrice(user.getId(), totalBrokerage);
} }
} }
@ -190,8 +192,8 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
int count = 0; int count = 0;
for (TradeBrokerageRecordDO record : records) { for (TradeBrokerageRecordDO record : records) {
try { try {
boolean successful = getSelf().unfreezeRecord(record); boolean success = getSelf().unfreezeRecord(record);
if (successful) { if (success) {
count++; count++;
} }
} catch (Exception e) { } catch (Exception e) {
@ -215,7 +217,6 @@ public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordServ
// 更新用户冻结佣金 // 更新用户冻结佣金
tradeBrokerageUserService.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(record.getUserId(), -record.getPrice()); tradeBrokerageUserService.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(record.getUserId(), -record.getPrice());
log.info("[unfreezeRecord][record({}) 更新为已结算成功]", record.getId()); log.info("[unfreezeRecord][record({}) 更新为已结算成功]", record.getId());
return true; return true;
} }

View File

@ -4,22 +4,29 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
// TODO @疯狂要不要 service 还是拍平就是都放在 brokerage 包下然后 bo 里面稍微分分
/** /**
* 佣金 增加 Request BO * 佣金 增加 Request BO
*
* @author owen * @author owen
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class BrokerageAddReqBO { public class BrokerageAddReqBO {
// TODO @疯狂bo 的话也可以考虑加下 @Validated 注解校验下参数防御性下哈虽然不一定用的到
/** /**
* 业务ID * 业务ID
*/ */
private String bizId; private String bizId;
// TODO @疯狂不需要 payPrice count计算成 price 就好啦
/** /**
* 商品支付价格 * 商品支付价格
*/ */
private Integer payPrice; private Integer payPrice;
// TODO @疯狂可以去掉 sku 更抽象一点
/** /**
* SKU 一级佣金 * SKU 一级佣金
*/ */
@ -32,4 +39,5 @@ public class BrokerageAddReqBO {
* 购买数量 * 购买数量
*/ */
private Integer count; private Integer count;
} }

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerag
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
// TODO @疯狂要不去掉 Trade 前缀哈交易这块我准备除了 tradeorder 保持下类似 aftersale都要取消前缀了tradeorder 保持的原因是避免 payorder 和它重复
/** /**
* 分销用户 Service 接口 * 分销用户 Service 接口
* *
@ -70,6 +71,7 @@ public interface TradeBrokerageUserService {
*/ */
void updateUserBrokeragePrice(Long id, int brokeragePrice); void updateUserBrokeragePrice(Long id, int brokeragePrice);
// TODO @疯狂int 类型一般不用哈尽量都用封装类型不差这点内存哈
/** /**
* 更新用户冻结佣金 * 更新用户冻结佣金
* *
@ -85,4 +87,5 @@ public interface TradeBrokerageUserService {
* @param frozenBrokeragePrice 减少冻结佣金负数 * @param frozenBrokeragePrice 减少冻结佣金负数
*/ */
void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice); void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice);
} }

View File

@ -30,12 +30,6 @@ public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService
@Resource @Resource
private TradeBrokerageUserMapper brokerageUserMapper; private TradeBrokerageUserMapper brokerageUserMapper;
private void validateBrokerageUserExists(Long id) {
if (brokerageUserMapper.selectById(id) == null) {
throw exception(BROKERAGE_USER_NOT_EXISTS);
}
}
@Override @Override
public TradeBrokerageUserDO getBrokerageUser(Long id) { public TradeBrokerageUserDO getBrokerageUser(Long id) {
return brokerageUserMapper.selectById(id); return brokerageUserMapper.selectById(id);
@ -55,15 +49,23 @@ public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService
public void updateBrokerageUserId(Long id, Long brokerageUserId) { public void updateBrokerageUserId(Long id, Long brokerageUserId) {
// 校验存在 // 校验存在
validateBrokerageUserExists(id); validateBrokerageUserExists(id);
// TODO @疯狂貌似没实现完
} }
@Override @Override
public void updateBrokerageEnabled(Long id, Boolean brokerageEnabled) { public void updateBrokerageEnabled(Long id, Boolean brokerageEnabled) {
// 校验存在 // 校验存在
validateBrokerageUserExists(id); validateBrokerageUserExists(id);
// TODO @疯狂貌似没实现完
} }
private void validateBrokerageUserExists(Long id) {
if (brokerageUserMapper.selectById(id) == null) {
throw exception(BROKERAGE_USER_NOT_EXISTS);
}
}
// TODO @疯狂getBindBrokerageUser 会不会好点因为统一使用 Bind 替代了 Invite
@Override @Override
public TradeBrokerageUserDO getInviteBrokerageUser(Long id) { public TradeBrokerageUserDO getInviteBrokerageUser(Long id) {
return Optional.ofNullable(id) return Optional.ofNullable(id)
@ -73,6 +75,7 @@ public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService
.orElse(null); .orElse(null);
} }
// TODO @疯狂单个更新不用事务哈
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateUserBrokeragePrice(Long id, int brokeragePrice) { public void updateUserBrokeragePrice(Long id, int brokeragePrice) {
@ -83,6 +86,7 @@ public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService
} }
} }
// TODO @疯狂单个更新不用事务哈
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateUserFrozenBrokeragePrice(Long id, int frozenBrokeragePrice) { public void updateUserFrozenBrokeragePrice(Long id, int frozenBrokeragePrice) {
@ -93,12 +97,14 @@ public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService
} }
} }
// TODO @疯狂单个更新不用事务哈
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice) { public void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice) {
Assert.isTrue(frozenBrokeragePrice < 0); Assert.isTrue(frozenBrokeragePrice < 0);
int updateRows = brokerageUserMapper.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(id, frozenBrokeragePrice); int updateRows = brokerageUserMapper.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(id, frozenBrokeragePrice);
if (updateRows == 0) { if (updateRows == 0) {
// TODO @疯狂挪到 trade 这变的错误码哈
throw exception(MEMBER_FROZEN_BROKERAGE_PRICE_NOT_ENOUGH); throw exception(MEMBER_FROZEN_BROKERAGE_PRICE_NOT_ENOUGH);
} }
} }

View File

@ -12,7 +12,6 @@ import javax.validation.Valid;
*/ */
public interface TradeConfigService { public interface TradeConfigService {
/** /**
* 更新交易中心配置 * 更新交易中心配置
* *

View File

@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomIntege
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO @芋艿单测后续看看
/** /**
* {@link TradeBrokerageRecordServiceImpl} 的单元测试类 * {@link TradeBrokerageRecordServiceImpl} 的单元测试类
* *

View File

@ -17,6 +17,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO @芋艿单测后续看看
/** /**
* {@link TradeBrokerageUserServiceImpl} 的单元测试类 * {@link TradeBrokerageUserServiceImpl} 的单元测试类
* *

View File

@ -9,7 +9,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/ */
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
// ========== 用户相关 1004001000============ // ========== 用户相关 1004001000============
ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户"); ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户");
ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用"); ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用");

View File

@ -136,6 +136,7 @@ public class MemberUserDO extends TenantBaseDO {
*/ */
private Long groupId; private Long groupId;
// TODO @疯狂看看要不要删除掉哈
// ========== 分销相关 ========== // ========== 分销相关 ==========
/** /**

View File

@ -61,4 +61,5 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
return selectCount(new LambdaQueryWrapperX<MemberUserDO>() return selectCount(new LambdaQueryWrapperX<MemberUserDO>()
.apply("FIND_IN_SET({0}, tag_ids)", tagId)); .apply("FIND_IN_SET({0}, tag_ids)", tagId));
} }
} }