将 market 模块,调整成 promotion 模块

This commit is contained in:
YunaiV
2022-10-30 17:37:07 +08:00
parent 829bbf58b5
commit e6acdf7098
64 changed files with 152 additions and 155 deletions

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-mall</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-promotion-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
market 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,4 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.promotion.api;

View File

@ -0,0 +1,21 @@
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);
}

View File

@ -0,0 +1,56 @@
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
public class PriceCalculateReqDTO {
/**
* 用户编号
*
* 对应 MemberUserDO 的 id 编号
*/
private Long userId;
/**
* 优惠劵编号
*/
private Long couponId;
/**
* 商品 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;
}
}

View File

@ -0,0 +1,248 @@
package cn.iocoder.yudao.module.promotion.api.price.dto;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum;
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
public class PriceCalculateRespDTO {
/**
* 订单
*/
private Order order;
/**
* 营销活动数组
*
* 只对应 {@link Order#items} 商品匹配的活动
*/
private List<Promotion> promotions;
/**
* 订单
*/
@Data
public static class Order {
/**
* 商品原价(总),单位:分
*
* 基于 {@link OrderItem#getOriginalPrice()} 求和
* 对应 taobao 的 trade.total_fee 字段
*/
private Integer originalPrice;
/**
* 订单优惠(总),单位:分
*
* 订单级优惠:对主订单的优惠,常见如:订单满 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}
*/
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
public static class Promotion {
/**
* 营销编号
*
* 例如说:营销活动的编号、优惠劵的编号
*/
private Long id;
/**
* 营销名字
*/
private String name;
/**
* 营销类型
*
* 枚举 {@link PromotionTypeEnum}
*/
private Integer type;
/**
* 营销级别
*
* 枚举 {@link PromotionLevelEnum}
*/
private Integer level;
/**
* 计算时的原价(总),单位:分
*/
private Integer originalPrice;
/**
* 计算时的优惠(总),单位:分
*/
private Integer discountPrice;
/**
* 匹配的商品 SKU 数组
*/
private List<PromotionItem> items;
// ========== 匹配情况 ==========
/**
* 是否满足优惠条件
*/
private Boolean meet;
/**
* 满足条件的提示
*
* 如果 {@link #meet} = true 满足,则提示“圣诞价:省 150.00 元”
* 如果 {@link #meet} = false 不满足,则提示“购满 85 元,可减 40 元”
*/
private String meetTip;
}
/**
* 营销匹配的商品 SKU
*/
@Data
public static class PromotionItem {
/**
* 商品 SKU 编号
*/
private Long skuId;
/**
* 计算时的原价(总),单位:分
*/
private Integer originalPrice;
/**
* 计算时的优惠(总),单位:分
*/
private Integer discountPrice;
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.promotion.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* market 错误码枚举类
* <p>
* market 系统,使用 1-003-000-000 段
*/
public interface ErrorCodeConstants {
// ========== 促销活动相关 1003001000 ============ TODO 芋艿:看看是不是要删除掉
ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "促销活动不存在");
// ========== Banner 相关 1003002000 ============
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在");
// ========== Coupon 相关 1003003000 ============
ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1003003000, "优惠劵没有可使用的商品!");
ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1003003000, "不满足优惠劵使用的最低金额");
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.promotion.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 促销活动的状态枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum PromotionActivityStatusEnum implements IntArrayValuable {
WAIT(10, "未开始"),
RUN(20, "进行中"),
END(30, "已结束"),
CLOSE(40, "已关闭");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionActivityStatusEnum::getStatus).toArray();
/**
* 状态值
*/
private final Integer status;
/**
* 状态名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.promotion.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 营销的条件类型枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum PromotionConditionTypeEnum implements IntArrayValuable {
PRICE(10, "满 N 元"),
COUNT(20, "满 N 件");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionConditionTypeEnum::getType).toArray();
/**
* 类型值
*/
private final Integer type;
/**
* 类型名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.promotion.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 营销的级别枚举
*
* 参考有赞:<a href="https://img01.yzcdn.cn/upload_files/2021/11/02/FhDjUrNDq-G0wjNdYDtgUX09fdGj.png">营销级别</a>
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum PromotionLevelEnum implements IntArrayValuable {
ORDER(1, "订单级"), // 多个商品,进行组合后优惠。例如说:满减送、打包一口价、第二件半价
SKU(2, "商品级"), // 单个商品,直接优惠。例如说:限时折扣、会员折扣
COUPON(3, "优惠劵"), // 多个商品,进行组合后优惠。例如说:优惠劵
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionLevelEnum::getLevel).toArray();
/**
* 级别值
*/
private final Integer level;
/**
* 类型名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.promotion.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 营销的商品范围枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum PromotionProductScopeEnum implements IntArrayValuable {
ALL(1, "全部商品参与"),
SPU(2, "指定商品参与"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray();
/**
* 范围值
*/
private final Integer scope;
/**
* 范围名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.promotion.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 营销类型枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum PromotionTypeEnum implements IntArrayValuable {
DISCOUNT_ACTIVITY(1, "限时折扣"),
REWARD_ACTIVITY(2, "满减送"),
MEMBER(3, "会员折扣"),
COUPON(4, "优惠劵")
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionTypeEnum::getType).toArray();
/**
* 类型值
*/
private final Integer type;
/**
* 类型名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}