code review:优惠劵逻辑

This commit is contained in:
YunaiV
2023-09-28 09:23:42 +08:00
parent 8811ce0200
commit 9e3564bd6a
24 changed files with 110 additions and 65 deletions

View File

@@ -44,4 +44,5 @@ public class CouponTemplatePageReqVO extends PageParam {
@Schema(description = "商品范围编号", example = "1")
private Long productScopeValue;
}

View File

@@ -41,13 +41,15 @@ public class AppCouponController {
@Operation(summary = "领取优惠劵")
@Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024")
public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) {
Long userId = getLoginUserId();
// 领取
Long userId = getLoginUserId();
couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER);
// 检查是否可以继续领取
CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId());
boolean canTakeAgain = true;
if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) {
// TODO @疯狂:要不要搞个 getTakeCount 方法?
Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds(
Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0);
canTakeAgain = takeCount < couponTemplate.getTakeLimitCount();
@@ -58,7 +60,7 @@ public class AppCouponController {
@GetMapping("/match-list")
@Operation(summary = "获得匹配指定商品的优惠劵列表")
public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) {
// todo: 优惠金额倒序
// todo: 优化:优惠金额倒序
return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO)));
}

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO;
@@ -45,12 +46,14 @@ public class AppCouponTemplateController {
@Operation(summary = "获得优惠劵模版分页")
public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
// 1.1 处理查询条件:商品范围编号
Long productScopeValue = getaProductScopeValue(pageReqVO);
// 1.2 处理查询条件:领取方式=直接领取
Long productScopeValue = getProductScopeValue(pageReqVO);
// 1.2 处理查询条件:领取方式 = 直接领取
List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
// 2. 分页查询
PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(
CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue));
// 3.1 领取数量
Map<Long, Integer> couponTakeCountMap = new HashMap<>(0);
Long userId = getLoginUserId();
@@ -63,17 +66,24 @@ public class AppCouponTemplateController {
return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap));
}
private Long getaProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {
Long productScopeValue = pageReqVO.getSpuId();
if (pageReqVO.getProductScope() == null || Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope())) {
// 通用券:清除商品范围
productScopeValue = null;
} else if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {
// 品类券:查询商品的品类
productScopeValue = Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId()))
/**
* 获得分页查询的商品范围
*
* @param pageReqVO 分页查询
* @return 商品范围
*/
private Long getProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {
// 通用券:清除商品范围
if (pageReqVO.getProductScope() == null || ObjectUtils.equalsAny(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope(), null)) {
return null;
}
// 品类券:查询商品的品类
if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {
return Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId()))
.map(ProductSpuRespDTO::getCategoryId).orElse(null);
}
return productScopeValue;
// 商品卷:直接返回
return pageReqVO.getSpuId();
}
}

View File

@@ -20,4 +20,5 @@ public class AppCouponTemplatePageReqVO extends PageParam {
@Schema(description = "商品标号", example = "1")
private Long spuId;
}

View File

@@ -61,4 +61,5 @@ public interface CouponConvert {
PageResult<AppCouponRespVO> convertAppPage(PageResult<CouponDO> pageResult);
List<AppCouponMatchRespVO> convertList(List<CouponDO> list);
}

View File

@@ -42,16 +42,16 @@ public interface CouponTemplateConvert {
if (MapUtil.isEmpty(couponTakeCountMap)) {
return result;
}
for (AppCouponTemplateRespVO vo : result.getList()) {
for (AppCouponTemplateRespVO template : result.getList()) {
// 每人领取数量无限制
if (vo.getTakeLimitCount() == -1) {
vo.setTakeStatus(false);
if (template.getTakeLimitCount() == -1) {
template.setTakeStatus(false);
continue;
}
// 检查已领取数量是否超过限领数量
vo.setTakeStatus(MapUtil.getInt(couponTakeCountMap, vo.getId(), 0) >= vo.getTakeLimitCount());
template.setTakeStatus(MapUtil.getInt(couponTakeCountMap, template.getId(), 0) >= template.getTakeLimitCount());
}
return result;
}
}

View File

@@ -70,6 +70,7 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
);
}
// TODO @疯狂:这个是不是搞个 Map 就可以呀?
default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class)
.select(CouponDO::getTemplateId)
@@ -81,18 +82,17 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope(
Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) {
Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
.map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
.collect(Collectors.joining(" OR "));
return selectList(new LambdaQueryWrapperX<CouponDO>()
.eq(CouponDO::getUserId, userId)
.eq(CouponDO::getStatus, status)
.le(CouponDO::getUsePrice, usePrice)
.and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope())
.or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope())
.le(CouponDO::getUsePrice, usePrice) // 价格小于等于,满足价格使用条件
.and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) // 商品范围一:全部
.or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) // 商品范围二:满足指定商品
.apply(productScopeValuesFindInSetFunc.apply(spuIds)))
.or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope())
.or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) // 商品范围三:满足指定分类
.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))));
}
@@ -102,4 +102,5 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
.le(CouponDO::getValidEndTime, validEndTime)
);
}
}

View File

@@ -137,7 +137,8 @@ public interface CouponService {
* @return 领取优惠券的数量
*/
default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
return convertMap(getTakeCountListByTemplateIds(templateIds, userId), CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount);
return convertMap(getTakeCountListByTemplateIds(templateIds, userId),
CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount);
}
/**

View File

@@ -222,13 +222,12 @@ public class CouponServiceImpl implements CouponService {
private boolean expireCoupon(CouponDO coupon) {
// 更新记录状态
CouponDO updateObj = new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus());
int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), updateObj);
int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(),
new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus()));
if (updateRows == 0) {
log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId());
return false;
}
log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId());
return true;
}

View File

@@ -9,6 +9,7 @@ import lombok.Data;
*/
@Data
public class CouponTakeCountBO {
/**
* 优惠劵模板编号
*/
@@ -17,4 +18,5 @@ public class CouponTakeCountBO {
* 领取数量
*/
private Integer count;
}