mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-08-17 03:31:54 +08:00
Merge branch 'feature/mall_product' of https://gitee.com/CrazyWorld/ruoyi-vue-pro into feature/mall_product
# Conflicts: # yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.coupon;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.github.yulichang.toolkit.MPJWrappers;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -16,9 +15,12 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 优惠劵 Mapper
|
||||
*
|
||||
@@ -70,14 +72,16 @@ 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)
|
||||
.selectCount(CouponDO::getId, CouponTakeCountBO::getCount)
|
||||
default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
|
||||
String templateIdAlias = "templateId";
|
||||
String countAlias = "count";
|
||||
List<Map<String, Object>> list = selectMaps(MPJWrappers.lambdaJoin(CouponDO.class)
|
||||
.selectAs(CouponDO::getTemplateId, templateIdAlias)
|
||||
.selectCount(CouponDO::getId, countAlias)
|
||||
.eq(CouponDO::getUserId, userId)
|
||||
.in(CouponDO::getTemplateId, templateIds)
|
||||
.groupBy(CouponDO::getTemplateId)), CouponTakeCountBO.class);
|
||||
.groupBy(CouponDO::getTemplateId));
|
||||
return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias));
|
||||
}
|
||||
|
||||
default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope(
|
||||
|
@@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -23,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())
|
||||
@@ -48,4 +41,33 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
|
||||
void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
|
||||
import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 针对 {@link RegisterCouponSendMessage} 的消费者
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RegisterCouponSendConsumer extends AbstractStreamMessageListener<RegisterCouponSendMessage> {
|
||||
|
||||
@Resource
|
||||
private CouponService couponService;
|
||||
|
||||
@Override
|
||||
public void onMessage(RegisterCouponSendMessage message) {
|
||||
log.info("[onMessage][消息内容({})]", message);
|
||||
couponService.takeCouponByRegister(message.getUserId());
|
||||
}
|
||||
|
||||
}
|
@@ -1,17 +1,16 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
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;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 优惠劵 Service 接口
|
||||
*
|
||||
@@ -119,12 +118,9 @@ public interface CouponService {
|
||||
/**
|
||||
* 【系统】给用户发送新人券
|
||||
*
|
||||
* @param templateId 优惠券模板编号
|
||||
* @param userId 用户编号列表
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
default void takeCouponByRegister(Long templateId, Long userId) {
|
||||
takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER);
|
||||
}
|
||||
void takeCouponByRegister(Long userId);
|
||||
|
||||
/**
|
||||
* 获取会员领取指定优惠券的数量
|
||||
@@ -134,11 +130,8 @@ public interface CouponService {
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
default Integer getTakeCount(Long templateId, Long userId) {
|
||||
return CollUtil.emptyIfNull(getTakeCountListByTemplateIds(Collections.singleton(templateId), userId))
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(CouponTakeCountBO::getCount)
|
||||
.orElse(0);
|
||||
Map<Long, Integer> map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId);
|
||||
return MapUtil.getInt(map, templateId, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,19 +141,7 @@ public interface CouponService {
|
||||
* @param userId 用户编号
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
return convertMap(getTakeCountListByTemplateIds(templateIds, userId),
|
||||
CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计会员领取优惠券的数量
|
||||
*
|
||||
* @param templateIds 优惠券模板编号列表
|
||||
* @param userId 用户编号
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
List<CouponTakeCountBO> getTakeCountListByTemplateIds(Collection<Long> templateIds, Long userId);
|
||||
Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户匹配的优惠券列表
|
||||
@@ -178,4 +159,13 @@ public interface CouponService {
|
||||
*/
|
||||
int expireCoupon();
|
||||
|
||||
/**
|
||||
* 获取用户是否可以领取优惠券
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param templates 优惠券列表
|
||||
* @return 是否可以领取
|
||||
*/
|
||||
Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates);
|
||||
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -21,7 +20,6 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -29,18 +27,14 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
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;
|
||||
|
||||
// TODO @疯狂:注册时,赠送用户优惠劵;为了解耦,可以考虑注册时发个 MQ 消息;然后营销这里监听后消费;
|
||||
/**
|
||||
* 优惠劵 Service 实现类
|
||||
*
|
||||
@@ -184,9 +178,17 @@ public class CouponServiceImpl implements CouponService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTakeCountBO> getTakeCountListByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
public void takeCouponByRegister(Long userId) {
|
||||
List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateByTakeType(CouponTakeTypeEnum.REGISTER);
|
||||
for (CouponTemplateDO template : templates) {
|
||||
takeCoupon(template.getId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
if (CollUtil.isEmpty(templateIds)) {
|
||||
return ListUtil.empty();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds);
|
||||
}
|
||||
@@ -222,6 +224,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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期单个优惠劵
|
||||
*
|
||||
|
@@ -5,8 +5,10 @@ import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.Cou
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠劵模板 Service 接口
|
||||
@@ -69,4 +71,24 @@ public interface CouponTemplateService {
|
||||
*/
|
||||
void updateCouponTemplateTakeCount(Long id, int incrCount);
|
||||
|
||||
/**
|
||||
* 获得指定领取方式的优惠券模板
|
||||
*
|
||||
* @param takeType 领取方式
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
@@ -2,16 +2,22 @@ package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS;
|
||||
@@ -29,9 +35,15 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
@Resource
|
||||
private CouponTemplateMapper couponTemplateMapper;
|
||||
|
||||
// TODO @疯狂:新增/修改时,需要校验对应的商品、分类是否存在
|
||||
@Resource
|
||||
private ProductCategoryApi productCategoryApi;
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@Override
|
||||
public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
|
||||
// 校验商品范围
|
||||
validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
|
||||
// 插入
|
||||
CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO)
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
@@ -48,6 +60,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
if (updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
|
||||
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
|
||||
}
|
||||
// 校验商品范围
|
||||
validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues());
|
||||
|
||||
// 更新
|
||||
CouponTemplateDO updateObj = CouponTemplateConvert.INSTANCE.convert(updateReqVO);
|
||||
@@ -78,6 +92,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
return couponTemplate;
|
||||
}
|
||||
|
||||
private void validateProductScope(Integer productScope, List<Long> productScopeValues) {
|
||||
if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) {
|
||||
productSpuApi.validateSpuList(productScopeValues);
|
||||
} else if (Objects.equals(PromotionProductScopeEnum.CATEGORY.getScope(), productScope)) {
|
||||
productCategoryApi.validateCategoryList(productScopeValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouponTemplateDO getCouponTemplate(Long id) {
|
||||
return couponTemplateMapper.selectById(id);
|
||||
@@ -93,4 +115,15 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
couponTemplateMapper.updateTakeCount(id, incrCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTemplateDO> getCouponTemplateByTakeType(CouponTakeTypeEnum takeType) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.coupon.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 优惠券领取数量 BO
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Data
|
||||
public class CouponTakeCountBO {
|
||||
|
||||
/**
|
||||
* 优惠劵模板编号
|
||||
*/
|
||||
private Long templateId;
|
||||
/**
|
||||
* 领取数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
}
|
Reference in New Issue
Block a user