Commit f97c7a0f6e14decc794b538d2611dd8a6a4f138f

Authored by owen
1 parent 6ef36d5c

trade: 分销业务绑定推广员

yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java
1 package cn.iocoder.yudao.module.trade.api.brokerage; 1 package cn.iocoder.yudao.module.trade.api.brokerage;
2 2
3 import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; 3 import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
4 -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;  
5 4
6 /** 5 /**
7 * 分销 API 接口 6 * 分销 API 接口
@@ -23,8 +22,8 @@ public interface BrokerageApi { @@ -23,8 +22,8 @@ public interface BrokerageApi {
23 * 22 *
24 * @param userId 用户编号 23 * @param userId 用户编号
25 * @param bindUserId 推广员编号 24 * @param bindUserId 推广员编号
26 - * @param bindMode 绑定模式 {@link BrokerageBindModeEnum} 25 + * @param isNewUser 是否为新用户
27 * @return 是否绑定 26 * @return 是否绑定
28 */ 27 */
29 - boolean bindUser(Long userId, Long bindUserId, Integer bindMode); 28 + boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser);
30 } 29 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
@@ -78,5 +78,11 @@ public interface ErrorCodeConstants { @@ -78,5 +78,11 @@ public interface ErrorCodeConstants {
78 // ========== 分销用户 模块 1011007000 ========== 78 // ========== 分销用户 模块 1011007000 ==========
79 ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在"); 79 ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在");
80 ErrorCode BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH = new ErrorCode(1011007001, "用户冻结佣金({})数量不足"); 80 ErrorCode BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH = new ErrorCode(1011007001, "用户冻结佣金({})数量不足");
  81 + ErrorCode BROKERAGE_BIND_SELF = new ErrorCode(1011007002, "不能绑定自己");
  82 + ErrorCode BROKERAGE_BIND_USER_NOT_ENABLED = new ErrorCode(1011007003, "绑定用户没有推广资格");
  83 + ErrorCode BROKERAGE_BIND_CONDITION_ADMIN = new ErrorCode(1011007004, "仅可在后台绑定推广员");
  84 + ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1011007005, "只有在注册时可以绑定");
  85 + ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人");
  86 + ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级");
81 87
82 } 88 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java
@@ -25,9 +25,8 @@ public class BrokerageApiImpl implements BrokerageApi { @@ -25,9 +25,8 @@ public class BrokerageApiImpl implements BrokerageApi {
25 } 25 }
26 26
27 @Override 27 @Override
28 - public boolean bindUser(Long userId, Long bindUserId, Integer bindMode) {  
29 - // todo 待实现  
30 - return false; 28 + public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
  29 + return brokerageUserService.bindUser(userId, bindUserId, isNewUser);
31 } 30 }
32 31
33 } 32 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
@@ -4,21 +4,22 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -4,21 +4,22 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*; 6 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*;
  7 +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
7 import io.swagger.v3.oas.annotations.Operation; 8 import io.swagger.v3.oas.annotations.Operation;
8 import io.swagger.v3.oas.annotations.Parameter; 9 import io.swagger.v3.oas.annotations.Parameter;
9 import io.swagger.v3.oas.annotations.tags.Tag; 10 import io.swagger.v3.oas.annotations.tags.Tag;
10 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
11 import org.springframework.format.annotation.DateTimeFormat; 12 import org.springframework.format.annotation.DateTimeFormat;
12 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
13 -import org.springframework.web.bind.annotation.GetMapping;  
14 -import org.springframework.web.bind.annotation.RequestMapping;  
15 -import org.springframework.web.bind.annotation.RequestParam;  
16 -import org.springframework.web.bind.annotation.RestController; 14 +import org.springframework.web.bind.annotation.*;
17 15
  16 +import javax.annotation.Resource;
  17 +import javax.validation.Valid;
