code review:分销逻辑

This commit is contained in:
YunaiV 2023-09-09 09:41:57 +08:00
parent 3b5215db21
commit 557b09a157
16 changed files with 68 additions and 76 deletions

View File

@ -20,6 +20,7 @@ public class BrokerageApiImpl implements BrokerageApi {
@Resource
private BrokerageUserService brokerageUserService;
@Override
public BrokerageUserDTO getBrokerageUser(Long userId) {
return BrokerageUserConvert.INSTANCE.convertDTO(brokerageUserService.getBrokerageUser(userId));
}

View File

@ -62,7 +62,7 @@ public class BrokerageUserController {
@Operation(summary = "修改推广资格")
@PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')")
public CommonResult<Boolean> updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) {
brokerageUserService.updateBrokerageEnabled(updateReqVO.getId(), updateReqVO.getEnabled());
brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled());
return success(true);
}
@ -89,12 +89,12 @@ public class BrokerageUserController {
// 合计分佣订单
Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap = convertMap(userIds,
userId -> userId,
userId -> brokerageRecordService.summaryByUserIdAndBizTypeAndStatus(userId,
userId -> brokerageRecordService.getUserBrokerageSummaryByUserId(userId,
BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()));
// 合计推广用户数量
Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
userId -> userId,
userId -> brokerageUserService.getCountByBindUserId(userId));
userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId));
// todo 合计提现

View File

@ -23,21 +23,18 @@ public class AppBrokerageWithdrawCreateReqVO {
@Min(value = 1, message = "提现金额不能小于 1")
private Integer price;
// ========== 银行卡微信支付宝 提现相关字段 ==========
@Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789")
@NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class})
private String accountNo;
// ========== 微信支付宝 提现相关字段 ==========
@Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png")
@URL(message = "收款码的图片,必须是一个 URL")
private String accountQrCodeUrl;
// ========== 银行卡 提现相关字段 ==========
@Schema(description = "持卡人姓名", example = "张三")

View File

@ -30,25 +30,21 @@ public interface BrokerageRecordConvert {
PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page);
// TODO @疯狂可能 title 不是很固化会存在类似沐晴成功购买XXX JVM 实战
default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
Integer brokerageFrozenDays, int brokerage, LocalDateTime unfreezeTime,
Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
String title) {
brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
// 不冻结时佣金直接就是结算状态
Integer status = brokerageFrozenDays > 0
? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus()
: BrokerageRecordStatusEnum.SETTLEMENT.getStatus();
return new BrokerageRecordDO()
.setUserId(user.getId())
.setBizType(bizType.getType())
.setBizId(bizId)
.setPrice(brokerage)
.setTotalPrice(user.getPrice())
return new BrokerageRecordDO().setUserId(user.getId())
.setBizType(bizType.getType()).setBizId(bizId)
.setPrice(brokeragePrice).setTotalPrice(user.getPrice())
.setTitle(title)
.setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokerage / 100.0)))
.setStatus(status)
.setFrozenDays(brokerageFrozenDays)
.setUnfreezeTime(unfreezeTime);
.setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokeragePrice / 100.0)))
.setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime);
}
}

View File

@ -37,24 +37,16 @@ public interface BrokerageUserConvert {
PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
for (BrokerageUserRespVO vo : result.getList()) {
// 用户信息
Optional.ofNullable(userMap.get(vo.getId()))
.ifPresent(user -> {
vo.setNickname(user.getNickname());
vo.setAvatar(user.getAvatar());
});
Optional.ofNullable(userMap.get(vo.getId())).ifPresent(
user -> vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
// 推广用户数量一级
vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0));
// 推广订单数量推广订单金额
Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));
// 推广订单数量
vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0));
// 推广订单金额
vo.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
// todo 已提现次数
vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
// todo 已提现次数已提现金额
vo.setWithdrawCount(0);
// todo 已提现金额
vo.setWithdrawPrice(0);
}
return result;

View File

@ -48,6 +48,7 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
BrokerageRecordDO::getBizId, bizId);
}
// TODO @疯狂mysql 关键字大写哈这样看起来清晰点例如说 SELECT COUNT(1)
@Select("select count(1), sum(price) from trade_brokerage_record where user_id = #{userId} and biz_type = #{bizType} and status = #{status}")
UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
@Param("bizType") Integer bizType,

