code review:分销逻辑

This commit is contained in:
YunaiV 2023-09-24 11:56:00 +08:00
parent 51899c4c13
commit 421bb7d154
21 changed files with 71 additions and 35 deletions

View File

@ -14,7 +14,7 @@
<name>${project.artifactId}</name>
<description>
错误码 ErrorCode 的自动配置功能,提供如下功能:
1. 远程读取:项目启动时,从 system-server 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提可配置;
1. 远程读取:项目启动时,从 system-server 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提可配置;
2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-server 服务加载最新的 ErrorCode 错误码;
3. 自动写入:项目启动时,将项目本地的错误码写到 system-server 服务中,方便管理员在管理后台编辑;
</description>

View File

@ -22,7 +22,9 @@ public enum BrokerageWithdrawStatusEnum implements IntArrayValuable {
WITHDRAW_FAIL(21, "提现失败"),
;
// TODO @疯狂字典现在枚举在每个模块的 DictTypeConstants 里哈可以创建一个出来主要是想治理每个模块到底有多少个枚举
public static final String DICT_TYPE = "BROKERAGE_WITHDRAW_STATUS";
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawStatusEnum::getStatus).toArray();
/**

View File

@ -45,6 +45,7 @@ public class AppBrokerageRecordController {
return success(BrokerageRecordConvert.INSTANCE.convertPage02(pageResult));
}
// TODO @疯狂这里还有一个漏网之鱼~
@GetMapping("/get-product-brokerage-price")
@Operation(summary = "获得商品的分销金额")
public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {

View File

@ -55,6 +55,7 @@ public class AppBrokerageUserController {
@PreAuthenticated
public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() {
Optional<BrokerageUserDO> user = Optional.ofNullable(brokerageUserService.getBrokerageUser(getLoginUserId()));
// 返回数据
AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO()
.setBrokerageEnabled(user.map(BrokerageUserDO::getBrokerageEnabled).orElse(false))
.setBrokeragePrice(user.map(BrokerageUserDO::getBrokeragePrice).orElse(0))
@ -66,6 +67,7 @@ public class AppBrokerageUserController {
@Operation(summary = "绑定推广员")
@PreAuthenticated
public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) {
// TODO @疯狂是不是 isNewUser 不用传递哈交给 service 自己计算出来
return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId(), false));
}
@ -74,17 +76,17 @@ public class AppBrokerageUserController {
@PreAuthenticated
public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() {
Long userId = getLoginUserId();
// 统计 yesterdayPricewithdrawPricefirstBrokerageUserCountsecondBrokerageUserCount 字段
LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(yesterday);
LocalDateTime endTime = LocalDateTimeUtil.endOfDay(yesterday);
AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO()
.setYesterdayPrice(brokerageRecordService.getSummaryPriceByUserId(userId, BrokerageRecordBizTypeEnum.ORDER.getType(), beginTime, endTime))
.setWithdrawPrice(brokerageWithdrawService.getSummaryPriceByUserIdAndStatus(userId, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus()))
.setBrokeragePrice(0)
.setFrozenPrice(0)
.setBrokeragePrice(0).setFrozenPrice(0)
.setFirstBrokerageUserCount(brokerageUserService.getBrokerageUserCountByBindUserId(userId, 1))
.setSecondBrokerageUserCount(brokerageUserService.getBrokerageUserCountByBindUserId(userId, 2));
// 设置 brokeragePricefrozenPrice 字段
Optional.ofNullable(brokerageUserService.getBrokerageUser(userId))
.ifPresent(user -> respVO.setBrokeragePrice(user.getBrokeragePrice()).setFrozenPrice(user.getFrozenPrice()));
return success(respVO);
@ -117,7 +119,6 @@ public class AppBrokerageUserController {
@PreAuthenticated
public CommonResult<PageResult<AppBrokerageUserChildSummaryRespVO>> getBrokerageUserChildSummaryPage(
AppBrokerageUserChildSummaryPageReqVO pageReqVO) {
// 分页查询
PageResult<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserService.getBrokerageUserChildSummaryPage(pageReqVO, getLoginUserId());
return success(pageResult);
}

View File

@ -30,6 +30,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLogi
@Validated
@Slf4j
public class AppBrokerageWithdrawController {
@Resource
private BrokerageWithdrawService brokerageWithdrawService;
@ -44,6 +45,7 @@ public class AppBrokerageWithdrawController {
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(
BrokerageWithdrawConvert.INSTANCE.convert(pageReqVO, getLoginUserId()));
// 拼接信息
// TODO @疯狂后端可以直接用 DictFrameworkUtils.getDictDataLabel() 去渲染哈这样就不用 getDictDataLabelMap 方法了
Map<String, String> statusNameMap = dictDataApi.getDictDataLabelMap(BrokerageWithdrawStatusEnum.DICT_TYPE);
return success(BrokerageWithdrawConvert.INSTANCE.convertPage02(pageResult, statusNameMap));
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.trade.controller.app.config.vo.AppTradeConfigRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -24,13 +25,15 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Validated
@Slf4j
public class AppTradeConfigController {
@Resource
private TradeConfigService tradeConfigService;
@GetMapping("/get")
@Operation(summary = "获得交易配置")
public CommonResult<AppTradeConfigRespVO> getTradeConfig() {
TradeConfigDO tradeConfig = ObjUtil.defaultIfNull(tradeConfigService.getTradeConfig(), new TradeConfigDO());
// TODO @疯狂是不是直接 convert 就好啦
AppTradeConfigRespVO respVO = new AppTradeConfigRespVO()
.setBrokeragePosterUrls(tradeConfig.getBrokeragePostUrls())
.setBrokerageFrozenDays(tradeConfig.getBrokerageFrozenDays())

View File

@ -18,6 +18,7 @@ public class AppTradeConfigRespVO {
@Schema(description = "佣金提现最小金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private Integer brokerageWithdrawMinPrice;
// TODO @疯狂如果是 list要不加个 s复数
@Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]")
private List<Integer> brokerageWithdrawType;

View File

@ -17,6 +17,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Validated
public class AppDeliverConfigController {
// TODO @芋艿这里后面干掉合并到 AppTradeConfigController
@GetMapping("/get")
@Operation(summary = "获得配送配置")
public CommonResult<AppDeliveryConfigRespVO> getDeliveryConfig() {

View File

@ -58,12 +58,12 @@ public interface BrokerageUserConvert {
return target;
}
default PageResult<AppBrokerageUserRankByUserCountRespVO> convertPage03(PageResult<AppBrokerageUserRankByUserCountRespVO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
for (AppBrokerageUserRankByUserCountRespVO vo : pageResult.getList()) {
copyTo(userMap.get(vo.getId()), vo);
}
default PageResult<AppBrokerageUserRankByUserCountRespVO> convertPage03(PageResult<AppBrokerageUserRankByUserCountRespVO> pageResult,
Map<Long, MemberUserRespDTO> userMap) {
pageResult.getList().forEach(vo -> copyTo(userMap.get(vo.getId()), vo));
return pageResult;
}
void copyTo(MemberUserRespDTO from, @MappingTarget AppBrokerageUserRankByUserCountRespVO to);
}

View File

@ -25,7 +25,6 @@ import java.util.List;
public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
// 分页查询
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
@ -59,7 +58,8 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
@Param("bizType") Integer bizType,
@Param("status") Integer status);
@Select("SELECT SUM(price) FROM trade_brokerage_record WHERE user_id = #{userId} AND biz_type = #{bizType} " +
@Select("SELECT SUM(price) FROM trade_brokerage_record " +
"WHERE user_id = #{userId} AND biz_type = #{bizType} " +
"AND create_time BETWEEN #{beginTime} AND #{endTime}")
Integer selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(@Param("userId") Long userId,
@Param("bizType") Integer bizType,
@ -76,4 +76,5 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
@Param("status") Integer status,
@Param("beginTime") LocalDateTime beginTime,
@Param("endTime") LocalDateTime endTime);
}

View File

@ -145,4 +145,5 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
default List<BrokerageUserDO> selectListByBindUserId(Long bindUserId) {
return selectList(BrokerageUserDO::getBindUserId, bindUserId);
}
}

View File

@ -36,6 +36,8 @@ public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO
.eq(BrokerageWithdrawDO::getStatus, status));
}
@Select("SELECT SUM(price) FROM trade_brokerage_withdraw WHERE user_id = #{userId} AND status = #{status}")
@Select("SELECT SUM(price) FROM trade_brokerage_withdraw " +
"WHERE user_id = #{userId} AND status = #{status}")
Integer selectSummaryPriceByUserIdAndStatus(@Param("userId") Long userId, @Param("status") Integer status);
}

View File

@ -37,7 +37,7 @@ public interface BrokerageRecordService {
PageResult<BrokerageRecordDO> getBrokerageRecordPage(BrokerageRecordPageReqVO pageReqVO);
/**
* 增加佣金
* 增加佣金多级分佣
*
* @param userId 会员编号
* @param bizType 业务类型
@ -46,7 +46,7 @@ public interface BrokerageRecordService {
void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, @Valid List<BrokerageAddReqBO> list);
/**
* 增加佣金
* 增加佣金只针对自己
*
* @param userId 会员编号
* @param bizType 业务类型
@ -95,6 +95,7 @@ public interface BrokerageRecordService {
/**
* 获得用户佣金排行分页列表基于佣金总数
*
* @param pageReqVO 分页查询
* @return 排行榜分页
*/
@ -108,4 +109,5 @@ public interface BrokerageRecordService {
* @return 用户的排名
*/
Integer getUserRankByPrice(Long userId, LocalDateTime[] times);
}

