Merge branch 'master-new' of https://gitee.com/zhijiantianya/onemall into master-new

This commit is contained in:
YunaiV 2020-07-30 01:15:35 +08:00
commit d88da8229f
27 changed files with 1631 additions and 16 deletions

View File

@ -11,9 +11,9 @@ public interface CouponRpc {
// ========== 优惠劵模板 ==========
CouponTemplateBO getCouponTemplate(Integer couponTemplateId);
CouponTemplateReqDTO getCouponTemplate(Integer couponTemplateId);
CouponTemplatePageBO getCouponTemplatePage(CouponTemplatePageReqDTO couponTemplatePageDTO);
CouponTemplatePageRespDTO getCouponTemplatePage(CouponTemplatePageReqDTO couponTemplatePageDTO);
/**
* 创建优惠码模板
@ -21,7 +21,7 @@ public interface CouponRpc {
* @param couponCodeTemplateAddDTO 优惠码模板添加 DTO
* @return 优惠码模板
*/
CouponTemplateBO addCouponCodeTemplate(CouponCodeTemplateAddReqDTO couponCodeTemplateAddDTO);
CouponTemplateReqDTO addCouponCodeTemplate(CouponCodeTemplateAddReqDTO couponCodeTemplateAddDTO);
/**
* 创建优惠劵模板
@ -29,7 +29,7 @@ public interface CouponRpc {
* @param couponCardTemplateAddDTO 优惠码模板添加 DTO
* @return 优惠劵模板
*/
CouponTemplateBO addCouponCardTemplate(CouponCardTemplateAddReqDTO couponCardTemplateAddDTO);
CouponTemplateReqDTO addCouponCardTemplate(CouponCardTemplateAddReqDTO couponCardTemplateAddDTO);
/**
* 更新优惠码模板
@ -60,7 +60,7 @@ public interface CouponRpc {
// ========== 优惠劵 ==========
CouponCardPageBO getCouponCardPage(CouponCardPageReqDTO couponCardPageDTO);
CouponCardPageRespDTO getCouponCardPage(CouponCardPageReqDTO couponCardPageDTO);
/**
* 基于优惠劵模板领取优惠劵
@ -69,7 +69,7 @@ public interface CouponRpc {
* @param couponTemplateId 优惠劵模板
* @return 优惠劵
*/
CouponCardBO addCouponCard(Integer userId, Integer couponTemplateId);
CouponCardReqDTO addCouponCard(Integer userId, Integer couponTemplateId);
/**
* 使用优惠劵下单
@ -97,7 +97,7 @@ public interface CouponRpc {
* @param couponCardId 优惠劵编号
* @return 优惠劵
*/
CouponCardDetailBO getCouponCardDetail(Integer userId, Integer couponCardId);
CouponCardDetailRespDTO getCouponCardDetail(Integer userId, Integer couponCardId);
/**
* 获得用户所有优惠劵并标明是否可用
@ -119,6 +119,6 @@ public interface CouponRpc {
* @param code 优惠码
* @return 优惠劵
*/
CouponCardBO useCouponCode(Integer userId, String code);
CouponCardReqDTO useCouponCode(Integer userId, String code);
}

View File