View File

@ -111,4 +111,5 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
.eq(BrokerageUserDO::getId, id)
.set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
}
}

View File

@ -5,6 +5,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 佣金 增加 Request BO
@ -24,6 +25,7 @@ public class BrokerageAddReqBO {
/**
* 佣金基数
*/
@NotNull(message = "佣金基数不能为空")
private Integer basePrice;
/**
* 一级佣金固定

View File

@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class UserBrokerageSummaryBO {
/**
* 佣金数量
*/
@ -21,4 +22,5 @@ public class UserBrokerageSummaryBO {
* 佣金总额
*/
private Integer price;
}

View File

@ -66,5 +66,5 @@ public interface BrokerageRecordService {
* @param status 佣金状态
* @return 用户佣金汇总
*/
UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status);
UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status);
}

View File

@ -89,6 +89,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
@Override
@Transactional(rollbackFor = Exception.class)
public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) {
// TODO @疯狂userId 加进去查询会不会更好一点万一穿错参数
BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId);
if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) {
log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
@ -138,7 +139,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
* @param list 佣金增加参数列表
* @param brokerageFrozenDays 冻结天数
* @param brokeragePercent 佣金比例
* @param fixedPriceFun 固定佣金
* @param fixedPriceFun 固定佣金 // TODO 疯狂这里是不是可以直接传递 fixedPrice
* @param bizType 业务类型
*/
private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
@ -200,9 +201,9 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
}
@Override
public UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status) {
public UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status) {
UserBrokerageSummaryBO summaryBO = brokerageRecordMapper.selectCountAndSumPriceByUserIdAndBizTypeAndStatus(userId, bizType, status);
return summaryBO == null ? new UserBrokerageSummaryBO(0, 0) : summaryBO;
return summaryBO != null ? summaryBO : new UserBrokerageSummaryBO(0, 0);
}
@Transactional(rollbackFor = Exception.class)

View File

@ -52,7 +52,7 @@ public interface BrokerageUserService {
* @param id 用户编号
* @param enabled 推广资格
*/
void updateBrokerageEnabled(Long id, Boolean enabled);
void updateBrokerageUserEnabled(Long id, Boolean enabled);
/**
* 获得用户的推广人
@ -79,20 +79,21 @@ public interface BrokerageUserService {
void updateUserFrozenPrice(Long id, Integer frozenPrice);
/**
* 更新用户冻结佣金减少, 更新用户佣金增加
* 更新用户冻结佣金减少更新用户佣金增加
*
* @param id 用户编号
* @param frozenPrice 减少冻结佣金负数
*/
void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice);
// TODO @疯狂这个后面可能要支持下二级
/**
* 获得推广用户数量一级
*
* @param bindUserId 绑定的推广员编号
* @return 推广用户数量
*/
Long getCountByBindUserId(Long bindUserId);
Long getBrokerageUserCountByBindUserId(Long bindUserId);
/**
* 会员绑定推广员
@ -103,4 +104,5 @@ public interface BrokerageUserService {
* @return 是否绑定
*/
boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser);
}

View File

