From f97c7a0f6e14decc794b538d2611dd8a6a4f138f Mon Sep 17 00:00:00 2001
From: owen <owen@evolsun.com>
Date: Sat, 9 Sep 2023 01:46:42 +0800
Subject: [PATCH] =?UTF-8?q?trade:=20=E5=88=86=E9=94=80=E4=B8=9A=E5=8A=A1?=
 =?UTF-8?q?=E7=BB=91=E5=AE=9A=E6=8E=A8=E5=B9=BF=E5=91=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../trade/api/brokerage/BrokerageApi.java     |  5 +-
 .../trade/enums/ErrorCodeConstants.java       |  6 ++
 .../trade/api/brokerage/BrokerageApiImpl.java |  5 +-
 .../brokerage/AppBrokerageUserController.java | 17 +++-
 .../vo/user/AppBrokerageUserBindReqVO.java    | 17 ++++
 .../brokerage/user/BrokerageUserService.java  | 10 ++
 .../user/BrokerageUserServiceImpl.java        | 92 ++++++++++++++++++-
 7 files changed, 140 insertions(+), 12 deletions(-)
 create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java

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<Boolean> 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;
+    }
+
 }