@ -10,7 +10,7 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
public class CouponCardAvailableRespDTO extends CouponCardBO {
public class CouponCardAvailableRespDTO extends CouponCardReqDTO {
/**
* 是否可用

View File

@ -0,0 +1,143 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 优惠劵明细 BO
*
* 主要是会带上 {@link CouponTemplateReqDTO} 的信息
*/
@Data
@Accessors(chain = true)
public class CouponCardDetailRespDTO implements Serializable {
// ========== 基本信息 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;
}

View File

@ -11,12 +11,12 @@ import java.util.List;
*/
@Data
@Accessors(chain = true)
public class CouponCardPageBO implements Serializable {
public class CouponCardPageRespDTO implements Serializable {
/**
* 优惠劵数组
*/
private List<CouponCardBO> list;
private List<CouponCardReqDTO> list;
/**
* 总量
*/

View File

@ -0,0 +1,112 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 优惠劵 BO
*/
@Data
@Accessors(chain = true)
public class CouponCardReqDTO implements Serializable {
// ========== 基本信息 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 Date usedTime;
// TODO 芋艿后续要加优惠劵的使用日志因为下单后可能会取消
// ========== 使用情况 END ==========
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -11,12 +11,12 @@ import java.util.List;
*/
@Data
@Accessors(chain = true)
public class CouponTemplatePageBO implements Serializable {
public class CouponTemplatePageRespDTO implements Serializable {
/**
* 优惠劵数组
*/
private List<CouponTemplateBO> list;
private List<CouponTemplateReqDTO> list;
/**
* 总量
*/

View File

@ -0,0 +1,155 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 优惠劵模板 BO
*/
@Data
@Accessors(chain = true)
public class CouponTemplateReqDTO implements Serializable {
// ========== 基本信息 BEGIN ==========
/**
* 模板编号自增唯一
*/
private Integer id;
/**
* 标题
*/
private String title;
/**
* 使用说明
*/
private String description;
/**
* 类型
*
* 1-优惠劵
* 2-优惠码
*/
private Integer type;
/**
* 码类型
*
* 1-一卡一码UNIQUE
* 2-通用码GENERAL
*
* 优惠码独有 @see CouponCodeDO
*/
private Integer codeType;
/**
* 优惠码状态
*
* 1-开启中
* 2-禁用中
* 3-已过期
*
* 当优惠劵开启中可以手动操作设置禁用中
*/
private Integer status;
/**
* 每人限领个数
*
* null - 则表示不限制
*/
private Integer quota;
/**
* 发放总量
*/
private Integer total;
// ========== 领取规则 END ==========
// ========== 使用规则 BEGIN ==========
/**
* 是否设置满多少金额可用单位
*
* 0-不限制
* 大于0-多少金额可用
*/
private Integer priceAvailable;
/**
* 可用范围的类型
*
* 10-全部ALL所有可用
* 20-部分PART部分商品可用或指定商品可用
* 21-部分PART部分商品不可用或指定商品可用
* 30-部分PART部分分类可用或指定商品可用
* 31-部分PART部分分类不可用或指定商品可用
*/
private Integer rangeType;
/**
* 指定商品 / 分类列表使用逗号分隔商品编号
*/
private String rangeValues;
/**
* 生效日期类型
*
* 1-固定日期
* 2-领取日期领到券 {@link #fixedStartTerm} 日开始 N 天内有效
*/
private Integer dateType;
/**
* 固定日期-生效开始时间
*/
private Date validStartTime;
/**
* 固定日期-生效结束时间
*/
private Date validEndTime;
/**
* 领取日期-开始天数
*
* 例如0-当天1-次天
*/
private Integer fixedStartTerm;
/**
* 领取日期-结束天数
*/
private Integer fixedEndTerm;
// ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ==========
/**
* 优惠类型
*
* 1-代金卷
* 2-折扣卷
*/
private Integer preferentialType;
/**
* 折扣百分比
*
* 例如80% 80
* 100% 100 则代表免费
*/
private Integer percentOff;
/**
* 优惠金额单位
*/
private Integer priceOff;
/**
* 折扣上限仅在 {@link #preferentialType} 等于 2 时生效
*
* 例如折扣上限为 20 当使用 8 折优惠券订单金额为 1000 元时最高只可折扣 20 而非 80
*/
private Integer discountPriceLimit;
// ========== 使用效果 END ==========
// ========== 统计信息 BEGIN ==========
/**
* 领取优惠券的次数
*/
private Integer statFetchNum;
// ========== 统计信息 END ==========
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -46,6 +46,12 @@
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>product-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
package cn.iocoder.mall.promotionservice.convert.coupon;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.CouponCardDetailRespDTO;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.CouponCardReqDTO;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponCardDO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponCardAvailableBO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponCardBO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponCardDetailBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface CouponCardConvert {
CouponCardConvert INSTANCE = Mappers.getMapper(CouponCardConvert.class);
// @Mappings({})
// CouponCardBO convertToBO(CouponCardDO banner);
//
@Mappings({})
List<CouponCardBO> convertToBO(List<CouponCardDO> cardList);
List<CouponCardReqDTO> convertToDTO(List<CouponCardDO> cardList);
CouponCardReqDTO convertToSingleDTO(CouponCardDO card);
@Mappings({})
CouponCardBO convert(CouponCardDO card);
@Mappings({})
CouponCardDetailRespDTO convert2(CouponCardDO card);
CouponCardAvailableBO convertAvailBO(CouponCardDO card,boolean x);
//@Mappings({})
//CouponCardAvailableBO convert2(CouponCardDO card, boolean x); // TODO 芋艿临时用来解决 mapstruct 无法正确匹配方法的问题
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.mall.promotionservice.convert.coupon;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.*;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponCardTemplateAddBO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponCardTemplateUpdateBO;
import cn.iocoder.mall.promotionservice.service.coupon.bo.CouponTemplateBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface CouponTemplateConvert {
CouponTemplateConvert INSTANCE = Mappers.getMapper(CouponTemplateConvert.class);
// @Mappings({})
// CouponTemplateBO convertToBO(CouponTemplateDO banner);
//
@Mappings({})
List<CouponTemplateBO> convertToBO(List<CouponTemplateDO> templateList);
List<CouponTemplateReqDTO> convertToDTO(List<CouponTemplateDO> templateList);
@Mappings({})
CouponTemplateDO convert(CouponCodeTemplateUpdateReqDTO template);
@Mappings({})
CouponTemplateDO convert(CouponCardTemplateAddReqDTO template);
@Mappings({})
CouponTemplateDO convert(CouponCardTemplateUpdateReqDTO template);
@Mappings({})
CouponTemplateDO convert(CouponCodeTemplateAddReqDTO template);
@Mappings({})
CouponTemplateDO convert(CouponCardTemplateAddBO template);
@Mappings({})
CouponTemplateDO convert(CouponCardTemplateUpdateBO template);
@Mappings({})
CouponTemplateBO convert(CouponTemplateDO template);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.mall.promotionservice.convert.recommend;
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendRespDTO;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend.ProductRecommendDO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendAddBO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendBO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendUpdateBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProductRecommendConvert {
ProductRecommendConvert INSTANCE = Mappers.getMapper(ProductRecommendConvert.class);
@Mappings({})
ProductRecommendBO convertToBO(ProductRecommendDO recommend);
@Mappings({})
List<ProductRecommendBO> convertToBO(List<ProductRecommendDO> recommendList);
@Mappings({})
List<ProductRecommendRespDTO> convertToDTO(List<ProductRecommendDO> recommendList);
@Mappings({})
ProductRecommendDO convert(ProductRecommendAddBO recommendAddDTO);
@Mappings({})
ProductRecommendDO convert(ProductRecommendUpdateBO recommendUpdateDTO);
}

View File

@ -0,0 +1,354 @@
package cn.iocoder.mall.promotionservice.service.coupon;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.DateUtil;
import cn.iocoder.mall.promotion.api.enums.*;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.*;
import cn.iocoder.mall.promotionservice.convert.coupon.CouponCardConvert;
import cn.iocoder.mall.promotionservice.convert.coupon.CouponTemplateConvert;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponCardDO;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon.CouponCardMapper;
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon.CouponTemplateMapper;
import cn.iocoder.mall.promotionservice.service.coupon.bo.*;
import cn.iocoder.common.framework.util.*;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Validated
public class CouponService {
@Autowired
private CouponTemplateMapper couponTemplateMapper;
@Autowired
private CouponCardMapper couponCardMapper;
// ========== 优惠劵模板 ==========
public cn.iocoder.mall.promotionservice.service.coupon.bo.CouponTemplateBO getCouponTemplate(Integer couponTemplateId) {
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
return CouponTemplateConvert.INSTANCE.convert(template);
}
public CouponTemplatePageRespDTO getCouponTemplatePage(CouponTemplatePageReqDTO couponTemplatePageDTO) {
CouponTemplatePageRespDTO couponTemplatePageBO = new CouponTemplatePageRespDTO();
// 查询分页数据
int offset = (couponTemplatePageDTO.getPageNo() - 1) * couponTemplatePageDTO.getPageSize();
couponTemplatePageBO.setList(CouponTemplateConvert.INSTANCE.convertToDTO(couponTemplateMapper.selectListByPage(
couponTemplatePageDTO.getType(), couponTemplatePageDTO.getTitle(),
couponTemplatePageDTO.getStatus(), couponTemplatePageDTO.getPreferentialType(),
offset, couponTemplatePageDTO.getPageSize())));
// 查询分页总数
couponTemplatePageBO.setTotal(couponTemplateMapper.selectCountByPage(
couponTemplatePageDTO.getType(), couponTemplatePageDTO.getTitle(),
couponTemplatePageDTO.getStatus(), couponTemplatePageDTO.getPreferentialType()));
return couponTemplatePageBO;
}
public cn.iocoder.mall.promotionservice.service.coupon.bo.CouponTemplateBO addCouponCardTemplate(CouponCardTemplateAddBO couponCardTemplateAddDTO) {
// 校验生效日期相关
checkCouponTemplateDateType(couponCardTemplateAddDTO.getDateType(),
couponCardTemplateAddDTO.getValidStartTime(), couponCardTemplateAddDTO.getValidEndTime(),
couponCardTemplateAddDTO.getFixedBeginTerm(), couponCardTemplateAddDTO.getFixedEndTerm());
// 校验优惠类型
Boolean checkCouponTemplateDateTypeResult = checkCouponTemplatePreferentialType(
couponCardTemplateAddDTO.getPreferentialType(), couponCardTemplateAddDTO.getPercentOff(),
couponCardTemplateAddDTO.getPriceOff(), couponCardTemplateAddDTO.getPriceAvailable());
// 保存优惠劵模板到数据库
CouponTemplateDO template = CouponTemplateConvert.INSTANCE.convert(couponCardTemplateAddDTO)
.setType(CouponTemplateTypeEnum.CARD.getValue())
.setStatus(CouponTemplateStatusEnum.ENABLE.getValue())
.setStatFetchNum(0);
template.setCreateTime(new Date());
couponTemplateMapper.insert(template);
// 返回成功
return CouponTemplateConvert.INSTANCE.convert(template);
}
public Boolean updateCouponCodeTemplate(CouponCodeTemplateUpdateBO couponCodeTemplateUpdateDTO) {
return null;
}
public Boolean updateCouponCardTemplate(CouponCardTemplateUpdateBO couponCardTemplateUpdateDTO) {
// 校验 CouponCardTemplate 存在
CouponTemplateDO template = couponTemplateMapper.selectById(couponCardTemplateUpdateDTO.getId());
if (template == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
}
// 校验 CouponCardTemplate CARD
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_CARD.getCode());
}
// 校验发放数量不能减少
if (couponCardTemplateUpdateDTO.getTotal() < template.getTotal()) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_TOTAL_CAN_NOT_REDUCE.getCode());
}
// 更新优惠劵模板到数据库
CouponTemplateDO updateTemplateDO = CouponTemplateConvert.INSTANCE.convert(couponCardTemplateUpdateDTO);
couponTemplateMapper.update(updateTemplateDO);
// 返回成功
return true;
}
public Boolean updateCouponTemplateStatus(Integer adminId, Integer couponTemplateId, Integer status) {
// 校验 CouponCardTemplate 存在
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
if (template == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
}
// 更新到数据库
CouponTemplateDO updateTemplateDO = new CouponTemplateDO().setId(couponTemplateId).setStatus(status);
couponTemplateMapper.update(updateTemplateDO);
// 返回成功
return true;
}
private Boolean checkCouponTemplateDateType(Integer dateType, Date validStartTime, Date validEndTime, Integer fixedBeginTerm, Integer fixedEndTerm) {
/*if (CouponTemplateDateTypeEnum.FIXED_DATE.getValue().equals(dateType)) { // 固定日期
if (validStartTime == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "生效开始时间不能为空");
}
if (validEndTime == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "生效结束时间不能为空");
}
if (validStartTime.after(validEndTime)) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "生效开始时间不能大于生效结束时间");
}
} else if (CouponTemplateDateTypeEnum.FIXED_TERM.getValue().equals(dateType)) { // 领取日期
if (fixedBeginTerm == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "领取日期开始时间不能为空");
}
if (fixedEndTerm == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "领取日期结束时间不能为空");
}
} else {
throw new IllegalArgumentException("未知的生效日期类型:" + dateType);
}*/
return true;
}
private Boolean checkCouponTemplatePreferentialType(Integer preferentialType, Integer percentOff,
Integer priceOff, Integer priceAvailable) {
/*if (PreferentialTypeEnum.PRICE.getValue().equals(preferentialType)) {
if (priceOff == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "优惠金额不能为空");
}
if (priceOff >= priceAvailable) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "优惠金额不能d大于等于使用金额门槛");
}
} else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(preferentialType)) {
if (percentOff == null) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "折扣百分比不能为空");
}
} else {
throw new IllegalArgumentException("未知的优惠类型:" + preferentialType);
}*/
return true;
}
// ========== 优惠劵 ==========
public CouponCardPageRespDTO getCouponCardPage(CouponCardPageReqDTO couponCardPageDTO) {
CouponCardPageRespDTO pageBO = new CouponCardPageRespDTO();
// 查询分页数据
int offset = (couponCardPageDTO.getPageNo() - 1) * couponCardPageDTO.getPageSize();
pageBO.setList(CouponCardConvert.INSTANCE.convertToDTO(couponCardMapper.selectListByPage(
couponCardPageDTO.getUserId(), couponCardPageDTO.getStatus(),
offset, couponCardPageDTO.getPageSize())));
// 查询分页总数
pageBO.setTotal(couponCardMapper.selectCountByPage(
couponCardPageDTO.getUserId(), couponCardPageDTO.getStatus()));
return pageBO;
}
@Transactional
public CouponCardReqDTO addCouponCard(Integer userId, Integer couponTemplateId) {
// 校验 CouponCardTemplate 存在
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
if (template == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
}
// 校验 CouponCardTemplate CARD
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_CARD.getCode());
}
// 校验 CouponCardTemplate 状态是否开启
if (!CouponTemplateStatusEnum.ENABLE.getValue().equals(template.getStatus())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_STATUS_NOT_ENABLE.getCode());
}
// 校验 CouponCardTemplate 是否到达可领取的上限
if (template.getStatFetchNum() > template.getTotal()) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_TOTAL_NOT_ENOUGH.getCode());
}
// 校验单人可领取优惠劵是否到达上限
if (couponCardMapper.selectCountByUserIdAndTemplateId(userId, couponTemplateId) > template.getQuota()) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
}
// 增加优惠劵已领取量
int updateTemplateCount = couponTemplateMapper.updateStatFetchNumIncr(couponTemplateId);
if (updateTemplateCount == 0) { // 超过 CouponCardTemplate 发放量
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
}
// 创建优惠劵
// 1. 基本信息 + 领取情况
CouponCardDO card = new CouponCardDO()
.setTemplateId(couponTemplateId)
.setTitle(template.getTitle())
.setStatus(CouponCardStatusEnum.UNUSED.getValue())
.setUserId(userId)
.setTakeType(CouponCardTakeTypeEnum.BY_USER.getValue()); // TODO 需要改
// 2. 使用规则
card.setPriceAvailable(template.getPriceAvailable());
setCouponCardValidTime(card, template);
// 3. 使用效果
card.setPreferentialType(template.getPreferentialType())
.setPriceOff(template.getPriceOff())
.setPercentOff(template.getPercentOff()).setDiscountPriceLimit(template.getDiscountPriceLimit());
// 保存优惠劵模板到数据库
card.setCreateTime(new Date());
couponCardMapper.insert(card);
// 返回成功
return CouponCardConvert.INSTANCE.convertToSingleDTO(card);
}
public Boolean useCouponCard(Integer userId, Integer couponCardId) {
// 查询优惠劵
CouponCardDO card = couponCardMapper.selectById(couponCardId);
if (card == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_NOT_EXISTS.getCode());
}
if (!userId.equals(card.getUserId())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_ERROR_USER.getCode());
}
if (!CouponCardStatusEnum.UNUSED.getValue().equals(card.getStatus())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
}
if (DateUtil.isBetween(card.getValidStartTime(), card.getValidEndTime())) { // 为避免定时器没跑实际优惠劵已经过期
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
}
// 更新优惠劵已使用
int updateCount = couponCardMapper.updateByIdAndStatus(card.getId(), CouponCardStatusEnum.UNUSED.getValue(),
new CouponCardDO().setStatus(CouponCardStatusEnum.USED.getValue()).setUsedTime(new Date()));
if (updateCount == 0) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
}
return true;
}
public Boolean cancelUseCouponCard(Integer userId, Integer couponCardId) {
// 查询优惠劵
CouponCardDO card = couponCardMapper.selectById(couponCardId);
if (card == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_NOT_EXISTS.getCode());
}
if (!userId.equals(card.getUserId())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_ERROR_USER.getCode());
}
if (!CouponCardStatusEnum.USED.getValue().equals(card.getStatus())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_STATUS_NOT_USED.getCode());
}
// 更新优惠劵已使用
int updateCount = couponCardMapper.updateByIdAndStatus(card.getId(), CouponCardStatusEnum.USED.getValue(),
new CouponCardDO().setStatus(CouponCardStatusEnum.UNUSED.getValue())); // TODO 芋艿usedTime 未设置空后面处理
if (updateCount == 0) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_STATUS_NOT_USED.getCode());
}
// 有一点要注意更新会未使用时优惠劵可能已经过期了直接让定时器跑过期这里不做处理
return true;
}
public CouponCardDetailRespDTO getCouponCardDetail(Integer userId, Integer couponCardId) {
// 查询优惠劵
CouponCardDO card = couponCardMapper.selectById(couponCardId);
if (card == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_NOT_EXISTS.getCode());
}
if (!userId.equals(card.getUserId())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_CARD_ERROR_USER.getCode());
}
// 查询优惠劵模板
CouponTemplateDO template = couponTemplateMapper.selectById(card.getTemplateId());
if (template == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.COUPON_TEMPLATE_NOT_EXISTS.getCode());
}
// 拼接结果
CouponCardDetailRespDTO detail = CouponCardConvert.INSTANCE.convert2(card);
detail.setRangeType(template.getRangeType());
detail.setRangeValues(StringUtils.splitToInt(template.getRangeValues(), ","));
return detail;
}
public List<CouponCardAvailableBO> getCouponCardList(Integer userId, List<CouponCardSpuBO> spus) {
// 查询用户未使用的优惠劵列表
List<CouponCardDO> cards = couponCardMapper.selectListByUserIdAndStatus(userId, CouponCardStatusEnum.UNUSED.getValue());
if (cards.isEmpty()) {
return Collections.emptyList();
}
// 查询优惠劵模板集合
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.convertAvailBO(card, true);
availableCard.setUnavailableReason(isMatch(card, templates.get(card.getTemplateId()), spus));
availableCard.setAvailable(availableCard.getUnavailableReason() == null);
return availableCard;
}).collect(Collectors.toList());
// 返回结果
return availableCards;
}
private void setCouponCardValidTime(CouponCardDO card, CouponTemplateDO template) {
if (CouponTemplateDateTypeEnum.FIXED_DATE.getValue().equals(template.getDateType())) {
card.setValidStartTime(template.getValidStartTime()).setValidEndTime(template.getValidEndTime());
} else if (CouponTemplateDateTypeEnum.FIXED_TERM.getValue().equals(template.getDateType())) {
Date validStartTime = DateUtil.getDayBegin(new Date());
card.setValidStartTime(DateUtil.addDate(validStartTime, Calendar.DAY_OF_YEAR, template.getFixedStartTerm()));
Date validEndTime = DateUtil.getDayEnd(card.getValidStartTime());
card.setValidEndTime(DateUtil.addDate(validEndTime, Calendar.DAY_OF_YEAR, template.getFixedEndTerm() - 1));
}
}
// 如果匹配则返回 null 即可
private String isMatch(CouponCardDO card, CouponTemplateDO template, List<CouponCardSpuBO> 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 = StringUtils.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 = StringUtils.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 = StringUtils.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 = StringUtils.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;
}
// ========== 优惠码 ==========
public CouponCardReqDTO useCouponCode(Integer userId, String code) {
return null;
}
}

