!616 完善分销功能

Merge pull request !616 from 疯狂的世界/brokerate
plp
芋道源码 3 years ago committed by Gitee
commit 18c9f22560
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F

@ -48,7 +48,7 @@ create table trade_brokerage_record
primary key, primary key,
user_id bigint not null comment '', user_id bigint not null comment '',
biz_id varchar(64) default '' not null comment '', biz_id varchar(64) default '' not null comment '',
biz_type tinyint default 0 not null comment '0-1-', biz_type tinyint default 0 not null comment '1-2-',
title varchar(64) default '' not null comment '', title varchar(64) default '' not null comment '',
price int default 0 not null comment '', price int default 0 not null comment '',
total_price int default 0 not null comment '', total_price int default 0 not null comment '',
@ -56,6 +56,8 @@ create table trade_brokerage_record
status tinyint default 0 not null comment '0-1-2-', status tinyint default 0 not null comment '0-1-2-',
frozen_days int default 0 not null comment '', frozen_days int default 0 not null comment '',
unfreeze_time datetime 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 '', creator varchar(64) collate utf8mb4_general_ci default '' null comment '',
create_time datetime default CURRENT_TIMESTAMP not null comment '', create_time datetime default CURRENT_TIMESTAMP not null comment '',
updater varchar(64) collate utf8mb4_general_ci default '' null comment '', updater varchar(64) collate utf8mb4_general_ci default '' null 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) 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); 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) 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) 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) INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)

@ -15,6 +15,9 @@ import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}
import static ${ServiceExceptionUtilClassName}.exception; import static ${ServiceExceptionUtilClassName}.exception;
import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
/** /**
* ${table.classComment} Service 实现类 * ${table.classComment} Service 实现类
* *
@ -61,6 +64,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
@Override @Override
public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return ${classNameVar}Mapper.selectById(id); return ${classNameVar}Mapper.selectById(id);
} }

@ -21,6 +21,13 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId> <artifactId>yudao-common</artifactId>
</dependency> </dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -1,7 +1,11 @@
package cn.iocoder.yudao.module.trade.api.brokerage; 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 cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/** /**
* API * API
* *
@ -17,6 +21,20 @@ public interface BrokerageApi {
*/ */
BrokerageUserDTO getBrokerageUser(Long userId); 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 * @param isNewUser
* @return * @return
*/ */
boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull Boolean isNewUser);
} }

@ -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;
}
}

@ -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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.BrokerageRecordPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert; 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.annotation.Resource;
import javax.validation.Valid; 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.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 = "管理后台 - 佣金记录") @Tag(name = "管理后台 - 佣金记录")
@RestController @RestController
@ -31,6 +37,9 @@ public class BrokerageRecordController {
@Resource @Resource
private BrokerageRecordService brokerageRecordService; private BrokerageRecordService brokerageRecordService;
@Resource
private MemberUserApi memberUserApi;
@GetMapping("/get") @GetMapping("/get")
@Operation(summary = "获得佣金记录") @Operation(summary = "获得佣金记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@ -45,7 +54,12 @@ public class BrokerageRecordController {
@PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) { public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO); PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult));
Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
} }
} }

@ -57,4 +57,9 @@ public class BrokerageRecordBaseVO {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime unfreezeTime; private LocalDateTime unfreezeTime;
@Schema(description = "来源用户类型")
private Integer sourceUserType;
@Schema(description = "来源用户编号")
private Long sourceUserId;
} }

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo; 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.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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -30,4 +32,8 @@ public class BrokerageRecordPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@Schema(description = "用户类型")
@InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer sourceUserType;
} }

@ -19,4 +19,19 @@ public class BrokerageRecordRespVO extends BrokerageRecordBaseVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; 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;
} }

@ -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.dal.dataobject.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 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.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.bo.UserBrokerageSummaryBO;
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -42,18 +43,18 @@ public class BrokerageUserController {
@Resource @Resource
private MemberUserApi memberUserApi; private MemberUserApi memberUserApi;
@PutMapping("/update-brokerage-user") @PutMapping("/update-bind-user")
@Operation(summary = "修改推广员") @Operation(summary = "修改推广员")
@PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-user')") @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')")
public CommonResult<Boolean> updateBrokerageUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) { public CommonResult<Boolean> updateBindUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) {
brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId()); brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId());
return success(true); return success(true);
} }
@PutMapping("/clear-brokerage-user") @PutMapping("/clear-bind-user")
@Operation(summary = "清除推广员") @Operation(summary = "清除推广员")
@PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-brokerage-user')") @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-bind-user')")
public CommonResult<Boolean> clearBrokerageUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) { public CommonResult<Boolean> clearBindUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) {
brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null); brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null);
return success(true); return success(true);
} }
@ -72,7 +73,8 @@ public class BrokerageUserController {
@PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) { public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(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") @GetMapping("/page")
@ -94,7 +96,7 @@ public class BrokerageUserController {
// 合计推广用户数量 // 合计推广用户数量
Map<Long, Long> brokerageUserCountMap = convertMap(userIds, Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
userId -> userId, userId -> userId,
userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId)); userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, BrokerageUserTypeEnum.ALL));
// todo 合计提现 // todo 合计提现

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo; 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.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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -27,4 +29,11 @@ public class BrokerageUserPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; 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;
} }

