mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	promotion:去除已经不使用的代码
This commit is contained in:
		@@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
    <name>${project.artifactId}</name>
 | 
			
		||||
    <description>
 | 
			
		||||
        market 模块 API,暴露给其它模块调用
 | 
			
		||||
        promotion 模块 API,暴露给其它模块调用
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.combination;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 拼团活动 Api 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author HUIHUI
 | 
			
		||||
 */
 | 
			
		||||
public interface CombinationActivityApi {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -41,14 +41,6 @@ public interface CombinationRecordApi {
 | 
			
		||||
     */
 | 
			
		||||
    boolean isCombinationRecordSuccess(Long userId, Long orderId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新拼团状态为【失败】
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId  用户编号
 | 
			
		||||
     * @param orderId 订单编号
 | 
			
		||||
     */
 | 
			
		||||
    void updateRecordStatusToFailed(Long userId, Long orderId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 【下单前】校验是否满足拼团活动条件
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.price;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格 API 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
public interface PriceApi {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 计算商品的价格
 | 
			
		||||
     *
 | 
			
		||||
     * @param calculateReqDTO 价格请求
 | 
			
		||||
     * @return 价格相应
 | 
			
		||||
     */
 | 
			
		||||
    PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.price.dto;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 优惠劵的匹配信息 Response DTO
 | 
			
		||||
 *
 | 
			
		||||
 * why 放在 price 包下?主要获取的时候,需要涉及到较多的价格计算逻辑,放在 price 可以更好的复用逻辑
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class CouponMeetRespDTO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 优惠劵编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    // ========== 非优惠劵的基本信息字段 ==========
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否匹配
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean meet;
 | 
			
		||||
    /**
 | 
			
		||||
     * 不匹配的提示,即 {@link #meet} = true 才有值
 | 
			
		||||
     *
 | 
			
		||||
     * 例如说:
 | 
			
		||||
     * 1. 所结算商品没有符合条件的商品
 | 
			
		||||
     * 2. 差 XXX 元可用优惠劵
 | 
			
		||||
     * 3. 优惠劵未到使用时间
 | 
			
		||||
     */
 | 
			
		||||
    private String meetTip;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.price.dto;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.Min;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格计算 Request DTO
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Deprecated
 | 
			
		||||
public class PriceCalculateReqDTO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户编号
 | 
			
		||||
     *
 | 
			
		||||
     * 对应 MemberUserDO 的 id 编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 优惠劵编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long couponId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 收货地址编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long addressId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 商品 SKU 数组
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "商品数组不能为空")
 | 
			
		||||
    private List<Item> items;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 商品 SKU
 | 
			
		||||
     */
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class Item {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * SKU 编号
 | 
			
		||||
         */
 | 
			
		||||
        @NotNull(message = "商品 SKU 编号不能为空")
 | 
			
		||||
        private Long skuId;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * SKU 数量
 | 
			
		||||
         */
 | 
			
		||||
        @NotNull(message = "商品 SKU 数量不能为空")
 | 
			
		||||
        @Min(value = 0L, message = "商品 SKU 数量必须大于等于 0") // 可传递 0 数量,用于购物车未选中的情况
 | 
			
		||||
        private Integer count;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,252 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.price.dto;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格计算 Response DTO
 | 
			
		||||
 *
 | 
			
		||||
 * 整体设计,参考 taobao 的技术文档:
 | 
			
		||||
 * 1. <a href="https://developer.alibaba.com/docs/doc.htm?treeId=1&articleId=1029&docType=1">订单管理</a>
 | 
			
		||||
 * 2. <a href="https://open.taobao.com/docV3.htm?docId=108471&docType=1">常用订单金额说明</a>
 | 
			
		||||
 *
 | 
			
		||||
 * 举个例子:<a href="https://img.alicdn.com/top/i1/LB1mALAi4HI8KJjy1zbXXaxdpXa">订单图</a>
 | 
			
		||||
 * 输入:
 | 
			
		||||
 * 1. 订单实付: trade.payment = 198.00;订单邮费:5 元;
 | 
			
		||||
 * 2. 商品级优惠 圣诞价: 省 29.00 元 和 圣诞价:省 150.00 元; 订单级优惠,圣诞 2:省 5.00 元;
 | 
			
		||||
 * 分摊:
 | 
			
		||||
 * 1. 商品 1:原价 108 元,优惠 29 元,子订单实付 79 元,分摊主订单优惠 1.99 元;
 | 
			
		||||
 * 2. 商品 2:原价 269 元,优惠 150 元,子订单实付 119 元,分摊主订单优惠 3.01 元;
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Deprecated
 | 
			
		||||
public class PriceCalculateRespDTO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单
 | 
			
		||||
     */
 | 
			
		||||
    private Order order;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 营销活动数组
 | 
			
		||||
     *
 | 
			
		||||
     * 只对应 {@link Order#items} 商品匹配的活动
 | 
			
		||||
     */
 | 
			
		||||
    private List<Promotion> promotions;
 | 
			
		||||
 | 
			
		||||
    // TODO @芋艿:需要改造下,主要是价格字段
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单
 | 
			
		||||
     */
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class Order {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品原价(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 基于 {@link OrderItem#getOriginalPrice()} 求和
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 trade.total_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer totalPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 订单优惠(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 order.discount_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer discountPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 优惠劵减免金额(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 trade.coupon_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer couponPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 积分减免金额(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 trade.point_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer pointPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 运费金额,单位:分
 | 
			
		||||
         */
 | 
			
		||||
        private Integer deliveryPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 最终购买金额(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * = {@link OrderItem#getPayPrice()} 求和
 | 
			
		||||
         * - {@link #couponPrice}
 | 
			
		||||
         * - {@link #pointPrice}
 | 
			
		||||
         * + {@link #deliveryPrice}
 | 
			
		||||
         * - {@link #discountPrice}
 | 
			
		||||
         */
 | 
			
		||||
        private Integer payPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品 SKU 数组
 | 
			
		||||
         */
 | 
			
		||||
        private List<OrderItem> items;
 | 
			
		||||
 | 
			
		||||
        // ========== 营销基本信息 ==========
 | 
			
		||||
        /**
 | 
			
		||||
         * 优惠劵编号
 | 
			
		||||
         */
 | 
			
		||||
        private Long couponId;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单商品 SKU
 | 
			
		||||
     */
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class OrderItem {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * SPU 编号
 | 
			
		||||
         */
 | 
			
		||||
        private Long spuId;
 | 
			
		||||
        /**
 | 
			
		||||
         * SKU 编号
 | 
			
		||||
         */
 | 
			
		||||
        private Long skuId;
 | 
			
		||||
        /**
 | 
			
		||||
         * 购买数量
 | 
			
		||||
         */
 | 
			
		||||
        private Integer count;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品原价(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * = {@link #originalUnitPrice} * {@link #getCount()}
 | 
			
		||||
         */
 | 
			
		||||
        private Integer originalPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品原价(单),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 ProductSkuDO 的 price 字段
 | 
			
		||||
         * 对应 taobao 的 order.price 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer originalUnitPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品优惠(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * 商品级优惠:对单个商品的,常见如:商品原价的 8 折;商品原价的减 50 元
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 order.discount_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer discountPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 子订单实付金额,不算主订单分摊金额,单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * = {@link #originalPrice}
 | 
			
		||||
         * - {@link #discountPrice}
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 order.payment 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer payPrice;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 子订单分摊金额(总),单位:分
 | 
			
		||||
         * 需要分摊 {@link Order#discountPrice}、{@link Order#couponPrice}、{@link Order#pointPrice}
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 order.part_mjz_discount 字段
 | 
			
		||||
         * 淘宝说明:子订单分摊优惠基础逻辑:一般正常优惠券和满减优惠按照子订单的金额进行分摊,特殊情况如果优惠券是指定商品使用的,只会分摊到对应商品子订单上不分摊。
 | 
			
		||||
         */
 | 
			
		||||
        private Integer orderPartPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 分摊后子订单实付金额(总),单位:分
 | 
			
		||||
         *
 | 
			
		||||
         * = {@link #payPrice}
 | 
			
		||||
         * - {@link #orderPartPrice}
 | 
			
		||||
         *
 | 
			
		||||
         * 对应 taobao 的 divide_order_fee 字段
 | 
			
		||||
         */
 | 
			
		||||
        private Integer orderDividePrice;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 营销明细
 | 
			
		||||
     */
 | 
			
		||||
    @Data
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public static class Promotion {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 营销编号
 | 
			
		||||
         *
 | 
			
		||||
         * 例如说:营销活动的编号、优惠劵的编号
 | 
			
		||||
         */
 | 
			
		||||
        private Long id;
 | 
			
		||||
        /**
 | 
			
		||||
         * 营销名字
 | 
			
		||||
         */
 | 
			
		||||
        private String name;
 | 
			
		||||
        /**
 | 
			
		||||
         * 营销类型
 | 
			
		||||
         *
 | 
			
		||||
         * 枚举 {@link PromotionTypeEnum}
 | 
			
		||||
         */
 | 
			
		||||
        private Integer type;
 | 
			
		||||
        /**
 | 
			
		||||
         * 营销级别
 | 
			
		||||
         *
 | 
			
		||||
         * 枚举 @link PromotionLevelEnum} TODO PromotionLevelEnum 没有这个枚举类
 | 
			
		||||
         */
 | 
			
		||||
        private Integer level;
 | 
			
		||||
        /**
 | 
			
		||||
         * 计算时的原价(总),单位:分
 | 
			
		||||
         */
 | 
			
		||||
        private Integer totalPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 计算时的优惠(总),单位:分
 | 
			
		||||
         */
 | 
			
		||||
        private Integer discountPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 匹配的商品 SKU 数组
 | 
			
		||||
         */
 | 
			
		||||
        private List<PromotionItem> items;
 | 
			
		||||
 | 
			
		||||
        // ========== 匹配情况 ==========
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 是否满足优惠条件
 | 
			
		||||
         */
 | 
			
		||||
        private Boolean match;
 | 
			
		||||
        /**
 | 
			
		||||
         * 满足条件的提示
 | 
			
		||||
         *
 | 
			
		||||
         * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元”
 | 
			
		||||
         * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元”
 | 
			
		||||
         */
 | 
			
		||||
        private String description;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 营销匹配的商品 SKU
 | 
			
		||||
     */
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class PromotionItem {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 商品 SKU 编号
 | 
			
		||||
         */
 | 
			
		||||
        private Long skuId;
 | 
			
		||||
        /**
 | 
			
		||||
         * 计算时的原价(总),单位:分
 | 
			
		||||
         */
 | 
			
		||||
        private Integer originalPrice;
 | 
			
		||||
        /**
 | 
			
		||||
         * 计算时的优惠(总),单位:分
 | 
			
		||||
         */
 | 
			
		||||
        private Integer discountPrice;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
    <name>${project.artifactId}</name>
 | 
			
		||||
 | 
			
		||||
    <description>
 | 
			
		||||
        market模块,主要实现营销相关功能
 | 
			
		||||
        例如:营销活动、banner广告、优惠券、优惠码等功能。
 | 
			
		||||
        promotion 模块,主要实现营销相关功能
 | 
			
		||||
        例如:营销活动、banner 广告、优惠券、优惠码等功能。
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
@@ -49,10 +49,6 @@
 | 
			
		||||
            <groupId>cn.iocoder.boot</groupId>
 | 
			
		||||
            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cn.iocoder.boot</groupId>
 | 
			
		||||
            <artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- Web 相关 -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.combination;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 拼团活动 Api 接口实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author HUIHUI
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class CombinationActivityApiImpl implements CombinationActivityApi {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -44,11 +44,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
 | 
			
		||||
        return CombinationRecordStatusEnum.isSuccess(record.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void updateRecordStatusToFailed(Long userId, Long orderId) {
 | 
			
		||||
        recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) {
 | 
			
		||||
        return recordService.validateJoinCombination(userId, activityId, headId, skuId, count);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.api.price;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.price.PriceService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格 API 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class PriceApiImpl implements PriceApi {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private PriceService priceService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) {
 | 
			
		||||
        //return priceService.calculatePrice(calculateReqDTO); TODO 没有 calculatePrice 这个方法
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,49 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.convert.price;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface PriceConvert {
 | 
			
		||||
 | 
			
		||||
    PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);
 | 
			
		||||
 | 
			
		||||
    default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List<ProductSkuRespDTO> skuList) {
 | 
			
		||||
        // 创建 PriceCalculateRespDTO 对象
 | 
			
		||||
        PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO();
 | 
			
		||||
        // 创建它的 Order 属性
 | 
			
		||||
        PriceCalculateRespDTO.Order order = new PriceCalculateRespDTO.Order().setTotalPrice(0).setDiscountPrice(0)
 | 
			
		||||
                .setCouponPrice(0).setPointPrice(0).setDeliveryPrice(0).setPayPrice(0)
 | 
			
		||||
                .setItems(new ArrayList<>()).setCouponId(calculateReqDTO.getCouponId());
 | 
			
		||||
        priceCalculate.setOrder(order).setPromotions(new ArrayList<>());
 | 
			
		||||
        // 创建它的 OrderItem 属性
 | 
			
		||||
        Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(),
 | 
			
		||||
                PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount);
 | 
			
		||||
        skuList.forEach(sku -> {
 | 
			
		||||
            Integer count = skuIdCountMap.get(sku.getId());
 | 
			
		||||
            PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem()
 | 
			
		||||
                    .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count)
 | 
			
		||||
                    .setOriginalUnitPrice(sku.getPrice()).setOriginalPrice(sku.getPrice() * count)
 | 
			
		||||
                    .setDiscountPrice(0).setOrderPartPrice(0);
 | 
			
		||||
            orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
 | 
			
		||||
            priceCalculate.getOrder().getItems().add(orderItem);
 | 
			
		||||
            // 补充价格信息到 Order 中
 | 
			
		||||
            order.setTotalPrice(order.getTotalPrice() + orderItem.getOriginalPrice())
 | 
			
		||||
                    .setPayPrice(order.getTotalPrice());
 | 
			
		||||
        });
 | 
			
		||||
        return priceCalculate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CouponMeetRespDTO convert(CouponDO coupon);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -21,15 +21,6 @@ import java.util.Map;
 | 
			
		||||
 */
 | 
			
		||||
public interface CombinationRecordService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新拼团状态
 | 
			
		||||
     *
 | 
			
		||||
     * @param status  状态
 | 
			
		||||
     * @param userId  用户编号
 | 
			
		||||
     * @param orderId 订单编号
 | 
			
		||||
     */
 | 
			
		||||
    void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 【下单前】校验是否满足拼团活动条件
 | 
			
		||||
     *
 | 
			
		||||
@@ -62,15 +53,6 @@ public interface CombinationRecordService {
 | 
			
		||||
     */
 | 
			
		||||
    CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取拼团记录
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId     用户 id
 | 
			
		||||
     * @param activityId 活动 id
 | 
			
		||||
     * @return 拼团记录列表
 | 
			
		||||
     */
 | 
			
		||||
    List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 【下单前】校验是否满足拼团活动条件
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -66,25 +66,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private TradeOrderApi tradeOrderApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
 | 
			
		||||
        // 校验拼团是否存在
 | 
			
		||||
        CombinationRecordDO record = validateCombinationRecord(userId, orderId);
 | 
			
		||||
 | 
			
		||||
        // 更新状态
 | 
			
		||||
        combinationRecordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setStatus(status));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
 | 
			
		||||
        // 校验拼团是否存在
 | 
			
		||||
        CombinationRecordDO recordDO = combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);
 | 
			
		||||
        if (recordDO == null) {
 | 
			
		||||
            throw exception(COMBINATION_RECORD_NOT_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
        return recordDO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO @芋艿:在详细预览下;
 | 
			
		||||
    @Override
 | 
			
		||||
    public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
 | 
			
		||||
@@ -229,11 +210,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
 | 
			
		||||
        return combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId) {
 | 
			
		||||
        return combinationRecordMapper.selectListByUserIdAndActivityId(userId, activityId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId,
 | 
			
		||||
                                                                  Long skuId, Integer count) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.service.price;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格计算 Service 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
public interface PriceService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得优惠劵的匹配信息列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param calculateReqDTO 价格请求
 | 
			
		||||
     * @return 价格响应
 | 
			
		||||
     */
 | 
			
		||||
    List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,96 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.service.price;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 价格计算 Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * 优惠计算顺序:min(限时折扣, 会员折扣) > 满减送 > 优惠券。
 | 
			
		||||
 * 参考文档:
 | 
			
		||||
 * 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384">有赞文档:限时折扣、满减送、优惠券哪个优先计算?</a>
 | 
			
		||||
 *
 | 
			
		||||
 * TODO 芋艿:进一步完善
 | 
			
		||||
 * 1. 限时折扣:指定金额、减免金额、折扣
 | 
			
		||||
 * 2. 满减送:循环、折扣
 | 
			
		||||
 * 3. 优惠劵:待定
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@Validated
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class PriceServiceImpl implements PriceService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CouponService couponService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO) {
 | 
			
		||||
        // 先计算一轮价格
 | 
			
		||||
//        PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO);
 | 
			
		||||
        PriceCalculateRespDTO priceCalculate = null;
 | 
			
		||||
 | 
			
		||||
        // 获得用户的待使用优惠劵
 | 
			
		||||
        List<CouponDO> couponList = couponService.getCouponList(calculateReqDTO.getUserId(), CouponStatusEnum.UNUSED.getStatus());
 | 
			
		||||
        if (CollUtil.isEmpty(couponList)) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 获得优惠劵的匹配信息
 | 
			
		||||
        return CollectionUtils.convertList(couponList, coupon -> {
 | 
			
		||||
            CouponMeetRespDTO couponMeetRespDTO = PriceConvert.INSTANCE.convert(coupon);
 | 
			
		||||
            try {
 | 
			
		||||
                // 校验优惠劵
 | 
			
		||||
                couponService.validCoupon(coupon);
 | 
			
		||||
 | 
			
		||||
                // 获得匹配的商品 SKU 数组
 | 
			
		||||
                // TODO 芋艿:后续处理
 | 
			
		||||
//                List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon);
 | 
			
		||||
                List<PriceCalculateRespDTO.OrderItem> orderItems = null;
 | 
			
		||||
                if (CollUtil.isEmpty(orderItems)) {
 | 
			
		||||
                    return couponMeetRespDTO.setMeet(false).setMeetTip("所结算商品没有符合条件的商品");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 计算是否满足优惠劵的使用金额
 | 
			
		||||
                Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
 | 
			
		||||
                assert originPrice != null;
 | 
			
		||||
                if (originPrice < coupon.getUsePrice()) {
 | 
			
		||||
                    return couponMeetRespDTO.setMeet(false)
 | 
			
		||||
//                            .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice)));
 | 
			
		||||
                            .setMeetTip("所结算的商品中未满足使用的金额");
 | 
			
		||||
                }
 | 
			
		||||
            } catch (ServiceException serviceException) {
 | 
			
		||||
                couponMeetRespDTO.setMeet(false);
 | 
			
		||||
                if (serviceException.getCode().equals(COUPON_VALID_TIME_NOT_NOW.getCode())) {
 | 
			
		||||
                    couponMeetRespDTO.setMeetTip("优惠劵未到使用时间");
 | 
			
		||||
                } else {
 | 
			
		||||
                    log.error("[getMeetCouponList][calculateReqDTO({}) 获得优惠劵匹配信息异常]", calculateReqDTO, serviceException);
 | 
			
		||||
                    couponMeetRespDTO.setMeetTip("优惠劵不满足使用条件");
 | 
			
		||||
                }
 | 
			
		||||
                return couponMeetRespDTO;
 | 
			
		||||
            }
 | 
			
		||||
            // 满足
 | 
			
		||||
            return couponMeetRespDTO.setMeet(true);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.service.price;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
 | 
			
		||||
import static java.util.Arrays.asList;
 | 
			
		||||
import static java.util.Collections.singletonList;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.*;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.doThrow;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@link PriceServiceImpl} 的单元测试
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
public class PriceServiceTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private PriceServiceImpl priceService;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RewardActivityService rewardActivityService;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private CouponService couponService;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ProductSkuApi productSkuApi;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 测试满减送活动,不匹配的情况
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculatePrice_rewardActivityNotMeet() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetMeetCouponList() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(1024L)
 | 
			
		||||
                .setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2)));
 | 
			
		||||
        // mock 方法(商品 SKU 信息)
 | 
			
		||||
        ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));
 | 
			
		||||
        when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku));
 | 
			
		||||
        // mock 方法(情况一:优惠劵未到使用时间)
 | 
			
		||||
        CouponDO coupon01 = randomPojo(CouponDO.class);
 | 
			
		||||
        doThrow(new ServiceException(COUPON_VALID_TIME_NOT_NOW)).when(couponService).validCoupon(coupon01);
 | 
			
		||||
        // mock 方法(情况二:所结算商品没有符合条件的商品)
 | 
			
		||||
        CouponDO coupon02 = randomPojo(CouponDO.class);
 | 
			
		||||
        // mock 方法(情况三:使用金额不足)
 | 
			
		||||
        CouponDO coupon03 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
 | 
			
		||||
                .setUsePrice(300));
 | 
			
		||||
        // mock 方法(情况五:满足条件)
 | 
			
		||||
        CouponDO coupon04 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
 | 
			
		||||
                .setUsePrice(190));
 | 
			
		||||
        // mock 方法(获得用户的待使用优惠劵)
 | 
			
		||||
        when(couponService.getCouponList(eq(1024L), eq(CouponStatusEnum.UNUSED.getStatus())))
 | 
			
		||||
                .thenReturn(asList(coupon01, coupon02, coupon03, coupon04));
 | 
			
		||||
        // 调用
 | 
			
		||||
        List<CouponMeetRespDTO> list = priceService.getMeetCouponList(calculateReqDTO);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(list.size(), 4);
 | 
			
		||||
        // 断言情况一:优惠劵未到使用时间
 | 
			
		||||
        CouponMeetRespDTO couponMeetRespDTO01 = list.get(0);
 | 
			
		||||
        assertPojoEquals(couponMeetRespDTO01, coupon01);
 | 
			
		||||
        assertFalse(couponMeetRespDTO01.getMeet());
 | 
			
		||||
        assertEquals(couponMeetRespDTO01.getMeetTip(), "优惠劵未到使用时间");
 | 
			
		||||
        // 断言情况二:所结算商品没有符合条件的商品
 | 
			
		||||
        CouponMeetRespDTO couponMeetRespDTO02 = list.get(1);
 | 
			
		||||
        assertPojoEquals(couponMeetRespDTO02, coupon02);
 | 
			
		||||
        assertFalse(couponMeetRespDTO02.getMeet());
 | 
			
		||||
        assertEquals(couponMeetRespDTO02.getMeetTip(), "所结算商品没有符合条件的商品");
 | 
			
		||||
        // 断言情况三:差 %s 元可用优惠劵
 | 
			
		||||
        CouponMeetRespDTO couponMeetRespDTO03 = list.get(2);
 | 
			
		||||
        assertPojoEquals(couponMeetRespDTO03, coupon03);
 | 
			
		||||
        assertFalse(couponMeetRespDTO03.getMeet());
 | 
			
		||||
        assertEquals(couponMeetRespDTO03.getMeetTip(), "所结算的商品中未满足使用的金额");
 | 
			
		||||
        // 断言情况四:满足条件
 | 
			
		||||
        CouponMeetRespDTO couponMeetRespDTO04 = list.get(3);
 | 
			
		||||
        assertPojoEquals(couponMeetRespDTO04, coupon04);
 | 
			
		||||
        assertTrue(couponMeetRespDTO04.getMeet());
 | 
			
		||||
        assertNull(couponMeetRespDTO04.getMeetTip());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user