View File

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

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.CouponCardReqDTO;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 优惠劵分页 BO
*/
@Data
@Accessors(chain = true)
public class CouponCardPageBO implements Serializable {
/**
* 优惠劵数组
*/
private List<CouponCardReqDTO> list;
/**
* 总量
*/
private Integer total;
}

View File

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

View File

@ -0,0 +1,140 @@
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.promotion.api.enums.CouponTemplateDateTypeEnum;
import cn.iocoder.mall.promotion.api.enums.PreferentialTypeEnum;
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* 优惠劵模板添加 DTO
*/
@Data
@Accessors(chain = true)
public class CouponCardTemplateAddBO implements Serializable {
// ========== 基本信息 BEGIN ==========
/**
* 标题
*/
@NotEmpty(message = "标题不能为空")
private String title;
/**
* 使用说明
*/
private String description;
// ========== 基本信息 END ==========
// ========== 领取规则 BEGIN ==========
/**
* 每人限领个数
*/
@NotNull(message = "每人限领个数不能为空")
@Min(value = 1, message = "每人限领个数最小为 {value}")
private Integer quota;
/**
* 发放总量
*/
@NotNull(message = "发放总量不能为空")
@Min(value = 1, message = "每人限领个数最小为 {value}")
private Integer total;
// ========== 领取规则 END ==========
// ========== 使用规则 BEGIN ==========
/**
* 是否设置满多少金额可用单位
*
* 0-不限制
* 大于0-多少金额可用
*/
@NotNull(message = "使用金额门槛不能为空")
@Min(value = 0L, message = "使用金额门槛最低为 {value}")
private Integer priceAvailable;
/**
* 可用范围的类型
*
* 10-全部ALL所有可用
* 20-部分PART部分商品可用或指定商品可用
* 21-部分PART部分商品不可用或指定商品可用
* 30-部分PART部分分类可用或指定分类可用
* 31-部分PART部分分类不可用或指定分类可用
*/
@NotNull(message = "可用范围的类型不能为空")
@InEnum(value = RangeTypeEnum.class, message = "可用范围的类型必须在 {value}")
private Integer rangeType;
/**
* 指定商品 / 分类列表使用逗号分隔商品编号
*/
private String rangeValues;
/**
* 生效日期类型
*
* 1-固定日期
* 2-领取日期领到券 {@link #fixedEndTerm} 日开始 N 天内有效
*/
@NotNull(message = "生效日期类型不能为空")
@InEnum(value = CouponTemplateDateTypeEnum.class, message = "生效日期类型必须在 {value}")
private Integer dateType;
/**
* 固定日期-生效开始时间
*/
private Date validStartTime;
/**
* 固定日期-生效结束时间
*/
private Date validEndTime;
/**
* 领取日期-开始天数
*
* 例如0-当天1-次天
*/
@Min(value = 0L, message = "领取日期开始时间最小为 {value}")
private Integer fixedBeginTerm;
/**
* 领取日期-结束天数
*/
@Min(value = 1L, message = "领取日期结束时间最小为 {value}")
private Integer fixedEndTerm;
// ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ==========
/**
* 优惠类型
*
* 1-代金卷
* 2-折扣卷
*/
@NotNull(message = "优惠类型不能为空")
@InEnum(value = PreferentialTypeEnum.class, message = "优惠类型必须在 {value}")
private Integer preferentialType;
/**
* 优惠金额单位
*/
@Min(value = 1, message = "优惠金额最小值为 {value}")
private Integer priceOff;
/**
* 折扣百分比
*
* 例如80% 80
* 100% 100 则代表免费
*/
@Max(value = 100, message = "折扣比最大值为 {value}")
private Integer percentOff;
/**
* 折扣上限仅在 {@link #preferentialType} 等于 2 时生效
*
* 例如折扣上限为 20 当使用 8 折优惠券订单金额为 1000 元时最高只可折扣 20 而非 80
*/
@Min(value = 1, message = "折扣上限最小值为 {value}")
private Integer discountPriceLimit;
// ========== 使用效果 END ==========
}