@ -28,7 +28,7 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
// ========== 推广信息 ========== // ========== 推广信息 ==========
@Schema(description = "推广用户数量(一级)", example = "20019") @Schema(description = "推广用户数量", example = "20019")
private Integer brokerageUserCount; private Integer brokerageUserCount;
@Schema(description = "推广订单数量", example = "20019") @Schema(description = "推广订单数量", example = "20019")
private Integer brokerageOrderCount; private Integer brokerageOrderCount;

@ -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.AppBrokerageProductPriceRespVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; 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.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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; 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.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 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; import static java.util.Arrays.asList;
@Tag(name = "用户 APP - 分销用户") @Tag(name = "用户 APP - 分销用户")
@ -27,6 +30,8 @@ import static java.util.Arrays.asList;
@Validated @Validated
@Slf4j @Slf4j
public class AppBrokerageRecordController { public class AppBrokerageRecordController {
@Resource
private BrokerageUserService brokerageUserService;
// TODO 芋艿:临时 mock => // TODO 芋艿:临时 mock =>
@GetMapping("/page") @GetMapping("/page")
@ -46,7 +51,7 @@ public class AppBrokerageRecordController {
@Operation(summary = "获得商品的分销金额") @Operation(summary = "获得商品的分销金额")
public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) { public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {
AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO(); AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO();
respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销 respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId()));
respVO.setBrokerageMinPrice(1); respVO.setBrokerageMinPrice(1);
respVO.setBrokerageMaxPrice(2); respVO.setBrokerageMaxPrice(2);
return success(respVO); return success(respVO);

@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO {
@Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
private Integer frozenPrice; private Integer frozenPrice;
@Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer firstBrokerageUserCount; private Integer firstBrokerageUserCount;
@Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.record;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.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.record.BrokerageRecordDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO; 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.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
/** /**
* Convert * Convert
@ -30,10 +33,9 @@ public interface BrokerageRecordConvert {
PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page); PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page);
// TODO @疯狂:可能 title 不是很固化会存在类似沐晴成功购买《XXX JVM 实战》
default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
String title) { String title, Long sourceUserId, Integer sourceUserType) {
brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
// 不冻结时,佣金直接就是结算状态 // 不冻结时,佣金直接就是结算状态
Integer status = brokerageFrozenDays > 0 Integer status = brokerageFrozenDays > 0
@ -43,8 +45,22 @@ public interface BrokerageRecordConvert {
.setBizType(bizType.getType()).setBizId(bizId) .setBizType(bizType.getType()).setBizId(bizId)
.setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice()) .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice())
.setTitle(title) .setTitle(title)
.setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokeragePrice / 100.0))) .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
.setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime); .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime)
.setSourceUserType(sourceUserType).setSourceUserId(sourceUserId);
} }
default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
PageResult<BrokerageRecordRespVO> 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;
}
} }

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

@ -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.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 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.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; 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.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.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.enums.order.TradeOrderItemAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; 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.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.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
@ -279,8 +280,10 @@ public interface TradeOrderConvert {
default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) { default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())) return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))
.setSourceUserId(item.getUserId())
.setBasePrice(item.getPayPrice() * item.getCount()) .setBasePrice(item.getPayPrice() * item.getCount())
.setFirstFixedPrice(sku.getSubCommissionFirstPrice()) .setFirstFixedPrice(sku.getSubCommissionFirstPrice())
.setSecondFixedPrice(sku.getSubCommissionSecondPrice()); .setSecondFixedPrice(sku.getSubCommissionSecondPrice())
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle());
} }
} }

@ -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.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 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.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -32,6 +33,8 @@ public class BrokerageRecordDO extends BaseDO {
private Integer id; private Integer id;
/** /**
* *
* <p>
* MemberUserDO.id
*/ */
private Long userId; private Long userId;
/** /**
@ -79,4 +82,17 @@ public class BrokerageRecordDO extends BaseDO {
*/ */
private LocalDateTime unfreezeTime; private LocalDateTime unfreezeTime;
/**
*
* <p>
* {@link BrokerageUserTypeEnum}
*/
private Integer sourceUserType;
/**
*
* <p>
* MemberUserDO.id
*/
private Long sourceUserId;
} }

@ -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.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO; 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.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 cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -23,10 +24,14 @@ import java.util.List;
public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) { default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
!BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>() return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
.eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
.eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType())
.betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BrokerageRecordDO::getId)); .orderByDesc(BrokerageRecordDO::getId));
} }
@ -43,13 +48,13 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
.eq(BrokerageRecordDO::getStatus, status)); .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, 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, UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
@Param("bizType") Integer bizType, @Param("bizType") Integer bizType,
@Param("status") Integer status); @Param("status") Integer status);

