From 495bf2ed581d53bb6b94e67a38b2ddbb0cf7909e Mon Sep 17 00:00:00 2001 From: wuwenbin Date: Wed, 29 Jul 2020 22:48:41 +0800 Subject: [PATCH] =?UTF-8?q?fix=20promotion=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E7=BB=A7=E7=BB=AD=E8=BF=81=E7=A7=BB,?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E6=88=90=EF=BC=8C=E5=86=8D=E5=86=8D=E5=86=8D?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/rpc/coupon/CouponRpc.java | 16 +- .../dto/CouponCardAvailableRespDTO.java | 2 +- .../coupon/dto/CouponCardDetailRespDTO.java | 143 +++++++ ...PageBO.java => CouponCardPageRespDTO.java} | 4 +- .../api/rpc/coupon/dto/CouponCardReqDTO.java | 112 ++++++ ...BO.java => CouponTemplatePageRespDTO.java} | 4 +- .../rpc/coupon/dto/CouponTemplateReqDTO.java | 155 ++++++++ .../promotion-service-app/pom.xml | 6 + .../convert/coupon/CouponCardConvert.java | 41 ++ .../convert/coupon/CouponTemplateConvert.java | 48 +++ .../recommend/ProductRecommendConvert.java | 34 ++ .../service/coupon/CouponService.java | 354 ++++++++++++++++++ .../coupon/bo/CouponCardAvailableBO.java | 25 ++ .../service/coupon/bo}/CouponCardBO.java | 2 +- .../coupon/bo}/CouponCardDetailBO.java | 2 +- .../service/coupon/bo/CouponCardPageBO.java | 26 ++ .../service/coupon/bo/CouponCardSpuBO.java | 40 ++ .../coupon/bo/CouponCardTemplateAddBO.java | 140 +++++++ .../coupon/bo/CouponCardTemplateUpdateBO.java | 201 ++++++++++ .../coupon/bo/CouponCodeTemplateUpdateBO.java | 14 + .../service/coupon/bo}/CouponTemplateBO.java | 2 +- .../coupon/bo/CouponTemplatePageBO.java | 26 ++ .../recommend/ProductRecommendService.java | 114 ++++++ .../recommend/bo/ProductRecommendAddBO.java | 29 ++ .../recommend/bo/ProductRecommendBO.java | 50 +++ .../recommend/bo/ProductRecommendPageBO.java | 26 ++ .../bo/ProductRecommendUpdateBO.java | 31 ++ 27 files changed, 1631 insertions(+), 16 deletions(-) create mode 100644 promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailRespDTO.java rename promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/{CouponCardPageBO.java => CouponCardPageRespDTO.java} (76%) create mode 100644 promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardReqDTO.java rename promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/{CouponTemplatePageBO.java => CouponTemplatePageRespDTO.java} (76%) create mode 100644 promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateReqDTO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponCardConvert.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponTemplateConvert.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/recommend/ProductRecommendConvert.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/CouponService.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardAvailableBO.java rename promotion-service-project/{promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto => promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo}/CouponCardBO.java (97%) rename promotion-service-project/{promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto => promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo}/CouponCardDetailBO.java (98%) create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardPageBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardSpuBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateAddBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateUpdateBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCodeTemplateUpdateBO.java rename promotion-service-project/{promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto => promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo}/CouponTemplateBO.java (98%) create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplatePageBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/ProductRecommendService.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendAddBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendPageBO.java create mode 100644 promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendUpdateBO.java diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/CouponRpc.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/CouponRpc.java index b6722673b..98f5cd27c 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/CouponRpc.java +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/CouponRpc.java @@ -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); } diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardAvailableRespDTO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardAvailableRespDTO.java index 78a26d08a..5050eb406 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardAvailableRespDTO.java +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardAvailableRespDTO.java @@ -10,7 +10,7 @@ import lombok.experimental.Accessors; */ @Data @Accessors(chain = true) -public class CouponCardAvailableRespDTO extends CouponCardBO { +public class CouponCardAvailableRespDTO extends CouponCardReqDTO { /** * 是否可用 diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailRespDTO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailRespDTO.java new file mode 100644 index 000000000..d82d9f1ab --- /dev/null +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailRespDTO.java @@ -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 rangeValues; + +} diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageBO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageRespDTO.java similarity index 76% rename from promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageBO.java rename to promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageRespDTO.java index 522027732..ad7416e00 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageBO.java +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardPageRespDTO.java @@ -11,12 +11,12 @@ import java.util.List; */ @Data @Accessors(chain = true) -public class CouponCardPageBO implements Serializable { +public class CouponCardPageRespDTO implements Serializable { /** * 优惠劵数组 */ - private List list; + private List list; /** * 总量 */ diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardReqDTO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardReqDTO.java new file mode 100644 index 000000000..d1bae56b0 --- /dev/null +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardReqDTO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageBO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageRespDTO.java similarity index 76% rename from promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageBO.java rename to promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageRespDTO.java index 15f33570d..3a86f3f55 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageBO.java +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplatePageRespDTO.java @@ -11,12 +11,12 @@ import java.util.List; */ @Data @Accessors(chain = true) -public class CouponTemplatePageBO implements Serializable { +public class CouponTemplatePageRespDTO implements Serializable { /** * 优惠劵(码)数组 */ - private List list; + private List list; /** * 总量 */ diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateReqDTO.java b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateReqDTO.java new file mode 100644 index 000000000..f81e564d8 --- /dev/null +++ b/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateReqDTO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-app/pom.xml b/promotion-service-project/promotion-service-app/pom.xml index 935e831b6..7717f549d 100644 --- a/promotion-service-project/promotion-service-app/pom.xml +++ b/promotion-service-project/promotion-service-app/pom.xml @@ -46,6 +46,12 @@ cn.iocoder.mall mall-spring-boot-starter-mybatis + + cn.iocoder.mall + product-service-api + 1.0-SNAPSHOT + compile + \ No newline at end of file diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponCardConvert.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponCardConvert.java new file mode 100644 index 000000000..562deb2cb --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponCardConvert.java @@ -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 convertToBO(List cardList); + + List convertToDTO(List 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 无法正确匹配方法的问题 + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponTemplateConvert.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponTemplateConvert.java new file mode 100644 index 000000000..ad7843a32 --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/coupon/CouponTemplateConvert.java @@ -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 convertToBO(List templateList); + + List convertToDTO(List 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); + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/recommend/ProductRecommendConvert.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/recommend/ProductRecommendConvert.java new file mode 100644 index 000000000..8cacb5188 --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/convert/recommend/ProductRecommendConvert.java @@ -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 convertToBO(List recommendList); + + @Mappings({}) + List convertToDTO(List recommendList); + + @Mappings({}) + ProductRecommendDO convert(ProductRecommendAddBO recommendAddDTO); + + @Mappings({}) + ProductRecommendDO convert(ProductRecommendUpdateBO recommendUpdateDTO); + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/CouponService.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/CouponService.java new file mode 100644 index 000000000..da75b159e --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/CouponService.java @@ -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 getCouponCardList(Integer userId, List spus) { + // 查询用户未使用的优惠劵列表 + List cards = couponCardMapper.selectListByUserIdAndStatus(userId, CouponCardStatusEnum.UNUSED.getValue()); + if (cards.isEmpty()) { + return Collections.emptyList(); + } + // 查询优惠劵模板集合 + Map templates = couponTemplateMapper.selectListByIds(cards.stream().map(CouponCardDO::getTemplateId).collect(Collectors.toSet())) + .stream().collect(Collectors.toMap(CouponTemplateDO::getId, template -> template)); + // 逐个判断是否可用 + List 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 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 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 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 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 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; + } + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardAvailableBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardAvailableBO.java new file mode 100644 index 000000000..2500fcc3a --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardAvailableBO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardBO.java similarity index 97% rename from promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardBO.java rename to promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardBO.java index 9d9a2b8fe..48c2e755c 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardBO.java +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardBO.java @@ -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; diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardDetailBO.java similarity index 98% rename from promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailBO.java rename to promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardDetailBO.java index 2847cbc60..e664d98ce 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponCardDetailBO.java +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardDetailBO.java @@ -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; diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardPageBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardPageBO.java new file mode 100644 index 000000000..59d0eff56 --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardPageBO.java @@ -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 list; + /** + * 总量 + */ + private Integer total; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardSpuBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardSpuBO.java new file mode 100644 index 000000000..32f45d52b --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardSpuBO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateAddBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateAddBO.java new file mode 100644 index 000000000..47d149a4a --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateAddBO.java @@ -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 ========== + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateUpdateBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateUpdateBO.java new file mode 100644 index 000000000..c2ef21e65 --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCardTemplateUpdateBO.java @@ -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; + } +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCodeTemplateUpdateBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCodeTemplateUpdateBO.java new file mode 100644 index 000000000..a8e9f80da --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponCodeTemplateUpdateBO.java @@ -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 { +} diff --git a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplateBO.java similarity index 98% rename from promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateBO.java rename to promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplateBO.java index e48f8f2c2..c987c8784 100644 --- a/promotion-service-project/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/rpc/coupon/dto/CouponTemplateBO.java +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplateBO.java @@ -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; diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplatePageBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplatePageBO.java new file mode 100644 index 000000000..437ba0bcc --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/coupon/bo/CouponTemplatePageBO.java @@ -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 list; + /** + * 总量 + */ + private Integer total; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/ProductRecommendService.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/ProductRecommendService.java new file mode 100644 index 000000000..e8770317e --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/ProductRecommendService.java @@ -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 getProductRecommendList(Integer type, Integer status) { + List 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; + } + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendAddBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendAddBO.java new file mode 100644 index 000000000..5914c0fa9 --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendAddBO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendBO.java new file mode 100644 index 000000000..da689a69e --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendBO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendPageBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendPageBO.java new file mode 100644 index 000000000..93b98db7f --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendPageBO.java @@ -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; + +} diff --git a/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendUpdateBO.java b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendUpdateBO.java new file mode 100644 index 000000000..8e8ec9e8f --- /dev/null +++ b/promotion-service-project/promotion-service-app/src/main/java/cn/iocoder/mall/promotionservice/service/recommend/bo/ProductRecommendUpdateBO.java @@ -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; + +}