Commit 9e3564bd6acf729f75ef2d2be21e32a350a30989
1 parent
8811ce02
code review:优惠劵逻辑
Showing
24 changed files
with
110 additions
and
65 deletions
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java
| ... | ... | @@ -41,13 +41,15 @@ public class AppCouponController { |
| 41 | 41 | @Operation(summary = "领取优惠劵") |
| 42 | 42 | @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024") |
| 43 | 43 | public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) { |
| 44 | - Long userId = getLoginUserId(); | |
| 45 | 44 | // 领取 |
| 45 | + Long userId = getLoginUserId(); | |
| 46 | 46 | couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); |
| 47 | + | |
| 47 | 48 | // 检查是否可以继续领取 |
| 48 | 49 | CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId()); |
| 49 | 50 | boolean canTakeAgain = true; |
| 50 | 51 | if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) { |
| 52 | + // TODO @疯狂:要不要搞个 getTakeCount 方法? | |
| 51 | 53 | Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds( |
| 52 | 54 | Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0); |
| 53 | 55 | canTakeAgain = takeCount < couponTemplate.getTakeLimitCount(); |
| ... | ... | @@ -58,7 +60,7 @@ public class AppCouponController { |
| 58 | 60 | @GetMapping("/match-list") |
| 59 | 61 | @Operation(summary = "获得匹配指定商品的优惠劵列表") |
| 60 | 62 | public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { |
| 61 | - // todo: 优惠金额倒序 | |
| 63 | + // todo: 优化:优惠金额倒序 | |
| 62 | 64 | return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO))); |
| 63 | 65 | } |
| 64 | 66 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon; |
| 3 | 3 | import cn.hutool.core.util.ObjUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | |
| 6 | 7 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 7 | 8 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 8 | 9 | import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; |
| ... | ... | @@ -45,12 +46,14 @@ public class AppCouponTemplateController { |
| 45 | 46 | @Operation(summary = "获得优惠劵模版分页") |
| 46 | 47 | public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) { |
| 47 | 48 | // 1.1 处理查询条件:商品范围编号 |
| 48 | - Long productScopeValue = getaProductScopeValue(pageReqVO); | |
| 49 | - // 1.2 处理查询条件:领取方式=直接领取 | |
| 49 | + Long productScopeValue = getProductScopeValue(pageReqVO); | |
| 50 | + // 1.2 处理查询条件:领取方式 = 直接领取 | |
| 50 | 51 | List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue()); |
| 52 | + | |
| 51 | 53 | // 2. 分页查询 |
| 52 | 54 | PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage( |
| 53 | 55 | CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue)); |
| 56 | + | |
| 54 | 57 | // 3.1 领取数量 |
| 55 | 58 | Map<Long, Integer> couponTakeCountMap = new HashMap<>(0); |
| 56 | 59 | Long userId = getLoginUserId(); |
| ... | ... | @@ -63,17 +66,24 @@ public class AppCouponTemplateController { |
| 63 | 66 | return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap)); |
| 64 | 67 | } |
| 65 | 68 | |
| 66 | - private Long getaProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) { | |
| 67 | - Long productScopeValue = pageReqVO.getSpuId(); | |
| 68 | - if (pageReqVO.getProductScope() == null || Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope())) { | |
| 69 | - // 通用券:清除商品范围 | |
| 70 | - productScopeValue = null; | |
| 71 | - } else if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) { | |
| 72 | - // 品类券:查询商品的品类 | |
| 73 | - productScopeValue = Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId())) | |
| 69 | + /** | |
| 70 | + * 获得分页查询的商品范围 | |
| 71 | + * | |
| 72 | + * @param pageReqVO 分页查询 | |
| 73 | + * @return 商品范围 | |
| 74 | + */ | |
| 75 | + private Long getProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) { | |
| 76 | + // 通用券:清除商品范围 | |
| 77 | + if (pageReqVO.getProductScope() == null || ObjectUtils.equalsAny(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope(), null)) { | |
| 78 | + return null; | |
| 79 | + } | |
| 80 | + // 品类券:查询商品的品类 | |
| 81 | + if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) { | |
| 82 | + return Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId())) | |
| 74 | 83 | .map(ProductSpuRespDTO::getCategoryId).orElse(null); |
| 75 | 84 | } |
| 76 | - return productScopeValue; | |
| 85 | + // 商品卷:直接返回 | |
| 86 | + return pageReqVO.getSpuId(); | |
| 77 | 87 | } |
| 78 | 88 | |
| 79 | 89 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java
| ... | ... | @@ -42,16 +42,16 @@ public interface CouponTemplateConvert { |
| 42 | 42 | if (MapUtil.isEmpty(couponTakeCountMap)) { |
| 43 | 43 | return result; |
| 44 | 44 | } |
| 45 | - | |
| 46 | - for (AppCouponTemplateRespVO vo : result.getList()) { | |
| 45 | + for (AppCouponTemplateRespVO template : result.getList()) { | |
| 47 | 46 | // 每人领取数量无限制 |
| 48 | - if (vo.getTakeLimitCount() == -1) { | |
| 49 | - vo.setTakeStatus(false); | |
| 47 | + if (template.getTakeLimitCount() == -1) { | |
| 48 | + template.setTakeStatus(false); | |
| 50 | 49 | continue; |
| 51 | 50 | } |
| 52 | 51 | // 检查已领取数量是否超过限领数量 |
| 53 | - vo.setTakeStatus(MapUtil.getInt(couponTakeCountMap, vo.getId(), 0) >= vo.getTakeLimitCount()); | |
| 52 | + template.setTakeStatus(MapUtil.getInt(couponTakeCountMap, template.getId(), 0) >= template.getTakeLimitCount()); | |
| 54 | 53 | } |
| 55 | 54 | return result; |
| 56 | 55 | } |
| 56 | + | |
| 57 | 57 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
| ... | ... | @@ -70,6 +70,7 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { |
| 70 | 70 | ); |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | + // TODO @疯狂:这个是不是搞个 Map 就可以呀? | |
| 73 | 74 | default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) { |
| 74 | 75 | return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class) |
| 75 | 76 | .select(CouponDO::getTemplateId) |
| ... | ... | @@ -81,18 +82,17 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { |
| 81 | 82 | |
| 82 | 83 | default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope( |
| 83 | 84 | Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) { |
| 84 | - | |
| 85 | 85 | Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() |
| 86 | 86 | .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) |
| 87 | 87 | .collect(Collectors.joining(" OR ")); |
| 88 | 88 | return selectList(new LambdaQueryWrapperX<CouponDO>() |
| 89 | 89 | .eq(CouponDO::getUserId, userId) |
| 90 | 90 | .eq(CouponDO::getStatus, status) |
| 91 | - .le(CouponDO::getUsePrice, usePrice) | |
| 92 | - .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) | |
| 93 | - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) | |
| 91 | + .le(CouponDO::getUsePrice, usePrice) // 价格小于等于,满足价格使用条件 | |
| 92 | + .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) // 商品范围一:全部 | |
| 93 | + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) // 商品范围二:满足指定商品 | |
| 94 | 94 | .apply(productScopeValuesFindInSetFunc.apply(spuIds))) |
| 95 | - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) | |
| 95 | + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) // 商品范围三:满足指定分类 | |
| 96 | 96 | .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); |
| 97 | 97 | } |
| 98 | 98 | |
| ... | ... | @@ -102,4 +102,5 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { |
| 102 | 102 | .le(CouponDO::getValidEndTime, validEndTime) |
| 103 | 103 | ); |
| 104 | 104 | } |
| 105 | + | |
| 105 | 106 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
| ... | ... | @@ -137,7 +137,8 @@ public interface CouponService { |
| 137 | 137 | * @return 领取优惠券的数量 |
| 138 | 138 | */ |
| 139 | 139 | default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) { |
| 140 | - return convertMap(getTakeCountListByTemplateIds(templateIds, userId), CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount); | |
| 140 | + return convertMap(getTakeCountListByTemplateIds(templateIds, userId), | |
| 141 | + CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount); | |
| 141 | 142 | } |
| 142 | 143 | |
| 143 | 144 | /** | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
| ... | ... | @@ -222,13 +222,12 @@ public class CouponServiceImpl implements CouponService { |
| 222 | 222 | |
| 223 | 223 | private boolean expireCoupon(CouponDO coupon) { |
| 224 | 224 | // 更新记录状态 |
| 225 | - CouponDO updateObj = new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus()); | |
| 226 | - int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), updateObj); | |
| 225 | + int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), | |
| 226 | + new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus())); | |
| 227 | 227 | if (updateRows == 0) { |
| 228 | 228 | log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId()); |
| 229 | 229 | return false; |
| 230 | 230 | } |
| 231 | - | |
| 232 | 231 | log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId()); |
| 233 | 232 | return true; |
| 234 | 233 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/bo/CouponTakeCountBO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
| ... | ... | @@ -42,6 +42,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti |
| 42 | 42 | @Validated |
| 43 | 43 | @Slf4j |
| 44 | 44 | public class AppBrokerageUserController { |
| 45 | + | |
| 45 | 46 | @Resource |
| 46 | 47 | private BrokerageUserService brokerageUserService; |
| 47 | 48 | @Resource |
| ... | ... | @@ -69,8 +70,7 @@ public class AppBrokerageUserController { |
| 69 | 70 | @Operation(summary = "绑定推广员") |
| 70 | 71 | @PreAuthenticated |
| 71 | 72 | public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) { |
| 72 | - MemberUserRespDTO user = memberUserApi.getUser(getLoginUserId()); | |
| 73 | - return success(brokerageUserService.bindBrokerageUser(user.getId(), reqVO.getBindUserId(), user.getCreateTime())); | |
| 73 | + return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId())); | |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | @GetMapping("/get-summary") |
| ... | ... | @@ -86,7 +86,7 @@ public class AppBrokerageUserController { |
| 86 | 86 | Integer yesterdayPrice = brokerageRecordService.getSummaryPriceByUserId(brokerageUser.getId(), |
| 87 | 87 | BrokerageRecordBizTypeEnum.ORDER.getType(), beginTime, endTime); |
| 88 | 88 | // 统计用户提现的佣金 |
| 89 | - Integer withdrawPrice = brokerageWithdrawService.getWithdrawSummaryByUserId(Collections.singleton(brokerageUser.getId()), | |
| 89 | + Integer withdrawPrice = brokerageWithdrawService.getWithdrawSummaryListByUserId(Collections.singleton(brokerageUser.getId()), | |
| 90 | 90 | BrokerageWithdrawStatusEnum.AUDIT_SUCCESS).stream() |
| 91 | 91 | .findFirst().map(UserWithdrawSummaryBO::getPrice).orElse(0); |
| 92 | 92 | // 统计分销用户数量(一级) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java
| ... | ... | @@ -68,6 +68,7 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { |
| 68 | 68 | .eq(BrokerageRecordDO::getStatus, status) |
| 69 | 69 | .groupBy(BrokerageRecordDO::getUserId)); |
| 70 | 70 | return BeanUtil.copyToList(list, UserBrokerageSummaryBO.class); |
| 71 | + // selectJoinList有BUG,会与租户插件冲突:解析SQL时,发生异常 https://gitee.com/best_handsome/mybatis-plus-join/issues/I84GYW | |
| 71 | 72 | // return selectJoinList(UserBrokerageSummaryBO.class, MPJWrappers.lambdaJoin(BrokerageRecordDO.class) |
| 72 | 73 | // .select(BrokerageRecordDO::getUserId) |
| 73 | 74 | // .selectCount(BrokerageRecordDO::getId, UserBrokerageSummaryBO::getCount) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java
| ... | ... | @@ -78,25 +78,25 @@ public interface BrokerageRecordService { |
| 78 | 78 | int unfreezeRecord(); |
| 79 | 79 | |
| 80 | 80 | /** |
| 81 | - * 汇总用户佣金 | |
| 81 | + * 按照 userId,汇总每个用户的佣金 | |
| 82 | 82 | * |
| 83 | 83 | * @param userIds 用户编号 |
| 84 | 84 | * @param bizType 业务类型 |
| 85 | 85 | * @param status 佣金状态 |
| 86 | - * @return 用户佣金汇总 | |
| 86 | + * @return 用户佣金汇总 List | |
| 87 | 87 | */ |
| 88 | - List<UserBrokerageSummaryBO> getUserBrokerageSummaryByUserId(Collection<Long> userIds, Integer bizType, Integer status); | |
| 88 | + List<UserBrokerageSummaryBO> getUserBrokerageSummaryListByUserId(Collection<Long> userIds, Integer bizType, Integer status); | |
| 89 | 89 | |
| 90 | 90 | /** |
| 91 | - * 汇总用户佣金 | |
| 91 | + * 按照 userId,汇总每个用户的佣金 | |
| 92 | 92 | * |
| 93 | 93 | * @param userIds 用户编号 |
| 94 | 94 | * @param bizType 业务类型 |
| 95 | 95 | * @param status 佣金状态 |
| 96 | - * @return 用户佣金汇总 | |
| 96 | + * @return 用户佣金汇总 Map | |
| 97 | 97 | */ |
| 98 | 98 | default Map<Long, UserBrokerageSummaryBO> getUserBrokerageSummaryMapByUserId(Collection<Long> userIds, Integer bizType, Integer status) { |
| 99 | - return convertMap(getUserBrokerageSummaryByUserId(userIds, bizType, status), UserBrokerageSummaryBO::getUserId); | |
| 99 | + return convertMap(getUserBrokerageSummaryListByUserId(userIds, bizType, status), UserBrokerageSummaryBO::getUserId); | |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | 102 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
| ... | ... | @@ -232,7 +232,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | 234 | @Override |
| 235 | - public List<UserBrokerageSummaryBO> getUserBrokerageSummaryByUserId(Collection<Long> userIds, Integer bizType, Integer status) { | |
| 235 | + public List<UserBrokerageSummaryBO> getUserBrokerageSummaryListByUserId(Collection<Long> userIds, Integer bizType, Integer status) { | |
| 236 | 236 | return brokerageRecordMapper.selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(userIds, bizType, status); |
| 237 | 237 | } |
| 238 | 238 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java
| ... | ... | @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokera |
| 9 | 9 | import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; |
| 10 | 10 | |
| 11 | 11 | import javax.validation.constraints.NotNull; |
| 12 | -import java.time.LocalDateTime; | |
| 13 | 12 | import java.util.Collection; |
| 14 | 13 | import java.util.List; |
| 15 | 14 | |
| ... | ... | @@ -107,10 +106,9 @@ public interface BrokerageUserService { |
| 107 | 106 | * |
| 108 | 107 | * @param userId 用户编号 |
| 109 | 108 | * @param bindUserId 推广员编号 |
| 110 | - * @param registerTime 用户注册时间 | |
| 111 | 109 | * @return 是否绑定 |
| 112 | 110 | */ |
| 113 | - boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime); | |
| 111 | + boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId); | |
| 114 | 112 | |
| 115 | 113 | /** |
| 116 | 114 | * 获取用户是否有分销资格 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
| ... | ... | @@ -7,6 +7,8 @@ import cn.hutool.core.util.BooleanUtil; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 9 | 9 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 10 | +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | |
| 11 | +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | |
| 10 | 12 | import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; |
| 11 | 13 | import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO; |
| 12 | 14 | import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; |
| ... | ... | @@ -48,6 +50,9 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 48 | 50 | @Resource |
| 49 | 51 | private TradeConfigService tradeConfigService; |
| 50 | 52 | |
| 53 | + @Resource | |
| 54 | + private MemberUserApi memberUserApi; | |
| 55 | + | |
| 51 | 56 | @Override |
| 52 | 57 | public BrokerageUserDO getBrokerageUser(Long id) { |
| 53 | 58 | return brokerageUserMapper.selectById(id); |
| ... | ... | @@ -155,7 +160,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 155 | 160 | } |
| 156 | 161 | |
| 157 | 162 | @Override |
| 158 | - public boolean bindBrokerageUser(Long userId, Long bindUserId, LocalDateTime registerTime) { | |
| 163 | + public boolean bindBrokerageUser(Long userId, Long bindUserId) { | |
| 159 | 164 | // 1. 获得分销用户 |
| 160 | 165 | boolean isNewBrokerageUser = false; |
| 161 | 166 | BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); |
| ... | ... | @@ -165,7 +170,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 165 | 170 | } |
| 166 | 171 | |
| 167 | 172 | // 2.1 校验是否能绑定用户 |
| 168 | - boolean validated = isUserCanBind(brokerageUser, registerTime); | |
| 173 | + boolean validated = isUserCanBind(brokerageUser); | |
| 169 | 174 | if (!validated) { |
| 170 | 175 | return false; |
| 171 | 176 | } |
| ... | ... | @@ -223,7 +228,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 223 | 228 | return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); |
| 224 | 229 | } |
| 225 | 230 | |
| 226 | - private boolean isUserCanBind(BrokerageUserDO user, LocalDateTime registerTime) { | |
| 231 | + private boolean isUserCanBind(BrokerageUserDO user) { | |
| 227 | 232 | // 校验分销功能是否启用 |
| 228 | 233 | TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); |
| 229 | 234 | if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { |
| ... | ... | @@ -237,9 +242,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 237 | 242 | |
| 238 | 243 | // 校验分销关系绑定模式 |
| 239 | 244 | if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) { |
| 240 | - // 判断是否为新用户:注册时间在30秒内的,都算新用户 | |
| 241 | - boolean isNotNewUser = LocalDateTimeUtils.beforeNow(registerTime.plusSeconds(30)); | |
| 242 | - if (isNotNewUser) { | |
| 245 | + // 判断是否为新用户:注册时间在 30 秒内的,都算新用户 | |
| 246 | + if (!isNewRegisterUser(user.getId())) { | |
| 243 | 247 | throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定 |
| 244 | 248 | } |
| 245 | 249 | } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) { |
| ... | ... | @@ -247,14 +251,29 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 247 | 251 | throw exception(BROKERAGE_BIND_OVERRIDE); // 已绑定了推广人 |
| 248 | 252 | } |
| 249 | 253 | } |
| 250 | - | |
| 251 | 254 | return true; |
| 252 | 255 | } |
| 253 | 256 | |
| 257 | + /** | |
| 258 | + * 判断是否为新用户 | |
| 259 | + * | |
| 260 | + * 标准:注册时间在 30 秒内的,都算新用户 | |
| 261 | + * | |
| 262 | + * 疑问:为什么通过这样的方式实现? | |
| 263 | + * 回答:因为注册在 member 模块,希望它和 trade 模块解耦,所以只能用这种约定的逻辑。 | |
| 264 | + * | |
| 265 | + * @param userId 用户编号 | |
| 266 | + * @return 是否新用户 | |
| 267 | + */ | |
| 268 | + private boolean isNewRegisterUser(Long userId) { | |
| 269 | + MemberUserRespDTO user = memberUserApi.getUser(userId); | |
| 270 | + return user != null && LocalDateTimeUtils.beforeNow(user.getCreateTime().plusSeconds(30)); | |
| 271 | + } | |
| 272 | + | |
| 254 | 273 | private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) { |
| 255 | 274 | // 校验要绑定的用户有无推广资格 |
| 256 | 275 | BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); |
| 257 | - if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) { | |
| 276 | + if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) { | |
| 258 | 277 | throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); |
| 259 | 278 | } |
| 260 | 279 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java
| ... | ... | @@ -56,22 +56,23 @@ public interface BrokerageWithdrawService { |
| 56 | 56 | Long createBrokerageWithdraw(AppBrokerageWithdrawCreateReqVO createReqVO, Long userId); |
| 57 | 57 | |
| 58 | 58 | /** |
| 59 | - * 汇总用户提现 | |
| 59 | + * 按照 userId,汇总每个用户的提现 | |
| 60 | 60 | * |
| 61 | 61 | * @param userIds 用户编号 |
| 62 | 62 | * @param status 提现状态 |
| 63 | - * @return 用户提现汇总 | |
| 63 | + * @return 用户提现汇总 List | |
| 64 | 64 | */ |
| 65 | - List<UserWithdrawSummaryBO> getWithdrawSummaryByUserId(Collection<Long> userIds, BrokerageWithdrawStatusEnum status); | |
| 65 | + List<UserWithdrawSummaryBO> getWithdrawSummaryListByUserId(Collection<Long> userIds, BrokerageWithdrawStatusEnum status); | |
| 66 | 66 | |
| 67 | 67 | /** |
| 68 | - * 汇总用户提现 | |
| 68 | + * 按照 userId,汇总每个用户的提现 | |
| 69 | 69 | * |
| 70 | 70 | * @param userIds 用户编号 |
| 71 | 71 | * @param status 提现状态 |
| 72 | - * @return 用户提现汇总 | |
| 72 | + * @return 用户提现汇总 Map | |
| 73 | 73 | */ |
| 74 | 74 | default Map<Long, UserWithdrawSummaryBO> getWithdrawSummaryMapByUserId(Set<Long> userIds, BrokerageWithdrawStatusEnum status) { |
| 75 | - return convertMap(getWithdrawSummaryByUserId(userIds, status), UserWithdrawSummaryBO::getUserId); | |
| 75 | + return convertMap(getWithdrawSummaryListByUserId(userIds, status), UserWithdrawSummaryBO::getUserId); | |
| 76 | 76 | } |
| 77 | + | |
| 77 | 78 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
| ... | ... | @@ -144,7 +144,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | @Override |
| 147 | - public List<UserWithdrawSummaryBO> getWithdrawSummaryByUserId(Collection<Long> userIds, BrokerageWithdrawStatusEnum status) { | |
| 147 | + public List<UserWithdrawSummaryBO> getWithdrawSummaryListByUserId(Collection<Long> userIds, BrokerageWithdrawStatusEnum status) { | |
| 148 | 148 | return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); |
| 149 | 149 | } |
| 150 | 150 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java
| ... | ... | @@ -13,12 +13,13 @@ import lombok.NoArgsConstructor; |
| 13 | 13 | @NoArgsConstructor |
| 14 | 14 | @AllArgsConstructor |
| 15 | 15 | public class UserBrokerageSummaryBO { |
| 16 | + | |
| 16 | 17 | /** |
| 17 | 18 | * 用户编号 |
| 18 | 19 | */ |
| 19 | 20 | private Long userId; |
| 20 | 21 | /** |
| 21 | - * 佣金数量 | |
| 22 | + * 推广数量 | |
| 22 | 23 | */ |
| 23 | 24 | private Integer count; |
| 24 | 25 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| ... | ... | @@ -753,6 +753,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 753 | 753 | |
| 754 | 754 | @Override |
| 755 | 755 | public void updateOrderItemWhenAfterSaleCreate(Long id, Long afterSaleId) { |
| 756 | + // TODO @疯狂:这个可以直接在接口上,写 @Null 参数校验; | |
| 756 | 757 | if (afterSaleId == null) { |
| 757 | 758 | throw new IllegalArgumentException(StrUtil.format("id({}) 退款发起,售后单编号不能为空", id)); |
| 758 | 759 | } |
| ... | ... | @@ -765,6 +766,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 765 | 766 | @Override |
| 766 | 767 | @Transactional(rollbackFor = Exception.class) |
| 767 | 768 | public void updateOrderItemWhenAfterSaleSuccess(Long id, Integer refundPrice) { |
| 769 | + // TODO @疯狂:这个可以直接在接口上,写 @Null 参数校验; | |
| 768 | 770 | if (refundPrice == null) { |
| 769 | 771 | throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id)); |
| 770 | 772 | } |
| ... | ... | @@ -787,15 +789,17 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 787 | 789 | } |
| 788 | 790 | |
| 789 | 791 | // TODO 芋艿:这块扣减规则,需要在考虑下 |
| 790 | - // 3.1 回滚数据:增加 SKU 库存 | |
| 792 | + // 3. 回滚数据:增加 SKU 库存 | |
| 791 | 793 | productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(Collections.singletonList(orderItem))); |
| 792 | - // 3.2 回滚数据:扣减用户积分(赠送的) | |
| 794 | + | |
| 795 | + // 4.1 回滚数据:扣减用户积分(赠送的) | |
| 793 | 796 | reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, orderItem.getAfterSaleId()); |
| 794 | - // 3.3 回滚数据:增加用户积分(返还抵扣) | |
| 797 | + // 4.2 回滚数据:增加用户积分(返还抵扣) | |
| 795 | 798 | addUserPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.AFTER_SALE_REFUND_USED, orderItem.getAfterSaleId()); |
| 796 | - // 3.4 回滚数据:扣减用户经验 | |
| 799 | + // 4.3 回滚数据:扣减用户经验 | |
| 797 | 800 | getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, orderItem.getAfterSaleId()); |
| 798 | - // 3.5 回滚数据:更新分佣记录为已失效 | |
| 801 | + | |
| 802 | + // 5. 回滚数据:更新分佣记录为已失效 | |
| 799 | 803 | getSelf().cancelBrokerageAsync(order.getUserId(), id); |
| 800 | 804 | } |
| 801 | 805 | |
| ... | ... | @@ -826,7 +830,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 826 | 830 | couponApi.returnUsedCoupon(order.getCouponId()); |
| 827 | 831 | } |
| 828 | 832 | |
| 829 | - | |
| 830 | 833 | /** |
| 831 | 834 | * 判断指定订单的所有订单项,是不是都售后成功 |
| 832 | 835 | * | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
| ... | ... | @@ -87,10 +87,11 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { |
| 87 | 87 | if (config.getTradeDeductMaxPrice() != null && config.getTradeDeductMaxPrice() > 0) { |
| 88 | 88 | usePoint = Math.min(usePoint, config.getTradeDeductMaxPrice()); |
| 89 | 89 | } |
| 90 | + // TODO @疯狂:这里应该是,抵扣到只剩下 0.01; | |
| 90 | 91 | // 积分优惠金额(分) |
| 91 | 92 | int pointPrice = usePoint * config.getTradeDeductUnitPrice(); |
| 92 | 93 | if (result.getPrice().getPayPrice() <= pointPrice) { |
| 93 | - // 禁止0元购 | |
| 94 | + // 禁止 0 元购 | |
| 94 | 95 | throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); |
| 95 | 96 | } |
| 96 | 97 | // // 允许0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分 | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
| ... | ... | @@ -190,7 +190,7 @@ public class MemberUserServiceImpl implements MemberUserService { |
| 190 | 190 | @Transactional(rollbackFor = Exception.class) |
| 191 | 191 | public void updateUser(MemberUserUpdateReqVO updateReqVO) { |
| 192 | 192 | // 校验存在 |
| 193 | - MemberUserDO user = validateUserExists(updateReqVO.getId()); | |
| 193 | + validateUserExists(updateReqVO.getId()); | |
| 194 | 194 | // 校验手机唯一 |
| 195 | 195 | validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile()); |
| 196 | 196 | ... | ... |