@ -1,13 +1,17 @@
package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user; package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
import cn.hutool.core.lang.Assert; 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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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.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.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 com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/** /**
* Mapper * Mapper
@ -19,12 +23,32 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) { default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>() return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
.eqIfPresent(BrokerageUserDO::getBindUserId, reqVO.getBindUserId())
.eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
.betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
.betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
.and(reqVO.getBindUserId() != null, w -> buildBindUserCondition(reqVO, w))
.orderByDesc(BrokerageUserDO::getId)); .orderByDesc(BrokerageUserDO::getId));
} }
static void buildBindUserCondition(BrokerageUserPageReqVO reqVO, LambdaQueryWrapper<BrokerageUserDO> 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<BrokerageUserDO> wrapper) {
wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
}
static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> 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<BrokerageUserDO> {
.set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); .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);
} }

@ -36,4 +36,13 @@ public class BrokerageAddReqBO {
*/ */
private Integer secondFixedPrice; private Integer secondFixedPrice;
/**
*
*/
private Long sourceUserId;
/**
*
*/
private String title;
} }

@ -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.dal.mysql.brokerage.record.BrokerageRecordMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; 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.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.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService; import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@ -27,7 +28,6 @@ import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function;
/** /**
* Service * Service
@ -72,7 +72,8 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
return; return;
} }
// 1.2 计算一级分佣 // 1.2 计算一级分佣
addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getFirstFixedPrice, bizType); addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(),
bizType, BrokerageUserTypeEnum.FIRST);
// 2.1 获得二级推广员 // 2.1 获得二级推广员
if (firstUser.getBindUserId() == null) { if (firstUser.getBindUserId() == null) {
@ -83,15 +84,15 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
return; return;
} }
// 2.2 计算二级分佣 // 2.2 计算二级分佣
addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), BrokerageAddReqBO::getSecondFixedPrice, bizType); addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(),
bizType, BrokerageUserTypeEnum.SECOND);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) { public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) {
// TODO @疯狂userId 加进去查询,会不会更好一点?万一穿错参数; BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizIdAndUserId(bizType.getType(), bizId, userId);
BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId); if (record == null) {
if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) {
log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
return; return;
} }
@ -139,12 +140,11 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
* @param list * @param list
* @param brokerageFrozenDays * @param brokerageFrozenDays
* @param brokeragePercent * @param brokeragePercent
* @param fixedPriceFun // TODO 疯狂:这里是不是可以直接传递 fixedPrice 呀?
* @param bizType * @param bizType
* @param sourceUserType
*/ */
private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays, private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> fixedPriceFun, Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) {
BrokerageRecordBizTypeEnum bizType) {
// 1.1 处理冻结时间 // 1.1 处理冻结时间
LocalDateTime unfreezeTime = null; LocalDateTime unfreezeTime = null;
if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
@ -154,12 +154,20 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
int totalBrokerage = 0; int totalBrokerage = 0;
List<BrokerageRecordDO> records = new ArrayList<>(); List<BrokerageRecordDO> records = new ArrayList<>();
for (BrokerageAddReqBO item : list) { 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) { if (brokeragePerItem <= 0) {
continue; continue;
} }
records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), 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; totalBrokerage += brokeragePerItem;
} }
if (CollUtil.isEmpty(records)) { if (CollUtil.isEmpty(records)) {

@ -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.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO; 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.brokerage.user.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -86,14 +87,14 @@ public interface BrokerageUserService {
*/ */
void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice); void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice);
// TODO @疯狂:这个后面可能要支持下,二级
/** /**
* 广 * 广
* *
* @param bindUserId 广 * @param bindUserId 广
* @param userType
* @return 广 * @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); boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser);
/**
*
*
* @param userId
* @return
*/
Boolean getUserBrokerageEnabled(Long userId);
} }

