diff --git a/sql/mysql/brokerage.sql b/sql/mysql/brokerage.sql index a84d80051..ff291647e 100644 --- a/sql/mysql/brokerage.sql +++ b/sql/mysql/brokerage.sql @@ -44,24 +44,26 @@ create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是 create table trade_brokerage_record ( - id int auto_increment comment '编号' + id int auto_increment comment '编号' primary key, - user_id bigint not null comment '用户编号', - biz_id varchar(64) default '' not null comment '业务编号', - biz_type tinyint default 0 not null comment '业务类型:0-订单,1-提现', - title varchar(64) default '' not null comment '标题', - price int default 0 not null comment '金额', - total_price int default 0 not null comment '当前总佣金', - description varchar(500) default '' not null comment '说明', - status tinyint default 0 not null comment '状态:0-待结算,1-已结算,2-已取消', - frozen_days int default 0 not null comment '冻结时间(天)', - unfreeze_time datetime null comment '解冻时间', - creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者', - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', - updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者', - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', - deleted bit default b'0' not null comment '是否删除', - tenant_id bigint default 0 not null comment '租户编号' + user_id bigint not null comment '用户编号', + biz_id varchar(64) default '' not null comment '业务编号', + biz_type tinyint default 0 not null comment '业务类型:1-订单,2-提现', + title varchar(64) default '' not null comment '标题', + price int default 0 not null comment '金额', + total_price int default 0 not null comment '当前总佣金', + description varchar(500) default '' not null comment '说明', + status tinyint default 0 not null comment '状态:0-待结算,1-已结算,2-已取消', + frozen_days int default 0 not null comment '冻结时间(天)', + unfreeze_time datetime null comment '解冻时间', + source_user_type tinyint not null comment '来源用户类型:1-一级推广用户,2-二级推广用户', + source_user_id bigint not null comment '来源用户编号', + creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者', + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', + updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者', + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', + deleted bit default b'0' not null comment '是否删除', + tenant_id bigint default 0 not null comment '租户编号' ) comment '佣金记录'; @@ -192,9 +194,9 @@ VALUES ('分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0); INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) -VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-brokerage-user', 3, 5, @parentId, '', '', '', 0); +VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, @parentId, '', '', '', 0); INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status) -VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-brokerage-user', 3, 6, @parentId, '', '', '', 0); +VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, @parentId, '', '', '', 0); -- 增加菜单:佣金记录 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name) diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm index a732039ce..148d1fa41 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm @@ -15,6 +15,9 @@ import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName} import static ${ServiceExceptionUtilClassName}.exception; import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; + /** * ${table.classComment} Service 实现类 * @@ -61,6 +64,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service @Override public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } return ${classNameVar}Mapper.selectById(id); } diff --git a/yudao-module-mall/yudao-module-trade-api/pom.xml b/yudao-module-mall/yudao-module-trade-api/pom.xml index 1299ad11d..6dd926b7b 100644 --- a/yudao-module-mall/yudao-module-trade-api/pom.xml +++ b/yudao-module-mall/yudao-module-trade-api/pom.xml @@ -21,6 +21,13 @@ cn.iocoder.boot yudao-common + + + + org.springframework.boot + spring-boot-starter-validation + true + 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 4d7314d4b..180cf4d8f 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,11 @@ package cn.iocoder.yudao.module.trade.api.brokerage; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + /** * 分销 API 接口 * @@ -17,6 +21,20 @@ public interface BrokerageApi { */ BrokerageUserDTO getBrokerageUser(Long userId); + /** + * 【会员】绑定推广员 + * + * @param userId 用户编号 + * @param bindUserId 推广员编号 + * @param registerTime 用户注册时间 + * @return 是否绑定 + */ + default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) { + // 注册时间在30秒内的,都算新用户 + boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30)); + return bindUser(userId, bindUserId, isNewUser); + } + /** * 绑定推广员 * @@ -25,5 +43,5 @@ public interface BrokerageApi { * @param isNewUser 是否为新用户 * @return 是否绑定 */ - boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); + boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull Boolean isNewUser); } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java new file mode 100644 index 000000000..ed71b8434 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 分销用户类型枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageUserTypeEnum implements IntArrayValuable { + + ALL(0, "全部"), + FIRST(1, "一级推广人"), + SECOND(2, "二级推广人"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageUserTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java index 81034124b..e015922a0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO; import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert; @@ -19,8 +21,12 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.Map; +import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - 佣金记录") @RestController @@ -31,6 +37,9 @@ public class BrokerageRecordController { @Resource private BrokerageRecordService brokerageRecordService; + @Resource + private MemberUserApi memberUserApi; + @GetMapping("/get") @Operation(summary = "获得佣金记录") @Parameter(name = "id", description = "编号", required = true, example = "1024") @@ -45,7 +54,12 @@ public class BrokerageRecordController { @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") public CommonResult> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) { PageResult pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO); - return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult)); + + Set userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId); + userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId)); + Map userMap = memberUserApi.getUserMap(userIds); + + return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap)); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java index cce84a804..477f89978 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java @@ -57,4 +57,9 @@ public class BrokerageRecordBaseVO { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime unfreezeTime; + @Schema(description = "来源用户类型") + private Integer sourceUserType; + + @Schema(description = "来源用户编号") + private Long sourceUserId; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java index 533fbd2ca..4ef472290 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -30,4 +32,8 @@ public class BrokerageRecordPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "用户类型") + @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}") + private Integer sourceUserType; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java index aead00a08..1f58b53ee 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java @@ -19,4 +19,19 @@ public class BrokerageRecordRespVO extends BrokerageRecordBaseVO { @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; + + // ========== 用户信息 ========== + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String userAvatar; + @Schema(description = "用户昵称", example = "李四") + private String userNickname; + + + // ========== 来源用户信息 ========== + + @Schema(description = "来源用户头像", example = "https://www.iocoder.cn/xxx.png") + private String sourceUserAvatar; + @Schema(description = "来源用户昵称", example = "李四") + private String sourceUserNickname; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java index b0263f684..f47f5d9ed 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java @@ -9,8 +9,9 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; -import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService; import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -42,18 +43,18 @@ public class BrokerageUserController { @Resource private MemberUserApi memberUserApi; - @PutMapping("/update-brokerage-user") + @PutMapping("/update-bind-user") @Operation(summary = "修改推广员") - @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-user')") - public CommonResult updateBrokerageUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) { + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')") + public CommonResult updateBindUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) { brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId()); return success(true); } - @PutMapping("/clear-brokerage-user") + @PutMapping("/clear-bind-user") @Operation(summary = "清除推广员") - @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-brokerage-user')") - public CommonResult clearBrokerageUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) { + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-bind-user')") + public CommonResult clearBindUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) { brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null); return success(true); } @@ -72,7 +73,8 @@ public class BrokerageUserController { @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") public CommonResult getBrokerageUser(@RequestParam("id") Long id) { BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id); - return success(BrokerageUserConvert.INSTANCE.convert(brokerageUser)); + BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser); + return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO)); } @GetMapping("/page") @@ -94,7 +96,7 @@ public class BrokerageUserController { // 合计推广用户数量 Map brokerageUserCountMap = convertMap(userIds, userId -> userId, - userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId)); + userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, BrokerageUserTypeEnum.ALL)); // todo 合计提现 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java index e6908e8aa..c40affac0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,4 +29,11 @@ public class BrokerageUserPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "用户类型") + @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}") + private Integer userType; + + @Schema(description = "绑定时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] bindUserTime; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java index ae7caf5ff..4aa3e5732 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java @@ -28,7 +28,7 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO { // ========== 推广信息 ========== - @Schema(description = "推广用户数量(一级)", example = "20019") + @Schema(description = "推广用户数量", example = "20019") private Integer brokerageUserCount; @Schema(description = "推广订单数量", example = "20019") private Integer brokerageOrderCount; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java index 9569162cb..66fb2994a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO; +import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; @@ -15,10 +16,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +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.web.core.util.WebFrameworkUtils.getLoginUserId; import static java.util.Arrays.asList; @Tag(name = "用户 APP - 分销用户") @@ -27,6 +30,8 @@ import static java.util.Arrays.asList; @Validated @Slf4j public class AppBrokerageRecordController { + @Resource + private BrokerageUserService brokerageUserService; // TODO 芋艿:临时 mock => @GetMapping("/page") @@ -46,7 +51,7 @@ public class AppBrokerageRecordController { @Operation(summary = "获得商品的分销金额") public CommonResult getProductBrokeragePrice(@RequestParam("spuId") Long spuId) { AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO(); - respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销 + respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId())); respVO.setBrokerageMinPrice(1); respVO.setBrokerageMaxPrice(2); return success(respVO); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java index cc9a03ebc..c1b4631db 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java @@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO { @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") private Integer frozenPrice; - @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private Integer firstBrokerageUserCount; @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java index b55a76c88..be0cc6bbb 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.record; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; @@ -13,6 +14,8 @@ import org.mapstruct.factory.Mappers; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +import java.util.Optional; /** * 佣金记录 Convert @@ -30,10 +33,9 @@ public interface BrokerageRecordConvert { PageResult convertPage(PageResult page); - // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》 default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, - String title) { + String title, Long sourceUserId, Integer sourceUserType) { brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); // 不冻结时,佣金直接就是结算状态 Integer status = brokerageFrozenDays > 0 @@ -43,8 +45,22 @@ public interface BrokerageRecordConvert { .setBizType(bizType.getType()).setBizId(bizId) .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice()) .setTitle(title) - .setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokeragePrice / 100.0))) - .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime); + .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d))) + .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime) + .setSourceUserType(sourceUserType).setSourceUserId(sourceUserId); } + default PageResult convertPage(PageResult pageResult, Map userMap) { + PageResult result = convertPage(pageResult); + + for (BrokerageRecordRespVO respVO : result.getList()) { + Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user -> + respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar())); + + Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user -> + respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar())); + } + + return result; + } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java index 6f0222b5b..2a23f1095 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java @@ -37,20 +37,25 @@ public interface BrokerageUserConvert { PageResult result = convertPage(pageResult); for (BrokerageUserRespVO vo : result.getList()) { // 用户信息 - Optional.ofNullable(userMap.get(vo.getId())).ifPresent( - user -> vo.setNickname(user.getNickname()).setAvatar(user.getAvatar())); - // 推广用户数量(一级) + copyTo(userMap.get(vo.getId()), vo); + + // 推广用户数量 vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0)); // 推广订单数量、推广订单金额 Optional orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId())); vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0)) .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0)); // todo 已提现次数、已提现金额 - vo.setWithdrawCount(0); - vo.setWithdrawPrice(0); + vo.setWithdrawCount(0).setWithdrawPrice(0); } return result; } + default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) { + Optional.ofNullable(source).ifPresent( + user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar())); + return target; + } + BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index e4c996da5..46f4362b9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; -import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; @@ -28,9 +27,11 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import org.mapstruct.Mapper; @@ -279,8 +280,10 @@ public interface TradeOrderConvert { default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) { return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())) + .setSourceUserId(item.getUserId()) .setBasePrice(item.getPayPrice() * item.getCount()) .setFirstFixedPrice(sku.getSubCommissionFirstPrice()) - .setSecondFixedPrice(sku.getSubCommissionSecondPrice()); + .setSecondFixedPrice(sku.getSubCommissionSecondPrice()) + .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java index be69c6075..a01462069 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.BrokerageUserTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -32,6 +33,8 @@ public class BrokerageRecordDO extends BaseDO { private Integer id; /** * 用户编号 + *

+ * 关联 MemberUserDO.id */ private Long userId; /** @@ -79,4 +82,17 @@ public class BrokerageRecordDO extends BaseDO { */ private LocalDateTime unfreezeTime; + /** + * 来源用户类型 + *

+ * 枚举 {@link BrokerageUserTypeEnum} + */ + private Integer sourceUserType; + /** + * 来源用户编号 + *

+ * 关联 MemberUserDO.id + */ + private Long sourceUserId; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java index b72b50ca7..16a0ae83a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; @@ -23,10 +24,14 @@ import java.util.List; public interface BrokerageRecordMapper extends BaseMapperX { default PageResult selectPage(BrokerageRecordPageReqVO reqVO) { + boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null && + !BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType()); + return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) + .eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType()) .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(BrokerageRecordDO::getId)); } @@ -43,13 +48,13 @@ public interface BrokerageRecordMapper extends BaseMapperX { .eq(BrokerageRecordDO::getStatus, status)); } - default BrokerageRecordDO selectByBizTypeAndBizId(Integer bizType, String bizId) { + default BrokerageRecordDO selectByBizTypeAndBizIdAndUserId(Integer bizType, String bizId, Long userId) { return selectOne(BrokerageRecordDO::getBizType, bizType, - BrokerageRecordDO::getBizId, bizId); + BrokerageRecordDO::getBizId, bizId, + BrokerageRecordDO::getUserId, userId); } - // 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}") + @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, @Param("status") Integer status); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java index 7fa3e415a..1566767f3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java @@ -1,13 +1,17 @@ package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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.enums.brokerage.BrokerageUserTypeEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; /** * 分销用户 Mapper @@ -19,12 +23,32 @@ public interface BrokerageUserMapper extends BaseMapperX { default PageResult selectPage(BrokerageUserPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(BrokerageUserDO::getBindUserId, reqVO.getBindUserId()) .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) + .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime()) + .and(reqVO.getBindUserId() != null, w -> buildBindUserCondition(reqVO, w)) .orderByDesc(BrokerageUserDO::getId)); } + static void buildBindUserCondition(BrokerageUserPageReqVO reqVO, LambdaQueryWrapper wrapper) { + if (BrokerageUserTypeEnum.FIRST.getType().equals(reqVO.getUserType())) { + buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper); + } else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) { + buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper); + } else { + buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper); + buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); + } + } + + static void buildFirstBindUserCondition(Long bindUserId, LambdaQueryWrapper wrapper) { + wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId); + } + + static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper w) { + w.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId)); + } + /** * 更新用户可用佣金(增加) * @@ -112,4 +136,10 @@ public interface BrokerageUserMapper extends BaseMapperX { .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); } + default Long selectCountByBindUserId(Long bindUserId) { + return selectCount(BrokerageUserDO::getBindUserId, bindUserId); + } + + @Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})") + Long selectCountByBindUserIdInBindUserId(Long bindUserId); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java index ff16ba16a..0412abc58 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java @@ -36,4 +36,13 @@ public class BrokerageAddReqBO { */ private Integer secondFixedPrice; + /** + * 来源用户编号 + */ + private Long sourceUserId; + + /** + * 佣金记录标题 + */ + private String title; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java index 7740d7d06..5dd00cc22 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper; 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.BrokerageUserTypeEnum; import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; @@ -27,7 +28,6 @@ import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.util.function.Function; /** * 佣金记录 Service 实现类 @@ -72,7 +72,8 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { return; } // 1.2 计算一级分佣 - addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getFirstFixedPrice, bizType); + addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), + bizType, BrokerageUserTypeEnum.FIRST); // 2.1 获得二级推广员 if (firstUser.getBindUserId() == null) { @@ -83,15 +84,15 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { return; } // 2.2 计算二级分佣 - addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), BrokerageAddReqBO::getSecondFixedPrice, bizType); + addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), + bizType, BrokerageUserTypeEnum.SECOND); } @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)) { + BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizIdAndUserId(bizType.getType(), bizId, userId); + if (record == null) { log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); return; } @@ -139,12 +140,11 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { * @param list 佣金增加参数列表 * @param brokerageFrozenDays 冻结天数 * @param brokeragePercent 佣金比例 - * @param fixedPriceFun 固定佣金 // TODO 疯狂:这里是不是可以直接传递 fixedPrice 呀? * @param bizType 业务类型 + * @param sourceUserType 来源用户类型 */ private void addBrokerage(BrokerageUserDO user, List list, Integer brokerageFrozenDays, - Integer brokeragePercent, Function fixedPriceFun, - BrokerageRecordBizTypeEnum bizType) { + Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) { // 1.1 处理冻结时间 LocalDateTime unfreezeTime = null; if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { @@ -154,12 +154,20 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { int totalBrokerage = 0; List records = new ArrayList<>(); for (BrokerageAddReqBO item : list) { - int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPriceFun.apply(item)); + Integer fixedPrice = 0; + if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) { + fixedPrice = item.getFirstFixedPrice(); + } else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) { + fixedPrice = item.getSecondFixedPrice(); + } + + int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice); if (brokeragePerItem <= 0) { continue; } records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), - brokerageFrozenDays, brokeragePerItem, unfreezeTime, bizType.getTitle())); + brokerageFrozenDays, brokeragePerItem, unfreezeTime, item.getTitle(), + item.getSourceUserId(), sourceUserType.getType())); totalBrokerage += brokeragePerItem; } if (CollUtil.isEmpty(records)) { 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 de9d0a2b7..df910789a 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 @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage.user; 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.enums.brokerage.BrokerageUserTypeEnum; import java.util.Collection; import java.util.List; @@ -86,14 +87,14 @@ public interface BrokerageUserService { */ void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice); - // TODO @疯狂:这个后面可能要支持下,二级 /** - * 获得推广用户数量(一级) + * 获得推广用户数量 * * @param bindUserId 绑定的推广员编号 + * @param userType 用户类型 * @return 推广用户数量 */ - Long getBrokerageUserCountByBindUserId(Long bindUserId); + Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType); /** * 【会员】绑定推广员 @@ -105,4 +106,11 @@ public interface BrokerageUserService { */ boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser); + /** + * 获取用户是否有分销资格 + * + * @param userId 用户编号 + * @return 是否有分销资格 + */ + Boolean getUserBrokerageEnabled(Long userId); } 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 1a168d966..11ab5c6c1 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 @@ -9,6 +9,7 @@ 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.enums.brokerage.BrokerageUserTypeEnum; import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -56,7 +57,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @Override public void updateBrokerageUserId(Long id, Long bindUserId) { // 校验存在 - validateBrokerageUserExists(id); + BrokerageUserDO brokerageUser = validateBrokerageUserExists(id); // 情况一:清除推广员 if (bindUserId == null) { @@ -66,7 +67,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } // 情况二:修改推广员 - // TODO @疯狂:要复用一些 validateCanBindUser 的校验哈; + validateCanBindUser(brokerageUser, bindUserId); brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); } @@ -85,10 +86,13 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } } - private void validateBrokerageUserExists(Long id) { - if (brokerageUserMapper.selectById(id) == null) { + private BrokerageUserDO validateBrokerageUserExists(Long id) { + BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(id); + if (brokerageUserDO == null) { throw exception(BROKERAGE_USER_NOT_EXISTS); } + + return brokerageUserDO; } @Override @@ -128,19 +132,23 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } @Override - public Long getBrokerageUserCountByBindUserId(Long bindUserId) { - // TODO @疯狂:mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法 - return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); + public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) { + switch (userType) { + case ALL: + Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId); + Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId); + return firstCount + secondCount; + case FIRST: + return brokerageUserMapper.selectCountByBindUserId(bindUserId); + case SECOND: + return brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId); + default: + return 0L; + } } - // TODO @疯狂:因为现在 user 会存在使用验证码直接注册,所以 isNewUser 不太好传递;我们是不是可以约定绑定的时间,createTime 在 30 秒内,就认为新用户; @Override public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) { - // TODO @疯狂:userId 为空,搞到参数校验里哇; - if (userId == null) { - throw exception(0); - } - // 1. 获得分销用户 boolean isNewBrokerageUser = false; BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); @@ -149,20 +157,20 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0); } - // 2.1 校验能否绑定 - boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser); + // 2.1 校验是否能绑定用户 + boolean validated = isUserCanBind(brokerageUser, isNewUser); if (!validated) { return false; } - - // 2.2 绑定用户 + // 2.3 校验能否绑定 + validateCanBindUser(brokerageUser, bindUserId); + // 2.3 绑定用户 if (isNewBrokerageUser) { Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格 - // TODO @疯狂:应该设置下 brokerageTime,而不是 bindUserTime - brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now()); + brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now()); } - // TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈; + brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()); brokerageUserMapper.insert(brokerageUser); } else { brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) @@ -171,30 +179,27 @@ 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) { + @Override + public Boolean getUserBrokerageEnabled(Long userId) { + // 全局分销功能是否开启 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { return false; } + // 用户是否有分销资格 + return Optional.ofNullable(getBrokerageUser(userId)) + .map(BrokerageUserDO::getBrokerageEnabled) + .orElse(false); + } + + private boolean isUserCanBind(BrokerageUserDO user, Boolean isNewUser) { // 校验分销功能是否启用 TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); - if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) { + 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.isFalse(bindUser.getBrokerageEnabled())) { - throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); - } - // 校验分佣模式:仅可后台手动设置推广员 if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) { throw exception(BROKERAGE_BIND_CONDITION_ADMIN); @@ -211,12 +216,26 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } } + return true; + } + + private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) { + // 校验要绑定的用户有无推广资格 + BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); + if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) { + throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); + } + + // 校验绑定自己 + if (Objects.equals(user.getId(), bindUserId)) { + throw exception(BROKERAGE_BIND_SELF); + } + // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈 // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!! if (Objects.equals(user.getId(), bindUser.getBindUserId())) { throw exception(BROKERAGE_BIND_LOOP); } - return true; } } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java index c5b674cc8..8381c73f1 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.member.service.user; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -103,6 +105,9 @@ public class MemberUserServiceImpl implements MemberUserService { @Override public List getUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } return memberUserMapper.selectBatchIds(ids); }