View File

@ -0,0 +1,201 @@
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 优惠劵模板更新 DTO
*/
@Data
@Accessors(chain = true)
public class CouponCardTemplateUpdateBO implements Serializable {
@NotNull(message = "编号不能为空")
private Integer id;
// ========== 基本信息 BEGIN ==========
/**
* 标题
*/
@NotEmpty(message = "标题不能为空")
private String title;
/**
* 使用说明
*/
private String description;
// ========== 基本信息 END ==========
// ========== 领取规则 BEGIN ==========
/**
* 每人限领个数
*/
@NotNull(message = "每人限领个数不能为空")
@Min(value = 1, message = "每人限领个数最小为 {value}")
private Integer quota;
/**
* 发放总量
*/
@NotNull(message = "发放总量不能为空")
@Min(value = 1, message = "每人限领个数最小为 {value}")
private Integer total;
// ========== 领取规则 END ==========
// ========== 使用规则 BEGIN ==========
// /**
// * 是否设置满多少金额可用单位
// *
// * 0-不限制
// * 大于0-多少金额可用
// */
// @NotNull(message = "使用金额门槛不能为空")
// @Min(value = 0L, message = "使用金额门槛最低为 {value}")
// private Integer priceAvailable;
/**
* 可用范围的类型
*
* 10-全部ALL所有可用
* 20-部分PART部分商品可用或指定商品可用
* 21-部分PART部分商品不可用或指定商品可用
* 30-部分PART部分分类可用或指定分类可用
* 31-部分PART部分分类不可用或指定分类可用
*/
@NotNull(message = "可用范围的类型不能为空")
@InEnum(value = RangeTypeEnum.class, message = "可用范围的类型必须在 {value}")
private Integer rangeType;
/**
* 指定商品 / 分类列表使用逗号分隔商品编号
*/
private String rangeValues;
// /**
// * 生效日期类型
// *
// * 1-固定日期
// * 2-领取日期领到券 {@link #fixedEndTerm} 日开始 N 天内有效
// */
// @NotNull(message = "生效日期类型不能为空")
// @InEnum(value = CouponTemplateDateTypeEnum.class, message = "生效日期类型必须在 {value}")
// private Integer dateType;
// /**
// * 固定日期-生效开始时间
// */
// private Date validStartTime;
// /**
// * 固定日期-生效结束时间
// */
// private Date validEndTime;
// /**
// * 领取日期-开始天数
// *
// * 例如0-当天1-次天
// */
// @Min(value = 0L, message = "领取日期开始时间最小为 {value}")
// private Integer fixedBeginTerm;
// /**
// * 领取日期-结束天数
// */
// @Min(value = 1L, message = "领取日期结束时间最小为 {value}")
// private Integer fixedEndTerm;
// ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ==========
// /**
// * 优惠类型
// *
// * 1-代金卷
// * 2-折扣卷
// */
// @NotNull(message = "优惠类型不能为空")
// @InEnum(value = CouponTemplatePreferentialTypeEnum.class, message = "优惠类型必须在 {value}")
// private Integer preferentialType;
// /**
// * 优惠金额单位
// */
// @Min(value = 1, message = "优惠金额最小值为 {value}")
// private Integer priceOff;
// /**
// * 折扣百分比
// *
// * 例如80% 80
// * 100% 100 则代表免费
// */
// @Max(value = 100, message = "折扣比最大值为 {value}")
// private Integer percentOff;
// /**
// * 折扣上限仅在 {@link #preferentialType} 等于 2 时生效
// *
// * 例如折扣上限为 20 当使用 8 折优惠券订单金额为 1000 元时最高只可折扣 20 而非 80
// */
// @Min(value = 1, message = "折扣上限最小值为 {value}")
// private Integer discountPriceLimit;
// ========== 使用效果 END ==========
public Integer getId() {
return id;
}
public CouponCardTemplateUpdateBO setId(Integer id) {
this.id = id;
return this;
}
public String getTitle() {
return title;
}
public CouponCardTemplateUpdateBO setTitle(String title) {
this.title = title;
return this;
}
public String getDescription() {
return description;
}
public CouponCardTemplateUpdateBO setDescription(String description) {
this.description = description;
return this;
}
public Integer getQuota() {
return quota;
}
public CouponCardTemplateUpdateBO setQuota(Integer quota) {
this.quota = quota;
return this;
}
public Integer getTotal() {
return total;
}
public CouponCardTemplateUpdateBO setTotal(Integer total) {
this.total = total;
return this;
}
public Integer getRangeType() {
return rangeType;
}
public CouponCardTemplateUpdateBO setRangeType(Integer rangeType) {
this.rangeType = rangeType;
return this;
}
public String getRangeValues() {
return rangeValues;
}
public CouponCardTemplateUpdateBO setRangeValues(String rangeValues) {
this.rangeValues = rangeValues;
return this;
}
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 优惠码模板更新 DTO
*/
@Data
@Accessors(chain = true)
public class CouponCodeTemplateUpdateBO implements Serializable {
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.promotion.api.rpc.coupon.dto;
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.promotionservice.service.coupon.bo;
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.CouponTemplateReqDTO;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 优惠劵模板分页 BO
*/
@Data
@Accessors(chain = true)
public class CouponTemplatePageBO implements Serializable {
/**
* 优惠劵数组
*/
private List<CouponTemplateReqDTO> list;
/**
* 总量
*/
private Integer total;
}

View File

@ -0,0 +1,114 @@
package cn.iocoder.mall.promotionservice.service.recommend;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.mall.mybatis.core.enums.DeletedStatusEnum;
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuRpc;
import cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeEnum;
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendPageReqDTO;
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendPageRespDTO;
import cn.iocoder.mall.promotionservice.convert.recommend.ProductRecommendConvert;
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend.ProductRecommendDO;
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.recommend.ProductRecommendMapper;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendAddBO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendBO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendPageBO;
import cn.iocoder.mall.promotionservice.service.recommend.bo.ProductRecommendUpdateBO;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Date;
import java.util.List;
@Service
@Validated
public class ProductRecommendService {
@Reference(validation = "true", version = "${dubbo.consumer.ProductSpuService.version}")
private ProductSpuRpc productSpuRpc;
@Autowired
private ProductRecommendMapper productRecommendMapper;
public List<ProductRecommendBO> getProductRecommendList(Integer type, Integer status) {
List<ProductRecommendDO> productRecommends = productRecommendMapper.selectListByTypeAndStatus(type, status);
return ProductRecommendConvert.INSTANCE.convertToBO(productRecommends);
}
public ProductRecommendPageRespDTO getProductRecommendPage(ProductRecommendPageReqDTO productRecommendPageDTO) {
ProductRecommendPageRespDTO productRecommendPageBO = new ProductRecommendPageRespDTO();
// 查询分页数据
int offset = (productRecommendPageDTO.getPageNo() - 1) * productRecommendPageDTO.getPageSize();
productRecommendPageBO.setList(ProductRecommendConvert.INSTANCE.convertToDTO(productRecommendMapper.selectPageByType(productRecommendPageDTO.getType(),
offset, productRecommendPageDTO.getPageSize())));
// 查询分页总数
productRecommendPageBO.setTotal(productRecommendMapper.selectCountByType(productRecommendPageDTO.getType()));
return productRecommendPageBO;
}
public ProductRecommendBO addProductRecommend(Integer adminId, ProductRecommendAddBO productRecommendAddDTO) {
// 校验商品不存在
if (productSpuRpc.getProductSpu(productRecommendAddDTO.getProductSpuId()) == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_PRODUCT_NOT_EXISTS.getCode());
}
// 校验商品是否已经推荐
if (productRecommendMapper.selectByProductSpuIdAndType(productRecommendAddDTO.getProductSpuId(), productRecommendAddDTO.getType()) != null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_EXISTS.getCode());
}
// 保存到数据库
ProductRecommendDO productRecommend = ProductRecommendConvert.INSTANCE.convert(productRecommendAddDTO).setStatus(CommonStatusEnum.ENABLE.getValue());
productRecommend.setDeleted(DeletedStatusEnum.DELETED_NO.getValue()).setCreateTime(new Date());
productRecommendMapper.insert(productRecommend);
// 返回成功
return ProductRecommendConvert.INSTANCE.convertToBO(productRecommend);
}
public Boolean updateProductRecommend(Integer adminId, ProductRecommendUpdateBO productRecommendUpdateDTO) {
// 校验更新的商品推荐存在
if (productRecommendMapper.selectById(productRecommendUpdateDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_NOT_EXISTS.getCode());
}
// 校验商品不存在
if (productSpuRpc.getProductSpu(productRecommendUpdateDTO.getProductSpuId()) == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_PRODUCT_NOT_EXISTS.getCode());
}
// 校验商品是否已经推荐
ProductRecommendDO existProductRecommend = productRecommendMapper.selectByProductSpuIdAndType(productRecommendUpdateDTO.getProductSpuId(), productRecommendUpdateDTO.getType());
if (existProductRecommend != null && !existProductRecommend.getId().equals(productRecommendUpdateDTO.getId())) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_EXISTS.getCode());
}
// 更新到数据库
ProductRecommendDO updateProductRecommend = ProductRecommendConvert.INSTANCE.convert(productRecommendUpdateDTO);
productRecommendMapper.update(updateProductRecommend);
// 返回成功
return true;
}
public Boolean updateProductRecommendStatus(Integer adminId, Integer productRecommendId, Integer status) {
// 校验更新的商品推荐存在
if (productRecommendMapper.selectById(productRecommendId) == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_NOT_EXISTS.getCode());
}
// 更新到数据库
ProductRecommendDO updateProductRecommend = new ProductRecommendDO().setId(productRecommendId).setStatus(status);
productRecommendMapper.update(updateProductRecommend);
// 返回成功
return true;
}
public Boolean deleteProductRecommend(Integer adminId, Integer productRecommendId) {
// 校验更新的商品推荐存在
if (productRecommendMapper.selectById(productRecommendId) == null) {
throw ServiceExceptionUtil.exception(PromotionErrorCodeEnum.PRODUCT_RECOMMEND_NOT_EXISTS.getCode());
}
// 更新到数据库
ProductRecommendDO updateProductRecommend = new ProductRecommendDO().setId(productRecommendId);
updateProductRecommend.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
productRecommendMapper.update(updateProductRecommend);
// 返回成功
return true;
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.mall.promotionservice.service.recommend.bo;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.promotion.api.enums.ProductRecommendTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 商品推荐添加 DTO
*/
@Data
@Accessors(chain = true)
public class ProductRecommendAddBO implements Serializable {
@InEnum(value = ProductRecommendTypeEnum.class, message = "修改推荐类型必须是 {value}")
@NotNull(message = "推荐类型不能为空")
private Integer type;
@NotNull(message = "商品编号不能为空")
private Integer productSpuId;
@NotNull(message = "排序不能为空")
private Integer sort;
@Length(max = 255, message = "备注最大长度为 255 位")
private String memo;
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.mall.promotionservice.service.recommend.bo;
import cn.iocoder.mall.promotion.api.enums.ProductRecommendTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 商品推荐 BO
*/
@Data
@Accessors(chain = true)
public class ProductRecommendBO implements Serializable {
/**
* 编号
*/
private Integer id;
/**
* 类型
*
* {@link ProductRecommendTypeEnum}
*/
private Integer type;
/**
* 商品 Spu 编号
*/
private Integer productSpuId;
/**
* 排序
*/
private Integer sort;
/**
* 状态
*
* {@link cn.iocoder.common.framework.enums.CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String memo;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.promotionservice.service.recommend.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 商品推荐分页 DTO
*/
@Data
@Accessors(chain = true)
public class ProductRecommendPageBO implements Serializable {
/**
* 推荐类型
*/
private Integer type;
@NotNull(message = "页码不能为空")
private Integer pageNo;
@NotNull(message = "每页条数不能为空")
private Integer pageSize;
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.mall.promotionservice.service.recommend.bo;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.promotion.api.enums.ProductRecommendTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 商品推荐更新 DTO
*/
@Data
@Accessors(chain = true)
public class ProductRecommendUpdateBO implements Serializable {
@NotNull(message = "编号不能为空")
private Integer id;
@NotNull(message = "类型不能为空")
@InEnum(value = ProductRecommendTypeEnum.class, message = "修改推荐类型必须是 {value}")
private Integer type;
@NotNull(message = "商品编号不能为空")
private Integer productSpuId;
@NotNull(message = "排序不能为空")
private Integer sort;
@Length(max = 255, message = "备注最大长度为 255 位")
private String memo;
}