@ -57,18 +57,22 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
public void updateBrokerageUserId(Long id, Long bindUserId) {
// 校验存在
validateBrokerageUserExists(id);
// 情况一清除推广员
if (bindUserId == null) {
// 清除推广员
brokerageUserMapper.updateBindUserIdAndBindUserTimeToNull(id);
} else {
// 修改推广员
brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
return;
}
// 情况二修改推广员
// TODO @疯狂要复用一些 validateCanBindUser 的校验哈
brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
}
@Override
public void updateBrokerageEnabled(Long id, Boolean enabled) {
public void updateBrokerageUserEnabled(Long id, Boolean enabled) {
// 校验存在
validateBrokerageUserExists(id);
if (BooleanUtil.isTrue(enabled)) {
@ -124,36 +128,41 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
}
@Override
public Long getCountByBindUserId(Long bindUserId) {
public Long getBrokerageUserCountByBindUserId(Long bindUserId) {
// TODO @疯狂mapper 封装下哈不直接在 service 调用这种基础 mapper 的基础方法
return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId);
}
// TODO @疯狂因为现在 user 会存在使用验证码直接注册所以 isNewUser 不太好传递我们是不是可以约定绑定的时间createTime 30 秒内就认为新用户
@Override
public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
// TODO @疯狂userId 为空搞到参数校验里哇
if (userId == null) {
throw exception(0);
}
boolean isInsert = false;
// 1. 获得分销用户
boolean isNewBrokerageUser = false;
BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId);
// 分销用户不存在的情况1.新注册 2.旧数据 3.分销功能关闭后又打开
if (brokerageUser == null) {
isInsert = true;
if (brokerageUser == null) { // 分销用户不存在的情况1. 新注册2. 旧数据3. 分销功能关闭后又打开
isNewBrokerageUser = true;
brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setPrice(0).setFrozenPrice(0);
}
// 校验能否绑定
// 2.1 校验能否绑定
boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser);
if (!validated) {
return false;
}
if (isInsert) {
// 2.2 绑定用户
if (isNewBrokerageUser) {
Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) {
// 人人分销用户默认就有分销资格
if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销用户默认就有分销资格
// TODO @疯狂应该设置下 brokerageTime而不是 bindUserTime
brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now());
}
// TODO @疯狂这里是不是要设置 bindUserIdbindUserTime 字段哈
brokerageUserMapper.insert(brokerageUser);
} else {
brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
@ -162,14 +171,16 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return true;
}
// TODO @疯狂validate 方法一般不返回 true false而是抛出异常如果要返回 true false 这种方法名字可以改成 isUserCanBind
private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) {
// TODO @疯狂bindUserId 为空搞到参数校验里哇
if (bindUserId == null) {
return false;
}
// 校验分销功能是否启用
TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) {
return false;
}
@ -180,7 +191,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
// 校验要绑定的用户有无推广资格
BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId);
if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) {
if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) {
throw exception(BROKERAGE_BIND_USER_NOT_ENABLED);
}
@ -200,6 +211,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
}
}
// TODO @疯狂这块是不是一直查询到根节点中间不允许出现自己就是不能形成环虽然目前是 2 但是未来可能会改多级 = = 环的话就会存在问题哈
// A->B->A下级不能绑定自己的上级, A->B->C->A可以!!
if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
throw exception(BROKERAGE_BIND_LOOP);

View File

@ -395,7 +395,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// 增加用户经验
getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
// 增加用户佣金
getSelf().addBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, order.getId());
getSelf().addBrokerageAsync(order.getUserId(), order.getId());
}
/**
@ -675,7 +675,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// 扣减用户经验
getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId);
// 更新分佣记录为已失效
getSelf().cancelBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, id);
getSelf().cancelBrokerageAsync(order.getUserId(), id);
}
@Override
@ -785,16 +785,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Async
protected void addBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderId) {
protected void addBrokerageAsync(Long userId, Long orderId) {
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
List<BrokerageAddReqBO> list = convertList(orderItems,
item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId())));
brokerageRecordService.addBrokerage(userId, bizType, list);
brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list);
}
@Async
protected void cancelBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderItemId) {
brokerageRecordService.cancelBrokerage(userId, bizType, String.valueOf(orderItemId));
protected void cancelBrokerageAsync(Long userId, Long orderItemId) {
brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId));
}
/**

View File

@ -33,11 +33,6 @@
<artifactId>yudao-module-infra-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-trade-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 -->
<dependency>

View File

@ -8,8 +8,6 @@ import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.trade.api.brokerage.BrokerageApi;
import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
@ -18,7 +16,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Optional;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -32,23 +29,16 @@ public class AppMemberUserController {
@Resource
private MemberUserService userService;
@Resource
private MemberLevelService levelService;
@Resource
private BrokerageApi brokerageApi;
@GetMapping("/get")
@Operation(summary = "获得基本信息")
@PreAuthenticated
public CommonResult<AppMemberUserInfoRespVO> getUserInfo() {
MemberUserDO user = userService.getUser(getLoginUserId());
MemberLevelDO level = levelService.getLevel(user.getLevelId());
BrokerageUserDTO brokerageUser = brokerageApi.getBrokerageUser(user.getId());
return success(MemberUserConvert.INSTANCE.convert(user, level)
.setBrokerageEnabled(Optional.ofNullable(brokerageUser).map(BrokerageUserDTO::getBrokerageEnabled).orElse(false))
);
return success(MemberUserConvert.INSTANCE.convert(user, level));
}
@PutMapping("/update")