diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java index 4952e5cad..4d7314d4b 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.trade.api.brokerage; import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; /** * 分销 API 接口 @@ -23,8 +22,8 @@ public interface BrokerageApi { * * @param userId 用户编号 * @param bindUserId 推广员编号 - * @param bindMode 绑定模式 {@link BrokerageBindModeEnum} + * @param isNewUser 是否为新用户 * @return 是否绑定 */ - boolean bindUser(Long userId, Long bindUserId, Integer bindMode); + boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index fa5be50b7..236e7af23 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/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 { // ========== 分销用户 模块 1011007000 ========== ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在"); ErrorCode BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH = new ErrorCode(1011007001, "用户冻结佣金({})数量不足"); + ErrorCode BROKERAGE_BIND_SELF = new ErrorCode(1011007002, "不能绑定自己"); + ErrorCode BROKERAGE_BIND_USER_NOT_ENABLED = new ErrorCode(1011007003, "绑定用户没有推广资格"); + ErrorCode BROKERAGE_BIND_CONDITION_ADMIN = new ErrorCode(1011007004, "仅可在后台绑定推广员"); + ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1011007005, "只有在注册时可以绑定"); + ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1011007006, "已绑定了推广人"); + ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1011007007, "下级不能绑定自己的上级"); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java index 1bb520734..4a534fa22 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java +++ b/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 { } @Override - public boolean bindUser(Long userId, Long bindUserId, Integer bindMode) { - // todo 待实现 - return false; + public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) { + return brokerageUserService.bindUser(userId, bindUserId, isNewUser); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java index ecbb7de45..ef1634098 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*; +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import javax.validation.Valid; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static java.util.Arrays.asList; @Tag(name = "用户 APP - 分销用户") @@ -27,6 +28,8 @@ import static java.util.Arrays.asList; @Validated @Slf4j public class AppBrokerageUserController { + @Resource + private BrokerageUserService brokerageUserService; // TODO 芋艿:临时 mock => @GetMapping("/get") @@ -120,4 +123,10 @@ public class AppBrokerageUserController { return success(1); } + @PutMapping("/bind-user") + @Operation(summary = "绑定推广员") + public CommonResult getBrokerageUserRankByPrice(@Valid AppBrokerageUserBindReqVO reqVO) { + return success(brokerageUserService.bindUser(getLoginUserId(), reqVO.getBindUserId(), false)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java new file mode 100644 index 000000000..f2a14996a --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "应用 App - 绑定推广员 Request VO") +@Data +public class AppBrokerageUserBindReqVO extends PageParam { + + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "推广员编号不能为空") + private Long bindUserId; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java index c26cfb6e3..61aa8bde0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java +++ b/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 { * @return 推广用户数量 */ Long getCountByBindUserId(Long bindUserId); + + /** + * 【会员】绑定推广员 + * + * @param userId 用户编号 + * @param bindUserId 推广员编号 + * @param isNewUser 是否为新用户 + * @return 是否绑定 + */ + boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java index 33f81602d..7666da49b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java @@ -1,21 +1,27 @@ package cn.iocoder.yudao.module.trade.service.brokerage.user; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.BooleanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Optional; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_USER_NOT_EXISTS; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** * 分销用户 Service 实现类 @@ -29,6 +35,9 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @Resource private BrokerageUserMapper brokerageUserMapper; + @Resource + private TradeConfigService tradeConfigService; + @Override public BrokerageUserDO getBrokerageUser(Long id) { return brokerageUserMapper.selectById(id); @@ -105,4 +114,83 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); } + @Override + public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) { + if (userId == null) { + throw exception(0); + } + + boolean isInsert = false; + BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); + // 分销用户不存在的情况:1.新注册 2.旧数据 3.分销功能关闭后又打开 + if (brokerageUser == null) { + isInsert = true; + brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setPrice(0).setFrozenPrice(0); + } + + // 校验能否绑定 + boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser); + if (!validated) { + return false; + } + + if (isInsert) { + Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); + if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { + // 人人分销:用户默认就有分销资格 + brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now()); + } + brokerageUserMapper.insert(brokerageUser); + } else { + brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) + .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); + } + return true; + } + + private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) { + if (bindUserId == null) { + return false; + } + + // 校验分销功能是否启用 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { + return false; + } + + // 校验绑定自己 + if (Objects.equals(user.getId(), bindUserId)) { + throw exception(BROKERAGE_BIND_SELF); + } + + // 校验要绑定的用户有无推广资格 + BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); + if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) { + throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); + } + + // 校验分佣模式:仅可后台手动设置推广员 + if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) { + throw exception(BROKERAGE_BIND_CONDITION_ADMIN); + } + + // 校验分销关系绑定模式 + if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) { + if (!BooleanUtil.isTrue(isNewUser)) { + throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定 + } + } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) { + if (user.getBindUserId() != null) { + throw exception(BROKERAGE_BIND_OVERRIDE); // 已绑定了推广人 + } + } + + // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!! + if (Objects.equals(user.getId(), bindUser.getBindUserId())) { + throw exception(BROKERAGE_BIND_LOOP); + } + return true; + } + }