优惠券:重构是否领取检查方式
This commit is contained in:
parent
aaa01de21d
commit
d2c5eaf916
@ -1,6 +1,5 @@
|
||||
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;
|
||||
@ -25,11 +24,9 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
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.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "用户 App - 优惠劵模板")
|
||||
@ -46,7 +43,6 @@ public class AppCouponTemplateController {
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
// TODO 疯狂:这里应该还有个 list 接口哈;获得优惠劵模版列表,用于首页、商品页的优惠劵
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得优惠劵模版列表")
|
||||
@Parameters({
|
||||
@ -56,46 +52,28 @@ public class AppCouponTemplateController {
|
||||
})
|
||||
public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(
|
||||
@RequestParam(value = "spuId", required = false) Long spuId,
|
||||
@RequestParam(value = "useType", required = false) Integer useType,
|
||||
@RequestParam(value = "productScope", required = false) Integer productScope,
|
||||
@RequestParam(value = "count", required = false, defaultValue = "10") Integer count) {
|
||||
List<AppCouponTemplateRespVO> list = new ArrayList<>();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO();
|
||||
vo.setId(i + 1L);
|
||||
vo.setName("优惠劵" + (i + 1));
|
||||
vo.setTakeLimitCount(random.nextInt(10) + 1);
|
||||
vo.setUsePrice(random.nextInt(100) * 100);
|
||||
vo.setValidityType(random.nextInt(2) + 1);
|
||||
if (vo.getValidityType() == 1) {
|
||||
vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10)));
|
||||
vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10));
|
||||
} else {
|
||||
vo.setFixedStartTerm(random.nextInt(10));
|
||||
vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1);
|
||||
}
|
||||
vo.setDiscountType(random.nextInt(2) + 1);
|
||||
if (vo.getDiscountType() == 1) {
|
||||
vo.setDiscountPercent(null);
|
||||
vo.setDiscountPrice(random.nextInt(50) * 100);
|
||||
vo.setDiscountLimitPrice(null);
|
||||
} else {
|
||||
vo.setDiscountPercent(random.nextInt(90) + 10);
|
||||
vo.setDiscountPrice(null);
|
||||
vo.setDiscountLimitPrice(random.nextInt(200) * 100);
|
||||
}
|
||||
// TODO @疯狂:是否已领取,要不在 TemplateService 搞个 static 方法,让它基于 countMap 这种去计算,这样好点?
|
||||
vo.setTakeStatus(random.nextBoolean());
|
||||
list.add(vo);
|
||||
}
|
||||
return success(list);
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(productScope, spuId);
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
|
||||
// 2. 查询
|
||||
List<CouponTemplateDO> list = couponTemplateService.getCouponTemplateList(canTakeTypes, productScope,
|
||||
productScopeValue, count);
|
||||
|
||||
// 3.1 领取数量
|
||||
Map<Long, Boolean> canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), list);
|
||||
// 3.2 拼接返回
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppList(list, canCanTakeMap));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得优惠劵模版分页")
|
||||
public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(pageReqVO);
|
||||
Long productScopeValue = getProductScopeValue(pageReqVO.getProductScope(), pageReqVO.getSpuId());
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
|
||||
@ -104,35 +82,30 @@ public class AppCouponTemplateController {
|
||||
CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue));
|
||||
|
||||
// 3.1 领取数量
|
||||
Map<Long, Integer> couponTakeCountMap = new HashMap<>(0);
|
||||
Long userId = getLoginUserId();
|
||||
if (userId != null) {
|
||||
List<Long> templateIds = convertList(pageResult.getList(), CouponTemplateDO::getId,
|
||||
t -> ObjUtil.notEqual(t.getTakeLimitCount(), -1)); // 只查有设置“每人限领个数”的
|
||||
couponTakeCountMap = couponService.getTakeCountMapByTemplateIds(templateIds, userId);
|
||||
}
|
||||
Map<Long, Boolean> canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), pageResult.getList());
|
||||
// 3.2 拼接返回
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap));
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, canCanTakeMap));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得分页查询的商品范围
|
||||
* 获得商品的使用范围编号
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 商品范围
|
||||
* @param productScope 商品范围
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @return 商品范围编号
|
||||
*/
|
||||
private Long getProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {
|
||||
// 通用券:清除商品范围
|
||||
if (pageReqVO.getProductScope() == null || ObjectUtils.equalsAny(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope(), null)) {
|
||||
private Long getProductScopeValue(Integer productScope, Long spuId) {
|
||||
// 通用券:没有商品范围
|
||||
if (productScope == null || ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
|
||||
return null;
|
||||
}
|
||||
// 品类券:查询商品的品类
|
||||
if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {
|
||||
return Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId()))
|
||||
// 品类券:查询商品的品类编号
|
||||
if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) {
|
||||
return Optional.ofNullable(productSpuApi.getSpu(spuId))
|
||||
.map(ProductSpuRespDTO::getCategoryId).orElse(null);
|
||||
}
|
||||
// 商品卷:直接返回
|
||||
return pageReqVO.getSpuId();
|
||||
return spuId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class AppCouponTemplateRespVO {
|
||||
|
||||
// ========== 用户相关字段 ==========
|
||||
|
||||
@Schema(description = "是否已领取", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean takeStatus;
|
||||
@Schema(description = "是否可以领取", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean canTake;
|
||||
|
||||
}
|
||||
|
@ -37,21 +37,25 @@ public interface CouponTemplateConvert {
|
||||
|
||||
PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult);
|
||||
|
||||
default PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult, Map<Long, Integer> couponTakeCountMap) {
|
||||
List<AppCouponTemplateRespVO> convertAppList(List<CouponTemplateDO> list);
|
||||
|
||||
default PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult, Map<Long, Boolean> userCanTakeMap) {
|
||||
PageResult<AppCouponTemplateRespVO> result = convertAppPage(pageResult);
|
||||
if (MapUtil.isEmpty(couponTakeCountMap)) {
|
||||
return result;
|
||||
}
|
||||
for (AppCouponTemplateRespVO template : result.getList()) {
|
||||
// 每人领取数量无限制
|
||||
if (template.getTakeLimitCount() == -1) {
|
||||
template.setTakeStatus(false);
|
||||
continue;
|
||||
}
|
||||
// 检查已领取数量是否超过限领数量
|
||||
template.setTakeStatus(MapUtil.getInt(couponTakeCountMap, template.getId(), 0) >= template.getTakeLimitCount());
|
||||
}
|
||||
copyTo(result.getList(), userCanTakeMap);
|
||||
return result;
|
||||
}
|
||||
|
||||
default List<AppCouponTemplateRespVO> convertAppList(List<CouponTemplateDO> list, Map<Long, Boolean> userCanTakeMap) {
|
||||
List<AppCouponTemplateRespVO> result = convertAppList(list);
|
||||
copyTo(result, userCanTakeMap);
|
||||
return result;
|
||||
}
|
||||
|
||||
default void copyTo(List<AppCouponTemplateRespVO> list, Map<Long, Boolean> userCanTakeMap) {
|
||||
for (AppCouponTemplateRespVO template : list) {
|
||||
// 检查已领取数量是否超过限领数量
|
||||
template.setCanTake(MapUtil.getBool(userCanTakeMap, template.getId(), false));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,16 +24,8 @@ import java.util.function.Consumer;
|
||||
public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
|
||||
default PageResult<CouponTemplateDO> selectPage(CouponTemplatePageReqVO reqVO) {
|
||||
// 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = null;
|
||||
if (CollUtil.isNotEmpty(reqVO.getCanTakeTypes())) {
|
||||
canTakeConsumer = w ->
|
||||
w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的
|
||||
.in(CouponTemplateDO::getTakeType, reqVO.getCanTakeTypes()) // 2. 领取方式一致
|
||||
.and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期
|
||||
.or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()))
|
||||
.apply(" take_count < total_count "); // 4. 剩余数量大于 0
|
||||
}
|
||||
// 构建可领取的查询条件
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = buildCanTakeQueryConsumer(reqVO.getCanTakeTypes());
|
||||
// 执行分页查询
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<CouponTemplateDO>()
|
||||
.likeIfPresent(CouponTemplateDO::getName, reqVO.getName())
|
||||
@ -52,4 +44,30 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
default List<CouponTemplateDO> selectListByTakeType(Integer takeType) {
|
||||
return selectList(CouponTemplateDO::getTakeType, takeType);
|
||||
}
|
||||
|
||||
default List<CouponTemplateDO> selectList(List<Integer> canTakeTypes, Integer productScope, Long productScopeValue, Integer count) {
|
||||
// 构建可领取的查询条件
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = buildCanTakeQueryConsumer(canTakeTypes);
|
||||
return selectList(new LambdaQueryWrapperX<CouponTemplateDO>()
|
||||
.eqIfPresent(CouponTemplateDO::getProductScope, productScope)
|
||||
.and(productScopeValue != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)",
|
||||
productScopeValue))
|
||||
.and(canTakeConsumer != null, canTakeConsumer)
|
||||
.last(" LIMIT " + count)
|
||||
.orderByDesc(CouponTemplateDO::getId));
|
||||
}
|
||||
|
||||
static Consumer<LambdaQueryWrapper<CouponTemplateDO>> buildCanTakeQueryConsumer(List<Integer> canTakeTypes) {
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = null;
|
||||
if (CollUtil.isNotEmpty(canTakeTypes)) {
|
||||
canTakeConsumer = w ->
|
||||
w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的
|
||||
.in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致
|
||||
.and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期
|
||||
.or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()))
|
||||
.apply(" take_count < total_count "); // 4. 剩余数量大于 0
|
||||
}
|
||||
return canTakeConsumer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
|
||||
@ -175,4 +176,13 @@ public interface CouponService {
|
||||
*/
|
||||
int expireCoupon();
|
||||
|
||||
/**
|
||||
* 获取用户是否可以领取优惠券
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param templates 优惠券列表
|
||||
* @return 是否可以领取
|
||||
*/
|
||||
Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates);
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@ -229,6 +229,29 @@ public class CouponServiceImpl implements CouponService {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates) {
|
||||
Map<Long, Boolean> userCanTakeMap = convertMap(templates, CouponTemplateDO::getId, templateId -> true);
|
||||
// 未登录时,都显示可以领取
|
||||
if (userId == null) {
|
||||
return userCanTakeMap;
|
||||
}
|
||||
|
||||
// 过滤领取数量无限制的
|
||||
Set<Long> templateIds = convertSet(templates, CouponTemplateDO::getId, template -> template.getTakeLimitCount() != -1);
|
||||
|
||||
// 检查用户领取的数量是否超过限制
|
||||
if (CollUtil.isNotEmpty(templateIds)) {
|
||||
Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
|
||||
for (CouponTemplateDO template : templates) {
|
||||
Integer takeCount = couponTakeCountMap.get(template.getId());
|
||||
userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount());
|
||||
}
|
||||
}
|
||||
|
||||
return userCanTakeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期单个优惠劵
|
||||
*
|
||||
|
@ -78,4 +78,17 @@ public interface CouponTemplateService {
|
||||
* @return 优惠券模板列表
|
||||
*/
|
||||
List<CouponTemplateDO> getCouponTemplateByTakeType(CouponTakeTypeEnum takeType);
|
||||
|
||||
/**
|
||||
* 获得优惠券模板列表
|
||||
*
|
||||
* @param canTakeTypes 可领取的类型列表
|
||||
* @param productScope 商品使用范围类型
|
||||
* @param productScopeValue 商品使用范围编号
|
||||
* @param count 查询数量
|
||||
* @return 优惠券模板列表
|
||||
*/
|
||||
List<CouponTemplateDO> getCouponTemplateList(List<Integer> canTakeTypes, Integer productScope,
|
||||
Long productScopeValue, Integer count);
|
||||
|
||||
}
|
||||
|
@ -120,4 +120,10 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
return couponTemplateMapper.selectListByTakeType(takeType.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTemplateDO> getCouponTemplateList(List<Integer> canTakeTypes, Integer productScope,
|
||||
Long productScopeValue, Integer count) {
|
||||
return couponTemplateMapper.selectList(canTakeTypes, productScope, productScopeValue, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user