View File

@ -240,6 +240,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
}
// TODO @疯狂这个求出来应该是不准的例如说超过 100+ 名后
@Override
public Integer getUserRankByPrice(Long userId, LocalDateTime[] times) {
AppBrokerageUserRankPageReqVO pageParam = new AppBrokerageUserRankPageReqVO().setTimes(times);
@ -255,21 +256,23 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
@Override
@Transactional(rollbackFor = Exception.class)
public void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId, Integer brokeragePrice, String title) {
// 校验佣金余额
// 1. 校验佣金余额
BrokerageUserDO user = brokerageUserService.getBrokerageUser(userId);
int balance = Optional.of(user)
.map(BrokerageUserDO::getBrokeragePrice).orElse(0);
if (balance + brokeragePrice < 0) {
// TODO @疯狂要不 MoneyUtils 统一搞个 format 金额的方法然后把分到元的字符串统一收口掉
throw exception(BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH, new Money(0, balance));
}
// 扣减佣金余额
// 2. 更新佣金余额
boolean success = brokerageUserService.updateUserPrice(userId, brokeragePrice);
if (!success) {
// 失败时则抛出异常只会出现扣减佣金时余额不足的情况
throw exception(BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH, new Money(0, balance));
}
// 新增记录
// 3. 新增记录
BrokerageRecordDO record = BrokerageRecordConvert.INSTANCE.convert(user, bizType, bizId, 0, brokeragePrice,
null, title, null, null);
brokerageRecordMapper.insert(record);

View File

@ -67,7 +67,6 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
public void updateBrokerageUserId(Long id, Long bindUserId) {
// 校验存在
BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
// 绑定关系未发生变化
if (Objects.equals(brokerageUser.getBindUserId(), bindUserId)) {
return;
@ -185,6 +184,13 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return true;
}
/**
* 补全绑定用户的字段
*
* @param bindUserId 绑定的用户编号
* @param brokerageUser update 对象
* @return 补全后的 update 对象
*/
private BrokerageUserDO fillBindUserData(Long bindUserId, BrokerageUserDO brokerageUser) {
return brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
}
@ -255,6 +261,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
}
// 下级不能绑定自己的上级
// TODO @疯狂这里是不是查询不到的时候应该有个 break 结束循环哈
for (int i = 0; i <= Short.MAX_VALUE; i++) {
if (Objects.equals(bindUser.getBindUserId(), user.getId())) {
throw exception(BROKERAGE_BIND_LOOP);
@ -263,18 +270,24 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
}
}
/**
* 根据绑定用户编号获得绑定用户编号列表
*
* @param bindUserId 绑定用户编号
* @param level 绑定用户的层级
* 如果 level 为空则查询 1+2 两个层级
* @return 绑定用户编号列表
*/
private List<Long> buildBindUserIdsByLevel(Long bindUserId, Integer level) {
Assert.isTrue(level == null || level <= 2, "目前只支持 level 小于等于 2");
List<Long> bindUserIds = CollUtil.newArrayList();
if (level == null || level == 1) {
bindUserIds.add(bindUserId);
}
if (level == null || level == 2) {
List<Long> firstUserIds = convertList(brokerageUserMapper.selectListByBindUserId(bindUserId), BrokerageUserDO::getId);
bindUserIds.addAll(firstUserIds);
bindUserIds.addAll(convertList(brokerageUserMapper.selectListByBindUserId(bindUserId), BrokerageUserDO::getId));
}
return bindUserIds;
}
}

