前后端:商品确认页,增加优惠劵接入

后端:修改了价格计算的逻辑
This commit is contained in:
YunaiV
2019-04-18 22:46:27 +08:00
parent 8962631b6a
commit 7277ecb2d4
34 changed files with 550 additions and 143 deletions

View File

@@ -2,13 +2,12 @@ package cn.iocoder.mall.promotion.api;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.promotion.api.bo.CouponCardBO;
import cn.iocoder.mall.promotion.api.bo.CouponCardPageBO;
import cn.iocoder.mall.promotion.api.bo.CouponTemplateBO;
import cn.iocoder.mall.promotion.api.bo.CouponTemplatePageBO;
import cn.iocoder.mall.promotion.api.bo.*;
import cn.iocoder.mall.promotion.api.constant.CouponTemplateStatusEnum;
import cn.iocoder.mall.promotion.api.dto.*;
import java.util.List;
public interface CouponService {
// ========== 优惠劵(码)模板 ==========
@@ -93,6 +92,17 @@ public interface CouponService {
*/
CommonResult<Boolean> cancelUseCouponCard(Integer userId, Integer couponCardId);
/**
* 获得用户所有优惠劵,并标明是否可用
*
* 注意spus 是作为条件,判断优惠劵是否可用
*
* @param userId 用户编号
* @param spus 匹配的商品/分类
* @return 优惠劵列表
*/
CommonResult<List<CouponCardAvailableBO>> getCouponCardList(Integer userId, List<CouponCardSpuDTO> spus);
// ========== 优惠码 ==========
/**

View File

@@ -0,0 +1,24 @@
package cn.iocoder.mall.promotion.api.bo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 可用优惠劵 BO
*
* 注意,如果优惠劵不可用,标记 available = false ,并写明 unavailableReason 原因
*/
@Data
@Accessors(chain = true)
public class CouponCardAvailableBO extends CouponCardBO {
/**
* 是否可用
*/
private Boolean available;
/**
* 不可用原因
*/
private String unavailableReason;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.mall.promotion.api.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 优惠劵商品 DTO
*
* 主要用于 {@link cn.iocoder.mall.promotion.api.CouponService#getCouponCardList(Integer, List)}
*/
@Data
@Accessors(chain = true)
public class CouponCardSpuDTO implements Serializable {
/**
* 商品 SPU 编号
*/
private Integer spuId;
/**
* 商品 SKU 编号
*/
private Integer skuId;
/**
* 分类编号
*/
private Integer categoryId;
/**
* 价格
*/
private Integer price;
/**
* 数量
*/
private Integer quantity;
}

View File

@@ -1,5 +1,6 @@
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.biz.dataobject.CouponCardDO;
import org.mapstruct.Mapper;
@@ -22,4 +23,7 @@ public interface CouponCardConvert {
@Mappings({})
CouponCardBO convert(CouponCardDO card);
@Mappings({})
CouponCardAvailableBO convert2(CouponCardDO card, boolean x); // TODO 芋艿,临时用来解决 mapstruct 无法正确匹配方法的问题
}

View File

@@ -11,6 +11,9 @@ public interface CouponCardMapper {
CouponCardDO selectById(@Param("id") Integer id);
List<CouponCardDO> selectListByUserIdAndStatus(@Param("userId") Integer userId,
@Param("status") Integer status);
List<CouponCardDO> selectListByPage(@Param("userId") Integer userId,
@Param("status") Integer status,
@Param("offset") Integer offset,

View File

@@ -4,6 +4,7 @@ import cn.iocoder.mall.promotion.biz.dataobject.CouponTemplateDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.List;
@Repository
@@ -11,6 +12,8 @@ public interface CouponTemplateMapper {
CouponTemplateDO selectById(@Param("id") Integer id);
List<CouponTemplateDO> selectListByIds(@Param("ids") Collection<Integer> ids);
List<CouponTemplateDO> selectListByPage(@Param("type") Integer type,
@Param("title") String title,
@Param("status") Integer status,

View File

@@ -1 +0,0 @@
package cn.iocoder.mall.promotion.biz;

View File

@@ -3,12 +3,10 @@ package cn.iocoder.mall.promotion.biz.service;
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
import cn.iocoder.common.framework.util.DateUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.promotion.api.CouponService;
import cn.iocoder.mall.promotion.api.bo.CouponCardBO;
import cn.iocoder.mall.promotion.api.bo.CouponCardPageBO;
import cn.iocoder.mall.promotion.api.bo.CouponTemplateBO;
import cn.iocoder.mall.promotion.api.bo.CouponTemplatePageBO;
import cn.iocoder.mall.promotion.api.bo.*;
import cn.iocoder.mall.promotion.api.constant.*;
import cn.iocoder.mall.promotion.api.dto.*;
import cn.iocoder.mall.promotion.biz.convert.CouponCardConvert;
@@ -22,8 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.*;
import java.util.stream.Collectors;
@Service // 实际上不用添加。添加的原因是,必须 Spring 报错提示
@com.alibaba.dubbo.config.annotation.Service(validation = "true")
@@ -252,6 +250,23 @@ public class CouponServiceImpl implements CouponService {
return null;
}
@Override
public CommonResult<List<CouponCardAvailableBO>> getCouponCardList(Integer userId, List<CouponCardSpuDTO> spus) {
// 查询用户未使用的优惠劵列表
List<CouponCardDO> cards = couponCardMapper.selectListByUserIdAndStatus(userId, CouponCardStatusEnum.UNUSED.getValue());
Map<Integer, CouponTemplateDO> templates = couponTemplateMapper.selectListByIds(cards.stream().map(CouponCardDO::getTemplateId).collect(Collectors.toSet()))
.stream().collect(Collectors.toMap(CouponTemplateDO::getId, template -> template));
// 逐个判断是否可用
List<CouponCardAvailableBO> availableCards = cards.stream().map(card -> {
CouponCardAvailableBO availableCard = CouponCardConvert.INSTANCE.convert2(card, true);
availableCard.setUnavailableReason(isMatch(card, templates.get(card.getTemplateId()), spus));
availableCard.setAvailable(availableCard.getUnavailableReason() == null);
return availableCard;
}).collect(Collectors.toList());
// 返回结果
return CommonResult.success(availableCards);
}
private void setCouponCardValidTime(CouponCardDO card, CouponTemplateDO template) {
if (CouponTemplateDateTypeEnum.FIXED_DATE.getValue().equals(template.getDateType())) {
card.setValidStartTime(template.getValidStartTime()).setValidEndTime(template.getValidEndTime());
@@ -263,6 +278,35 @@ public class CouponServiceImpl implements CouponService {
}
}
// 如果匹配,则返回 null 即可。
private String isMatch(CouponCardDO card, CouponTemplateDO template, List<CouponCardSpuDTO> spus) {
int totalPrice = 0;
if (RangeTypeEnum.ALL.getValue().equals(template.getRangeType())) {
totalPrice = spus.stream().mapToInt(spu -> spu.getPrice() * spu.getQuantity()).sum();
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(template.getRangeType())) {
List<Integer> spuIds = StringUtil.splitToInt(template.getRangeValues(), ",");
totalPrice = spus.stream().mapToInt(spu -> spuIds.contains(spu.getSpuId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
} else if (RangeTypeEnum.PRODUCT_EXCLUDE_PART.getValue().equals(template.getRangeType())) {
List<Integer> spuIds = StringUtil.splitToInt(template.getRangeValues(), ",");
totalPrice = spus.stream().mapToInt(spu -> !spuIds.contains(spu.getSpuId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
} else if (RangeTypeEnum.CATEGORY_INCLUDE_PART.getValue().equals(template.getRangeType())) {
List<Integer> spuIds = StringUtil.splitToInt(template.getRangeValues(), ",");
totalPrice = spus.stream().mapToInt(spu -> spuIds.contains(spu.getCategoryId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
} else if (RangeTypeEnum.CATEGORY_EXCLUDE_PART.getValue().equals(template.getRangeType())) {
List<Integer> spuIds = StringUtil.splitToInt(template.getRangeValues(), ",");
totalPrice = spus.stream().mapToInt(spu -> !spuIds.contains(spu.getCategoryId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
}
// 总价为 0 时,说明优惠劵丫根不匹配
if (totalPrice == 0) {
return "优惠劵不匹配";
}
// 如果不满足金额
if (totalPrice < card.getPriceAvailable()) {
return String.format("差 %1$,.2f 元可用优惠劵", (card.getPriceAvailable() - totalPrice) / 100D);
}
return null;
}
// ========== 优惠码 ==========
@Override

View File

@@ -33,6 +33,20 @@
WHERE id = #{id}
</select>
<select id="selectListByUserIdAndStatus" resultType="CouponCardDO">
SELECT
<include refid="FIELDS" />
FROM coupon_card
<where>
<if test="userId != null">
AND user_id = #{userId}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
</select>
<select id="selectListByPage" resultType="CouponCardDO">
SELECT
<include refid="FIELDS" />

View File

@@ -34,6 +34,16 @@
WHERE id = #{id}
</select>
<select id="selectListByIds" resultType="CouponTemplateDO">
SELECT
<include refid="FIELDS"/>
FROM coupon_template
WHERE id IN
<foreach item="id" collection="ids" separator="," open="(" close=")" index="">
#{id}
</foreach>
</select>
<select id="selectListByPage" resultType="CouponTemplateDO">
SELECT
<include refid="FIELDS" />

View File

@@ -1 +0,0 @@
package cn.iocoder.mall.promotion.biz;