18 import java.time.LocalDateTime; 18 import java.time.LocalDateTime;
19 19
20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 21 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  22 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
22 import static java.util.Arrays.asList; 23 import static java.util.Arrays.asList;
23 24
24 @Tag(name = "用户 APP - 分销用户") 25 @Tag(name = "用户 APP - 分销用户")
@@ -27,6 +28,8 @@ import static java.util.Arrays.asList; @@ -27,6 +28,8 @@ import static java.util.Arrays.asList;
27 @Validated 28 @Validated
28 @Slf4j 29 @Slf4j
29 public class AppBrokerageUserController { 30 public class AppBrokerageUserController {
  31 + @Resource
  32 + private BrokerageUserService brokerageUserService;
30 33
31 // TODO 芋艿:临时 mock => 34 // TODO 芋艿:临时 mock =>
32 @GetMapping("/get") 35 @GetMapping("/get")
@@ -120,4 +123,10 @@ public class AppBrokerageUserController { @@ -120,4 +123,10 @@ public class AppBrokerageUserController {
120 return success(1); 123 return success(1);
121 } 124 }
122 125
  126 + @PutMapping("/bind-user")
  127 + @Operation(summary = "绑定推广员")
  128 + public CommonResult<Boolean> getBrokerageUserRankByPrice(@Valid AppBrokerageUserBindReqVO reqVO) {
  129 + return success(brokerageUserService.bindUser(getLoginUserId(), reqVO.getBindUserId(), false));
  130 + }
  131 +
123 } 132 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "应用 App - 绑定推广员 Request VO")
  10 +@Data
  11 +public class AppBrokerageUserBindReqVO extends PageParam {
  12 +
  13 + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + @NotNull(message = "推广员编号不能为空")
  15 + private Long bindUserId;
  16 +
  17 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
@@ -93,4 +93,14 @@ public interface BrokerageUserService { @@ -93,4 +93,14 @@ public interface BrokerageUserService {
93 * @return 推广用户数量 93 * @return 推广用户数量
94 */ 94 */
95 Long getCountByBindUserId(Long bindUserId); 95 Long getCountByBindUserId(Long bindUserId);
  96 +
  97 + /**
  98 + * 【会员】绑定推广员
  99 + *
  100 + * @param userId 用户编号
  101 + * @param bindUserId 推广员编号
  102 + * @param isNewUser 是否为新用户
  103 + * @return 是否绑定
  104 + */
  105 + boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser);
96 } 106 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
1 package cn.iocoder.yudao.module.trade.service.brokerage.user; 1 package cn.iocoder.yudao.module.trade.service.brokerage.user;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.BooleanUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 6 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
6 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
7 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper; 9 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper;
  10 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
  11 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
  12 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
8 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
9 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
10 15
11 import javax.annotation.Resource; 16 import javax.annotation.Resource;
  17 +import java.time.LocalDateTime;
12 import java.util.Collection; 18 import java.util.Collection;
13 import java.util.List; 19 import java.util.List;
  20 +import java.util.Objects;
14 import java.util.Optional; 21 import java.util.Optional;
15 22
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH;  
18 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_USER_NOT_EXISTS; 24 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
19 25
20 /** 26 /**
21 * 分销用户 Service 实现类 27 * 分销用户 Service 实现类
@@ -29,6 +35,9 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -29,6 +35,9 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
29 @Resource 35 @Resource
30 private BrokerageUserMapper brokerageUserMapper; 36 private BrokerageUserMapper brokerageUserMapper;
31 37
  38 + @Resource
  39 + private TradeConfigService tradeConfigService;
  40 +
32 @Override 41 @Override
33 public BrokerageUserDO getBrokerageUser(Long id) { 42 public BrokerageUserDO getBrokerageUser(Long id) {
34 return brokerageUserMapper.selectById(id); 43 return brokerageUserMapper.selectById(id);
@@ -105,4 +114,83 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -105,4 +114,83 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
105 return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); 114 return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId);
106 } 115 }
107 116
  117 + @Override
  118 + public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
  119 + if (userId == null) {
  120 + throw exception(0);
  121 + }
  122 +
  123 + boolean isInsert = false;
  124 + BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId);
  125 + // 分销用户不存在的情况:1.新注册 2.旧数据 3.分销功能关闭后又打开
  126 + if (brokerageUser == null) {
  127 + isInsert = true;
  128 + brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setPrice(0).setFrozenPrice(0);
  129 + }
  130 +
  131 + // 校验能否绑定
  132 + boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser);
  133 + if (!validated) {
  134 + return false;
  135 + }
  136 +
  137 + if (isInsert) {
  138 + Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
  139 + if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) {
  140 + // 人人分销:用户默认就有分销资格
  141 + brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now());
  142 + }
  143 + brokerageUserMapper.insert(brokerageUser);
  144 + } else {
  145 + brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
  146 + .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
  147 + }
  148 + return true;
  149 + }
  150 +
  151 + private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) {
  152 + if (bindUserId == null) {
  153 + return false;
  154 + }
  155 +
  156 + // 校验分销功能是否启用
  157 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
  158 + if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
  159 + return false;
  160 + }
  161 +
  162 + // 校验绑定自己
  163 + if (Objects.equals(user.getId(), bindUserId)) {
  164 + throw exception(BROKERAGE_BIND_SELF);
  165 + }
  166 +
  167 + // 校验要绑定的用户有无推广资格
  168 + BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId);
  169 + if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) {
  170 + throw exception(BROKERAGE_BIND_USER_NOT_ENABLED);
  171 + }
  172 +
  173 + // 校验分佣模式:仅可后台手动设置推广员
  174 + if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) {
  175 + throw exception(BROKERAGE_BIND_CONDITION_ADMIN);
  176 + }
  177 +
  178 + // 校验分销关系绑定模式
  179 + if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) {
  180 + if (!BooleanUtil.isTrue(isNewUser)) {
  181 + throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定
  182 + }
  183 + } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) {
  184 + if (user.getBindUserId() != null) {
  185 + throw exception(BROKERAGE_BIND_OVERRIDE); // 已绑定了推广人
  186 + }
  187 + }
  188 +
  189 + // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!!
  190 + if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
  191 + throw exception(BROKERAGE_BIND_LOOP);
  192 + }
  193 + return true;
  194 + }
  195 +
108 } 196 }