View File

@ -20,7 +20,6 @@ public interface BrokerageWithdrawService {
* @param status 审核状态
* @param auditReason 驳回原因
*/
void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason);
/**

View File

@ -4,8 +4,7 @@
<select id="selectSummaryPageByUserId"
resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
SELECT bu.id, bu.bind_user_time AS brokerageTime,
u.nickname, u.avatar,
SELECT bu.id, bu.bind_user_time AS brokerageTime, u.nickname, u.avatar,
(SELECT SUM(price) FROM trade_brokerage_record r
WHERE r.user_id = u.id AND biz_type = 1 AND r.status = 1 AND r.deleted = FALSE) AS brokeragePrice,
(SELECT COUNT(1) FROM trade_brokerage_record r
@ -22,8 +21,7 @@
AND bu.bind_user_id = #{userId}
</if>
<if test="param.level == 2">
AND bu.bind_user_id = (SELECT id FROM trade_brokerage_user c WHERE c.bind_user_id =
#{userId})
AND bu.bind_user_id IN (SELECT id FROM trade_brokerage_user c WHERE c.bind_user_id = #{userId})
</if>
</where>
<choose>
@ -41,4 +39,5 @@
</otherwise>
</choose>
</select>
</mapper>

View File

@ -38,6 +38,7 @@ public class DictDataApiImpl implements DictDataApi {
@Override
public List<DictDataRespDTO> getDictDataList(String type) {
// TODO @疯狂不用 DictDataExportReqVO 可以考虑直接加个允许传递 type 传递的
List<DictDataDO> list = dictDataService.getDictDataList(new DictDataExportReqVO().setDictType(type));
return DictDataConvert.INSTANCE.convertList04(list);
}

View File

@ -28,10 +28,12 @@ public class AppDictDataController {
@Resource
private DictDataService dictDataService;
// TODO @疯狂暂时不用 path 参数哈主要考虑一些中间件支持的一般例如说链路追踪之类的还是作为一个参数噶
@GetMapping("/type/{dictType}")
@Operation(summary = "根据字典类型查询字典数据信息")
public CommonResult<List<AppDictDataRespVO>> getDicts(@PathVariable String dictType) {
public CommonResult<List<AppDictDataRespVO>> getDictDataList(@PathVariable String dictType) {
List<DictDataDO> list = dictDataService.getDictDataList(new DictDataExportReqVO().setDictType(dictType));
return success(DictDataConvert.INSTANCE.convertList03(list));
}
}

View File

@ -14,6 +14,8 @@ import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
public class AppDictDataRespVO extends DictDataBaseVO {
// TODO @疯狂app 的接口不集成 admin 接口的 vo 看看是不是只返回必要的字段类似 remarksort 不好返回的哈
@Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;