@ -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.dal.mysql.brokerage.user.BrokerageUserMapper;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; 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.BrokerageEnabledConditionEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -56,7 +57,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
@Override @Override
public void updateBrokerageUserId(Long id, Long bindUserId) { public void updateBrokerageUserId(Long id, Long bindUserId) {
// 校验存在 // 校验存在
validateBrokerageUserExists(id); BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
// 情况一:清除推广员 // 情况一:清除推广员
if (bindUserId == null) { if (bindUserId == null) {
@ -66,7 +67,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
} }
// 情况二:修改推广员 // 情况二:修改推广员
// TODO @疯狂:要复用一些 validateCanBindUser 的校验哈; validateCanBindUser(brokerageUser, bindUserId);
brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
} }
@ -85,10 +86,13 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
} }
} }
private void validateBrokerageUserExists(Long id) { private BrokerageUserDO validateBrokerageUserExists(Long id) {
if (brokerageUserMapper.selectById(id) == null) { BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(id);
if (brokerageUserDO == null) {
throw exception(BROKERAGE_USER_NOT_EXISTS); throw exception(BROKERAGE_USER_NOT_EXISTS);
} }
return brokerageUserDO;
} }
@Override @Override
@ -128,19 +132,23 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
} }
@Override @Override
public Long getBrokerageUserCountByBindUserId(Long bindUserId) { public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
// TODO @疯狂mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法 switch (userType) {
return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); 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 @Override
public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) { public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) {
// TODO @疯狂userId 为空,搞到参数校验里哇;
if (userId == null) {
throw exception(0);
}
// 1. 获得分销用户 // 1. 获得分销用户
boolean isNewBrokerageUser = false; boolean isNewBrokerageUser = false;
BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); 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); brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0);
} }
// 2.1 校验绑定 // 2.1 校验是否能绑定用户
boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser); boolean validated = isUserCanBind(brokerageUser, isNewUser);
if (!validated) { if (!validated) {
return false; return false;
} }
// 2.3 校验能否绑定
// 2.2 绑定用户 validateCanBindUser(brokerageUser, bindUserId);
// 2.3 绑定用户
if (isNewBrokerageUser) { if (isNewBrokerageUser) {
Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格 if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格
// TODO @疯狂:应该设置下 brokerageTime而不是 bindUserTime brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now());
brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now());
} }
// TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈; brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
brokerageUserMapper.insert(brokerageUser); brokerageUserMapper.insert(brokerageUser);
} else { } else {
brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
@ -171,28 +179,25 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return true; return true;
} }
// TODO @疯狂validate 方法,一般不返回 true false而是抛出异常如果要返回 true false 这种,方法名字可以改成 isUserCanBind @Override
private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) { public Boolean getUserBrokerageEnabled(Long userId) {
// TODO @疯狂bindUserId 为空,搞到参数校验里哇; // 全局分销功能是否开启
if (bindUserId == null) {
return false;
}
// 校验分销功能是否启用
TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) { if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
return false; return false;
} }
// 校验绑定自己 // 用户是否有分销资格
if (Objects.equals(user.getId(), bindUserId)) { return Optional.ofNullable(getBrokerageUser(userId))
throw exception(BROKERAGE_BIND_SELF); .map(BrokerageUserDO::getBrokerageEnabled)
.orElse(false);
} }
// 校验要绑定的用户有无推广资格 private boolean isUserCanBind(BrokerageUserDO user, Boolean isNewUser) {
BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); // 校验分销功能是否启用
if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) { TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
return false;
} }
// 校验分佣模式:仅可后台手动设置推广员 // 校验分佣模式:仅可后台手动设置推广员
@ -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 级,但是未来可能会改多级; = = 环的话,就会存在问题哈 // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈
// A->B->A下级不能绑定自己的上级, A->B->C->A可以!! // A->B->A下级不能绑定自己的上级, A->B->C->A可以!!
if (Objects.equals(user.getId(), bindUser.getBindUserId())) { if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
throw exception(BROKERAGE_BIND_LOOP); throw exception(BROKERAGE_BIND_LOOP);
} }
return true;
} }
} }

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.member.service.user; 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.IdUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -103,6 +105,9 @@ public class MemberUserServiceImpl implements MemberUserService {
@Override @Override
public List<MemberUserDO> getUserList(Collection<Long> ids) { public List<MemberUserDO> getUserList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return memberUserMapper.selectBatchIds(ids); return memberUserMapper.selectBatchIds(ids);
} }

Loading…
Cancel
Save