前端:订单确认页,接入优惠劵列表(不包括计算)
后端:增加优惠劵的计算逻辑
This commit is contained in:
@@ -92,6 +92,15 @@ public interface CouponService {
|
||||
*/
|
||||
CommonResult<Boolean> cancelUseCouponCard(Integer userId, Integer couponCardId);
|
||||
|
||||
/**
|
||||
* 获得指定优惠劵
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param couponCardId 优惠劵编号
|
||||
* @return 优惠劵
|
||||
*/
|
||||
CommonResult<CouponCardDetailBO> getCouponCardDetail(Integer userId, Integer couponCardId);
|
||||
|
||||
/**
|
||||
* 获得用户所有优惠劵,并标明是否可用
|
||||
*
|
||||
@@ -103,6 +112,7 @@ public interface CouponService {
|
||||
*/
|
||||
CommonResult<List<CouponCardAvailableBO>> getCouponCardList(Integer userId, List<CouponCardSpuDTO> spus);
|
||||
|
||||
|
||||
// ========== 优惠码 ==========
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package cn.iocoder.mall.promotion.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠劵明细 BO 。
|
||||
*
|
||||
* 主要是,会带上 {@link CouponTemplateBO} 的信息
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CouponCardDetailBO {
|
||||
|
||||
// ========== 基本信息 BEGIN ==========
|
||||
/**
|
||||
* 优惠劵编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 优惠劵(码)分组编号
|
||||
*/
|
||||
private Integer templateId;
|
||||
/**
|
||||
* 优惠劵名
|
||||
*/
|
||||
private String title;
|
||||
// /**
|
||||
// * 核销码
|
||||
// */
|
||||
// private String verifyCode;
|
||||
/**
|
||||
* 优惠码状态
|
||||
*
|
||||
* 1-未使用
|
||||
* 2-已使用
|
||||
* 3-已失效
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== 基本信息 END ==========
|
||||
|
||||
// ========== 领取情况 BEGIN ==========
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 领取类型
|
||||
*
|
||||
* 1 - 用户主动领取
|
||||
* 2 - 后台自动发放
|
||||
*/
|
||||
private Integer takeType;
|
||||
// ========== 领取情况 END ==========
|
||||
|
||||
// ========== 使用规则 BEGIN ==========
|
||||
/**
|
||||
* 是否设置满多少金额可用,单位:分
|
||||
*/
|
||||
private Integer priceAvailable;
|
||||
/**
|
||||
* 生效开始时间
|
||||
*/
|
||||
private Date validStartTime;
|
||||
/**
|
||||
* 生效结束时间
|
||||
*/
|
||||
private Date validEndTime;
|
||||
// ========== 使用规则 END ==========
|
||||
|
||||
// ========== 使用效果 BEGIN ==========
|
||||
/**
|
||||
* 优惠类型
|
||||
*
|
||||
* 1-代金卷
|
||||
* 2-折扣卷
|
||||
*/
|
||||
private Integer preferentialType;
|
||||
/**
|
||||
* 折扣
|
||||
*/
|
||||
private Integer percentOff;
|
||||
/**
|
||||
* 优惠金额,单位:分。
|
||||
*/
|
||||
private Integer priceOff;
|
||||
/**
|
||||
* 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。
|
||||
*
|
||||
* 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。
|
||||
*/
|
||||
private Integer discountPriceLimit;
|
||||
// ========== 使用效果 END ==========
|
||||
|
||||
// ========== 使用情况 BEGIN ==========
|
||||
/**
|
||||
* 是否使用
|
||||
*/
|
||||
private Boolean used;
|
||||
/**
|
||||
* 使用订单号
|
||||
*/
|
||||
private Integer usedOrderId;
|
||||
/**
|
||||
* 订单中优惠面值,单位:分
|
||||
*/
|
||||
private Integer usedPrice;
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
|
||||
// TODO 芋艿,后续要加优惠劵的使用日志,因为下单后,可能会取消。
|
||||
|
||||
// ========== 使用情况 END ==========
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
// ========== FROM template 使用规则 BEGIN ==========
|
||||
/**
|
||||
* 可用范围的类型
|
||||
*
|
||||
* 10-全部(ALL):所有可用
|
||||
* 20-部分(PART):部分商品可用,或指定商品可用
|
||||
* 21-部分(PART):部分商品不可用,或指定商品可用
|
||||
* 30-部分(PART):部分分类可用,或指定商品可用
|
||||
* 31-部分(PART):部分分类不可用,或指定商品可用
|
||||
*/
|
||||
private Integer rangeType;
|
||||
/**
|
||||
* 指定商品 / 分类列表,使用逗号分隔商品编号
|
||||
*/
|
||||
private List<Integer> rangeValues;
|
||||
|
||||
}
|
||||
@@ -17,15 +17,21 @@ public enum PromotionErrorCodeEnum {
|
||||
|
||||
|
||||
// ========== COUPON TEMPLATE 模块 ==========
|
||||
PRODUCT_TEMPLATE_NOT_EXISTS(1006002000, "优惠劵模板(码)不存在"),
|
||||
PRODUCT_TEMPLATE_NOT_CARD(1006002001, "不是优惠劵模板"),
|
||||
PRODUCT_TEMPLATE_NOT_CODE(1006002002, "不是优惠码模板"),
|
||||
PRODUCT_TEMPLATE_TOTAL_CAN_NOT_REDUCE(1006002003, "优惠劵(码)模板的发放数量不能减小"),
|
||||
PRODUCT_TEMPLATE_STATUS_NOT_ENABLE(1006002004, "优惠劵模板(码)未开启"),
|
||||
PRODUCT_TEMPLATE_TOTAL_NOT_ENOUGH(1006002005, "优惠劵(码)模板的发放量不足"),
|
||||
PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA(1006002006, "优惠劵领取到达上限"),
|
||||
COUPON_TEMPLATE_NOT_EXISTS(1006002000, "优惠劵模板(码)不存在"),
|
||||
COUPON_TEMPLATE_NOT_CARD(1006002001, "不是优惠劵模板"),
|
||||
COUPON_TEMPLATE_NOT_CODE(1006002002, "不是优惠码模板"),
|
||||
COUPON_TEMPLATE_TOTAL_CAN_NOT_REDUCE(1006002003, "优惠劵(码)模板的发放数量不能减小"),
|
||||
COUPON_TEMPLATE_STATUS_NOT_ENABLE(1006002004, "优惠劵模板(码)未开启"),
|
||||
COUPON_TEMPLATE_TOTAL_NOT_ENOUGH(1006002005, "优惠劵(码)模板的发放量不足"),
|
||||
COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA(1006002006, "优惠劵领取到达上限"),
|
||||
|
||||
// ========== COUPON CARD 模块 ==========
|
||||
COUPON_CARD_NOT_EXISTS(1006003000, "优惠劵不存在"),
|
||||
COUPON_CARD_ERROR_USER(1006003001, "优惠劵不属于当前用户"),
|
||||
COUPON_CARD_NOT_MATCH(1006003002, "优惠劵不匹配,无法使用"),
|
||||
;
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.iocoder.mall.promotion.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.promotion.api.bo.CouponCardAvailableBO;
|
||||
import cn.iocoder.mall.promotion.api.bo.CouponCardBO;
|
||||
import cn.iocoder.mall.promotion.api.bo.CouponCardDetailBO;
|
||||
import cn.iocoder.mall.promotion.biz.dataobject.CouponCardDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
@@ -23,6 +24,9 @@ public interface CouponCardConvert {
|
||||
@Mappings({})
|
||||
CouponCardBO convert(CouponCardDO card);
|
||||
|
||||
@Mappings({})
|
||||
CouponCardDetailBO convert2(CouponCardDO card);
|
||||
|
||||
@Mappings({})
|
||||
CouponCardAvailableBO convert2(CouponCardDO card, boolean x); // TODO 芋艿,临时用来解决 mapstruct 无法正确匹配方法的问题
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service // 实际上不用添加。添加的原因是,必须 Spring 报错提示
|
||||
@@ -99,15 +102,15 @@ public class CouponServiceImpl implements CouponService {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(couponCardTemplateUpdateDTO.getId());
|
||||
if (template == null) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_NOT_EXISTS.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是 CARD
|
||||
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_NOT_CARD.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_CARD.getCode());
|
||||
}
|
||||
// 校验发放数量不能减少
|
||||
if (couponCardTemplateUpdateDTO.getTotal() < template.getTotal()) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_TOTAL_CAN_NOT_REDUCE.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_TOTAL_CAN_NOT_REDUCE.getCode());
|
||||
}
|
||||
// 更新优惠劵模板到数据库
|
||||
CouponTemplateDO updateTemplateDO = CouponTemplateConvert.INSTANCE.convert(couponCardTemplateUpdateDTO);
|
||||
@@ -121,7 +124,7 @@ public class CouponServiceImpl implements CouponService {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
|
||||
if (template == null) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_NOT_EXISTS.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 更新到数据库
|
||||
CouponTemplateDO updateTemplateDO = new CouponTemplateDO().setId(couponTemplateId).setStatus(status);
|
||||
@@ -195,28 +198,28 @@ public class CouponServiceImpl implements CouponService {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
|
||||
if (template == null) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_NOT_EXISTS.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是 CARD
|
||||
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_NOT_CARD.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_CARD.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 状态是否开启
|
||||
if (!CouponTemplateStatusEnum.ENABLE.getValue().equals(template.getStatus())) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_STATUS_NOT_ENABLE.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_STATUS_NOT_ENABLE.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是否到达可领取的上限
|
||||
if (template.getStatFetchNum() > template.getTotal()) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_TOTAL_NOT_ENOUGH.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_TOTAL_NOT_ENOUGH.getCode());
|
||||
}
|
||||
// 校验单人可领取优惠劵是否到达上限
|
||||
if (couponCardMapper.selectCountByUserIdAndTemplateId(userId, couponTemplateId) > template.getQuota()) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
}
|
||||
// 增加优惠劵已领取量
|
||||
int updateTemplateCount = couponTemplateMapper.updateStatFetchNumIncr(couponTemplateId);
|
||||
if (updateTemplateCount == 0) { // 超过 CouponCardTemplate 发放量
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
}
|
||||
// 创建优惠劵
|
||||
// 1. 基本信息 + 领取情况
|
||||
@@ -250,6 +253,28 @@ public class CouponServiceImpl implements CouponService {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<CouponCardDetailBO> getCouponCardDetail(Integer userId, Integer couponCardId) {
|
||||
// 查询优惠劵
|
||||
CouponCardDO card = couponCardMapper.selectById(couponCardId);
|
||||
if (card == null) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_CARD_NOT_EXISTS.getCode());
|
||||
}
|
||||
if (!userId.equals(card.getUserId())) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_CARD_ERROR_USER.getCode());
|
||||
}
|
||||
// 查询优惠劵模板
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(card.getTemplateId());
|
||||
if (template == null) {
|
||||
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 拼接结果
|
||||
CouponCardDetailBO detail = CouponCardConvert.INSTANCE.convert2(card);
|
||||
detail.setRangeType(template.getRangeType());
|
||||
detail.setRangeValues(StringUtil.splitToInt(template.getRangeValues(), ","));
|
||||
return CommonResult.success(detail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<CouponCardAvailableBO>> getCouponCardList(Integer userId, List<CouponCardSpuDTO> spus) {
|
||||
// 查询用户未使用的优惠劵列表
|
||||
|
||||
Reference in New Issue
Block a user