1. 订单服务,修改为交易服务
2. 迁移订单创建 rpc 接口
This commit is contained in:
40
trade-service-project/pom.xml
Normal file
40
trade-service-project/pom.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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>
|
||||
<artifactId>onemall</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>trade-service-project</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>trade-service-api</module>
|
||||
<module>trade-service-app</module>
|
||||
<module>trade-service-integration-test</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- onemall 基础 bom 文件 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-dependencies</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 自身项目 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>trade-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
||||
31
trade-service-project/trade-service-api/pom.xml
Normal file
31
trade-service-project/trade-service-api/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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>
|
||||
<artifactId>trade-service-project</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>trade-service-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>common-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.iocoder.mall.tradeservice.enums;
|
||||
|
||||
import cn.iocoder.common.framework.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* 订单错误码
|
||||
* <p>
|
||||
* 错误码区间 [1-008-000-000 ~ 1-008-000-000]
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-23 11:23
|
||||
*/
|
||||
public interface OrderErrorCodeConstants {
|
||||
|
||||
// order
|
||||
ErrorCode ORDER_NOT_EXISTENT = new ErrorCode(1008000000, "获取订单不存在!");
|
||||
ErrorCode ORDER_GET_SKU_FAIL = new ErrorCode(1008000001, "获取商品失败!)");
|
||||
ErrorCode ORDER_GET_SKU_NOT_EXISTENT = new ErrorCode(1008000002, "获取的商品不存在!");
|
||||
ErrorCode ORDER_PAY_AMOUNT_NOT_NEGATIVE = new ErrorCode(1008000003, "支付金额不能为负数!");
|
||||
ErrorCode ORDER_STATUS_NOT_CANCEL = new ErrorCode(1008000004, "订单状态不能取消!)");
|
||||
ErrorCode ORDER_DELIVERY_INCORRECT_DATA = new ErrorCode(1008000005, "订单发货数据不正确!");
|
||||
ErrorCode ORDER_INSUFFICIENT_INVENTORY = new ErrorCode(1008000006, "库存不足!");
|
||||
ErrorCode ORDER_GOODS_AMOUNT_INCORRECT = new ErrorCode(1008000007, "商品金额非法!");
|
||||
ErrorCode ORDER_GET_GOODS_INFO_INCORRECT = new ErrorCode(1008000008, "获取额商品信息不正确!");
|
||||
ErrorCode ORDER_GET_USER_ADDRESS_FAIL = new ErrorCode(1008000009, "获取用户地址失败!");
|
||||
ErrorCode ORDER_GET_PAY_FAIL = new ErrorCode(1008000010, "调用pay失败!");
|
||||
ErrorCode ORDER_NOT_USER_ORDER = new ErrorCode(1008000011, "不是该用户的订单!");
|
||||
ErrorCode ORDER_UNABLE_CONFIRM_ORDER = new ErrorCode(1008000012, "状态不对不能确认订单!");
|
||||
ErrorCode ORDER_CREATE_CART_IS_EMPTY = new ErrorCode(1008000013, "购物车无选中的商品,无法创建订单");
|
||||
ErrorCode ORDER_STATUS_NOT_WAITING_PAYMENT = new ErrorCode(1008000014, "订单不处于等待支付状态");
|
||||
ErrorCode ORDER_PAY_AMOUNT_ERROR = new ErrorCode(1008000015, "订单金额不正确");
|
||||
|
||||
// order item
|
||||
ErrorCode ORDER_ITEM_ONLY_ONE = new ErrorCode(1008000200, "订单Item只有一个!");
|
||||
ErrorCode ORDER_ITEM_SOME_NOT_EXISTS = new ErrorCode(1008000201, "有不存在的商品!");
|
||||
|
||||
// 订单退货
|
||||
ErrorCode ORDER_RETURN_NO_RETURN_APPLY = new ErrorCode(1008000400, "未退货申请");
|
||||
ErrorCode ORDER_RETURN_NOT_EXISTENT = new ErrorCode(1008000401, "退货订单不存在");
|
||||
ErrorCode ORDER_RETURN_REFUND_FAILED = new ErrorCode(1008000402, "退款失败");
|
||||
|
||||
// ========== 购物车 ==========
|
||||
ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1008003000, "购物车项不存在");
|
||||
ErrorCode CARD_ITEM_SKU_NOT_FOUND = new ErrorCode(1008003001, "商品不存在");
|
||||
ErrorCode CARD_ITEM_SKU_QUANTITY_NOT_ENOUGH = new ErrorCode(1008003002, "商品库存不足");
|
||||
|
||||
// 工具类服务 1008004000
|
||||
ErrorCode DICT_SERVER_INVOKING_FAIL = new ErrorCode(1008004000, "字典服务调用失败!");
|
||||
ErrorCode ORDER_LOGISTICS_INVOKING_FAIL = new ErrorCode(1008004001, "订单物流调用失败!");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.aftersale;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 售后订单的状态枚举
|
||||
*
|
||||
* 整体流程,见 https://www.processon.com/view/link/5fbdf47f07912946156305d7
|
||||
*
|
||||
* 1. 在退款的情况下,需要 1 个来回
|
||||
* 2. 在退货退款的情况下,需要 2 个来回,额外增加一个买家退货的过程
|
||||
* 3. 在换货的情况下,需要 3 个来回,额外增加一个买家退货 + 卖家发货的过程
|
||||
*/
|
||||
@Getter
|
||||
public enum AfterSaleOrderStatusEnum {
|
||||
|
||||
WAIT_SELLER_AGREE(10, "售后申请待商家处理"),
|
||||
WAIT_BUYER_RETURN_GOODS(20, "商家同意售后申请,待买家处理"),
|
||||
SELLER_REFUSE_BUYER(30, "商家不同意售后申请,待买家处理"),
|
||||
WAIT_SELLER_CONFIRM_GOODS(40, "买家已退货,待商家确认收货"),
|
||||
WAIT_BUYER_CONFIRM_GOODS(50, "商家已发货,待买家确认收货"),
|
||||
SELLER_REFUSE_RETURN_GOODS(60, "商家拒绝收货,待买家处理"),
|
||||
SUCCESS(70, "售后成功"),
|
||||
CLOSED(80, "售后失败"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
AfterSaleOrderStatusEnum(Integer status, String desc) {
|
||||
this.status = status;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.aftersale;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 售后单的类型枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum AfterSaleTypeEnum {
|
||||
|
||||
IN_SALE(10, "售中退款"),
|
||||
AFTER_SALE(20, "售后退款");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
AfterSaleTypeEnum(Integer type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.aftersale;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 售后单的方式枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum AfterSaleWayEnum {
|
||||
|
||||
REFUND(10, "退款"),
|
||||
RETURN_AND_REFUND(20, "退货退款"),
|
||||
EXCHANGE(30, "换货");
|
||||
|
||||
/**
|
||||
* 方式
|
||||
*/
|
||||
private final Integer way;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
AfterSaleWayEnum(Integer way, String desc) {
|
||||
this.way = way;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.logistics;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 物流的配送类型
|
||||
*/
|
||||
@Getter
|
||||
public enum LogisticsDeliveryTypeEnum {
|
||||
|
||||
/**
|
||||
* 无需快递
|
||||
*/
|
||||
NULL(0),
|
||||
/**
|
||||
* 传统快递
|
||||
*/
|
||||
EXPRESS(1);
|
||||
|
||||
private final Integer deliveryType;
|
||||
|
||||
LogisticsDeliveryTypeEnum(Integer deliveryType) {
|
||||
this.deliveryType = deliveryType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.order;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 交易订单的售后状态的枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum TradeOrderAfterSaleStatusEnum {
|
||||
|
||||
NULL(0, "无"),
|
||||
IN_PROCESS(10, "售后中"),
|
||||
END(10, "售后结束");
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
TradeOrderAfterSaleStatusEnum(Integer status, String desc) {
|
||||
this.status = status;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.mall.tradeservice.enums.order;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 交易订单 - 状态蜜桔
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-16 14:06
|
||||
*/
|
||||
@Getter
|
||||
public enum TradeOrderStatusEnum {
|
||||
|
||||
WAITING_PAYMENT(10, "等待付款"),
|
||||
WAIT_SHIPMENT(20, "等待发货"),
|
||||
ALREADY_SHIPMENT(30, "已发货"),
|
||||
COMPLETED(40, "已完成"),
|
||||
CLOSED(50, "已关闭");
|
||||
|
||||
/**
|
||||
* 状态值
|
||||
*/
|
||||
private final Integer value;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
TradeOrderStatusEnum(int value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 购物车 Rpc 接口
|
||||
*/
|
||||
public interface CartRpc {
|
||||
|
||||
/**
|
||||
* 添加商品到购物车
|
||||
*
|
||||
* @param addReqDTO 添加商品信息
|
||||
* @return 成功
|
||||
*/
|
||||
CommonResult<Boolean> addCartItem(CartItemAddReqDTO addReqDTO);
|
||||
|
||||
/**
|
||||
* 更新购物车商品数量
|
||||
*
|
||||
* @param updateQuantityReqDTO 更新商品数量 DTO
|
||||
* @return 成功
|
||||
*/
|
||||
CommonResult<Boolean> updateCartItemQuantity(CartItemUpdateQuantityReqDTO updateQuantityReqDTO);
|
||||
|
||||
/**
|
||||
* 更新购物车商品是否选中
|
||||
*
|
||||
* @param updateSelectedReqDTO 更新商品是否选中 DTO
|
||||
* @return 成功
|
||||
*/
|
||||
CommonResult<Boolean> updateCartItemSelected(CartItemUpdateSelectedReqDTO updateSelectedReqDTO);
|
||||
|
||||
/**
|
||||
* 删除购物车商品列表
|
||||
*
|
||||
* @param deleteListReqDTO 删除商品列表 DTO
|
||||
* @return 成功
|
||||
*/
|
||||
CommonResult<Boolean> deleteCartItems(CartItemDeleteListReqDTO deleteListReqDTO);
|
||||
|
||||
/**
|
||||
* 查询用户在购物车中的商品数量
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 商品数量
|
||||
*/
|
||||
CommonResult<Integer> sumCartItemQuantity(Integer userId);
|
||||
|
||||
/**
|
||||
* 查询用户在购物车种的商品列表
|
||||
*
|
||||
* @param listReqDTO 查询条件 DTO
|
||||
* @return 购物车中商品列表信息
|
||||
*/
|
||||
CommonResult<List<CartItemRespDTO>> listCartItems(CartItemListReqDTO listReqDTO);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 购物车添加购物项 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemAddReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@NotNull(message = "数量不能为空")
|
||||
@Min(message = "数量必须大于 0", value = 1L)
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 购物车删除商品列表 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemDeleteListReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 商品 SKU 编号列表
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号列表不能为空")
|
||||
private List<Integer> skuIds;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 购物车的商品信息查询 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemListReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 购物车的商品信息 Response DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemRespDTO implements Serializable {
|
||||
|
||||
// ========= 基础字段 BEGIN =========
|
||||
|
||||
/**
|
||||
* 编号,唯一自增。
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
// ========= 基础字段 END =========
|
||||
|
||||
// ========= 买家信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
// ========= 买家信息 END =========
|
||||
|
||||
// ========= 商品信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品购买数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
// ========= 商品信息 END =========
|
||||
|
||||
// ========= 优惠信息 BEGIN =========
|
||||
|
||||
// /**
|
||||
// * 商品营销活动编号
|
||||
// */
|
||||
// private Integer activityId;
|
||||
// /**
|
||||
// * 商品营销活动类型
|
||||
// */
|
||||
// private Integer activityType;
|
||||
|
||||
// ========= 优惠信息 END =========
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 购物车更新数量 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemUpdateQuantityReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@NotNull(message = "数量不能为空")
|
||||
@Min(message = "数量必须大于 0", value = 1L)
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 购物车更新是否选中 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemUpdateSelectedReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 商品 SKU 编号列表
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号列表不能为空")
|
||||
private Collection<Integer> skuIds;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
@NotNull(message = "是否选中不能为空")
|
||||
private Boolean selected;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.order;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderCreateReqDTO;
|
||||
|
||||
/**
|
||||
* 交易订单 Rpc 接口
|
||||
*/
|
||||
public interface TradeOrderRpc {
|
||||
|
||||
/**
|
||||
* 创建交易订单
|
||||
*
|
||||
* @param createReqDTO 订单信息
|
||||
* @return 订单编号
|
||||
*/
|
||||
CommonResult<Integer> createTradeOrder(TradeOrderCreateReqDTO createReqDTO);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.order.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易订单创建 Request DTO
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-16 14:42
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class TradeOrderCreateReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
@NotNull(message = "用户 IP 不能为空")
|
||||
private String ip;
|
||||
/**
|
||||
* 收件地址编号
|
||||
*/
|
||||
@NotNull(message = "用户地址不能为空")
|
||||
private Integer userAddressId;
|
||||
/**
|
||||
* 优惠劵编号
|
||||
*/
|
||||
private Integer couponCardId;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 订单商品项列表
|
||||
*/
|
||||
@NotNull(message = "必须选择购买的商品")
|
||||
private List<OrderItem> orderItems;
|
||||
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class OrderItem implements Serializable {
|
||||
|
||||
/**
|
||||
* 商品编号
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 购买数量不能为空")
|
||||
@Min(value = 1, message = "商品 SKU 购买数量必须大于 0")
|
||||
private Integer quantity;
|
||||
}
|
||||
|
||||
}
|
||||
140
trade-service-project/trade-service-app/pom.xml
Normal file
140
trade-service-project/trade-service-app/pom.xml
Normal file
@@ -0,0 +1,140 @@
|
||||
<?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>
|
||||
<artifactId>trade-service-project</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>trade-service-app</artifactId>
|
||||
<dependencies>
|
||||
<!-- RPC 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 系统服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>system-service-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 用户服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>user-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 商品服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>product-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 订单服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>trade-service-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 营销服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>promotion-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId> <!-- 需要开启 Web 容器,因为 Actuator 需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<!-- MQ 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-rocketmq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 和 Config 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-jdk8</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<!-- 使用 spring-boot-maven-plugin 插件打包 -->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.iocoder.mall.tradeservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TradeServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TradeServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.mall.tradeservice.client.product;
|
||||
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuRpc;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuListQueryReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class ProductSkuClient {
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
||||
private ProductSkuRpc productSkuRpc;
|
||||
|
||||
public List<ProductSkuRespDTO> listProductSkus(Collection<Integer> productSkuIds, String... fields) {
|
||||
if (CollectionUtils.isEmpty(productSkuIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult = productSkuRpc.listProductSkus(
|
||||
new ProductSkuListQueryReqDTO().setProductSkuIds(productSkuIds).setFields(Arrays.asList(fields)));
|
||||
listProductSkusResult.checkError();
|
||||
return listProductSkusResult.getData();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.mall.tradeservice.client.promotion;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.CouponCardRpc;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardUseReqDTO;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CouponCardClient {
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.CouponCardRpc.version}")
|
||||
private CouponCardRpc couponCardRpc;
|
||||
|
||||
public void useCouponCard(Integer userId, Integer couponCardId) {
|
||||
CommonResult<Boolean> useCouponCardResult = couponCardRpc.useCouponCard(new CouponCardUseReqDTO()
|
||||
.setUserId(userId).setCouponCardId(couponCardId));
|
||||
useCouponCardResult.checkError();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.mall.tradeservice.client.promotion;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.PriceRpc;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcRespDTO;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class PriceClient {
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.PriceRpc.version}")
|
||||
private PriceRpc priceRpc;
|
||||
|
||||
/**
|
||||
* 计算商品们的价格
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param items 商品 SKU 集合
|
||||
* @param couponCardId 优惠劵编号,允许为空
|
||||
* @return 价格
|
||||
*/
|
||||
public PriceProductCalcRespDTO calcProductPrice(Integer userId, List<PriceProductCalcReqDTO.Item> items,
|
||||
Integer couponCardId) {
|
||||
CommonResult<PriceProductCalcRespDTO> calcProductPriceResult = priceRpc.calcProductPrice(
|
||||
new PriceProductCalcReqDTO().setUserId(userId).setItems(items).setCouponCardId(couponCardId));
|
||||
calcProductPriceResult.checkError();
|
||||
return calcProductPriceResult.getData();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.tradeservice.client.user;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.userservice.rpc.address.UserAddressRpc;
|
||||
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressRespDTO;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class UserAddressClient {
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.UserAddressRpc.version}")
|
||||
private UserAddressRpc userAddressRpc;
|
||||
|
||||
public UserAddressRespDTO getUserAddress(Integer userAddressId, Integer userId) {
|
||||
CommonResult<UserAddressRespDTO> getUserAddressResult = userAddressRpc.getUserAddress(userAddressId);
|
||||
getUserAddressResult.checkError();
|
||||
if (getUserAddressResult.getData() == null) {
|
||||
return null;
|
||||
}
|
||||
// 如果用户编号不匹配,则返回 null
|
||||
return Objects.equals(getUserAddressResult.getData().getUserId(), userId) ?
|
||||
getUserAddressResult.getData() : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.iocoder.mall.tradeservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* Spring Aop 配置类
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||
public class AopConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.tradeservice.config;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("cn.iocoder.mall.tradeservice.dal.mysql.mapper") // 扫描对应的 Mapper 接口
|
||||
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
// 数据库连接池 Druid
|
||||
|
||||
@Bean
|
||||
public ISqlInjector sqlInjector() {
|
||||
return new DefaultSqlInjector(); // MyBatis Plus 逻辑删除
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
return new PaginationInterceptor(); // MyBatis Plus 分页插件
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.mall.tradeservice.convert.cart;
|
||||
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.cart.CartItemDO;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.CartItemAddReqDTO;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.CartItemListReqDTO;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.CartItemRespDTO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemAddBO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemBO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemListQueryBO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface CartConvert {
|
||||
|
||||
CartConvert INSTANCE = Mappers.getMapper(CartConvert.class);
|
||||
|
||||
CartItemDO convert(CartItemAddBO bean);
|
||||
|
||||
CartItemAddBO convert(CartItemAddReqDTO bean);
|
||||
|
||||
List<CartItemBO> convertList(List<CartItemDO> list);
|
||||
|
||||
CartItemListQueryBO convert(CartItemListReqDTO bean);
|
||||
|
||||
List<CartItemRespDTO> convertList02(List<CartItemBO> list);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.aftersale;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.mall.tradeservice.enums.aftersale.AfterSaleTypeEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.aftersale.AfterSaleWayEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.logistics.LogisticsDeliveryTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 售后订单,用于处理 {@link TradeOrderDO} 交易订单的退货换流程
|
||||
*
|
||||
* TODO 超时机制
|
||||
* TODO 用户(买家)和商家每一个步骤,都需要记录协商记录,多设计一个表
|
||||
*/
|
||||
@TableName(value = "after_sale_order")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class AfterSaleOrderDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
* 售后订单编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 售后状态
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 用户手机
|
||||
*/
|
||||
private String userMobile;
|
||||
/**
|
||||
* 售后类型
|
||||
*
|
||||
* 枚举 {@link AfterSaleTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 售后方式
|
||||
*
|
||||
* 枚举 {@link AfterSaleWayEnum}
|
||||
*/
|
||||
private Integer way;
|
||||
/**
|
||||
* 货物状态,是否收到货
|
||||
*/
|
||||
private Boolean logisticsReceived;
|
||||
/**
|
||||
* 用户售后原因
|
||||
*
|
||||
* TODO 不同情况下的退款,原因不同
|
||||
*/
|
||||
private Integer reasonType;
|
||||
/**
|
||||
* 用户售后说明
|
||||
*/
|
||||
private String reasonMemo;
|
||||
/**
|
||||
* 用户售后凭证图片的地址数组
|
||||
*
|
||||
* 数组,以逗号分隔
|
||||
*/
|
||||
private String reasonPicUrls;
|
||||
/**
|
||||
* 商家拒绝理由
|
||||
*/
|
||||
private String rejectReasonMemo;
|
||||
|
||||
// ========== 交易订单相关 ==========
|
||||
/**
|
||||
* 交易订单编号
|
||||
*
|
||||
* 外键 {@link TradeOrderDO#getId()}
|
||||
*/
|
||||
private Integer tradeOrderId;
|
||||
/**
|
||||
* 交易订单项编号
|
||||
*
|
||||
* 外键 {@link TradeOrderItemDO#getId()}
|
||||
*/
|
||||
private Integer tradeOrderItemId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
// ========== 退款相关 ==========
|
||||
/**
|
||||
* 退款金额,单位:分。
|
||||
*/
|
||||
private Integer refundPrice;
|
||||
|
||||
// ========== 退货相关 ==========
|
||||
/**
|
||||
* 退货地址,即商家的收件地址
|
||||
*/
|
||||
private String returnDetailAddress;
|
||||
/**
|
||||
* 退货物流公司编号
|
||||
*
|
||||
* 使用 DataDict 数据字典 EXPRESS
|
||||
*/
|
||||
private String returnLogisticsExpressId;
|
||||
/**
|
||||
* 退货物流单号
|
||||
*/
|
||||
private String returnLogisticsExpressNo;
|
||||
/**
|
||||
* 退货物流说明
|
||||
*/
|
||||
private String returnLogisticsReasonMemo;
|
||||
/**
|
||||
* 退货物流凭证图片的地址数组
|
||||
*
|
||||
* 数组,以逗号分隔
|
||||
*/
|
||||
private String returnLogisticsPicUrls;
|
||||
/**
|
||||
* 退货物流的填写时间
|
||||
*/
|
||||
private Date returnLogisticsDate;
|
||||
|
||||
// ========== 换货相关 ==========
|
||||
/**
|
||||
* 换货物流的配送方式
|
||||
* 这里指的是商家重新给用户(买家)发货
|
||||
*
|
||||
* 枚举 {@link LogisticsDeliveryTypeEnum}
|
||||
*/
|
||||
private Integer exchangeLogisticsDeliveryType;
|
||||
/**
|
||||
* 换货物流公司编号
|
||||
*/
|
||||
private Integer exchangeLogisticsExpressId;
|
||||
/**
|
||||
* 换货物流公司单号
|
||||
*/
|
||||
private String exchangeLogisticsExpressNo;
|
||||
/**
|
||||
* 换货物流的填写时间
|
||||
*/
|
||||
private Date exchangeLogisticsDate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.cart;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 购物车的商品信息 DO
|
||||
*/
|
||||
@TableName("cart_item")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class CartItemDO extends DeletableDO {
|
||||
|
||||
// ========= 基础字段 BEGIN =========
|
||||
|
||||
/**
|
||||
* 编号,唯一自增。
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
// ========= 基础字段 END =========
|
||||
|
||||
// ========= 买家信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
// ========= 买家信息 END =========
|
||||
|
||||
// ========= 商品信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品购买数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
// TODO 冗余字段
|
||||
|
||||
|
||||
// ========= 商品信息 END =========
|
||||
|
||||
// ========= 优惠信息 BEGIN =========
|
||||
|
||||
// /**
|
||||
// * 商品营销活动编号
|
||||
// */
|
||||
// private Integer activityId;
|
||||
// /**
|
||||
// * 商品营销活动类型
|
||||
// */
|
||||
// private Integer activityType;
|
||||
|
||||
// ========= 优惠信息 END =========
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order;
|
||||
|
||||
/**
|
||||
* 订单优惠明细
|
||||
*
|
||||
* 可参考 https://jos.jd.com/apilist?apiGroupId=55&apiId=16757&apiName=jingdong.pop.order.coupondetail
|
||||
*/
|
||||
// TODO 芋艿 后续在完善
|
||||
public class OrderPreferentialDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* 1 - 促销活动
|
||||
* 2 - 优惠劵
|
||||
*/
|
||||
private Integer type;
|
||||
// TODO 芋艿 优惠劵编号 or 促销活动编号
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
private Integer orderId;
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
/**
|
||||
* 传入时的价格
|
||||
*/
|
||||
private Integer originTotal;
|
||||
/**
|
||||
* 总优惠价格
|
||||
*/
|
||||
private Integer discountTotal;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import cn.iocoder.mall.tradeservice.enums.logistics.LogisticsDeliveryTypeEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderAfterSaleStatusEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 交易订单
|
||||
*
|
||||
* idx_userId 索引:基于 {@link #userId} 字段
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-16 13:49
|
||||
*/
|
||||
@TableName(value = "trade_order")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class TradeOrderDO extends DeletableDO {
|
||||
|
||||
// ========== 订单基本信息 ==========
|
||||
/**
|
||||
* 订单编号(主键)
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 订单编号(业务)
|
||||
*/
|
||||
private String orderNo;
|
||||
/**
|
||||
* 订单状态。
|
||||
* 如果有多个商品分开发货,需要全部商品发完才会改变状态
|
||||
*
|
||||
* 枚举 {@link TradeOrderStatusEnum}
|
||||
*/
|
||||
private Integer orderStatus;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 订单结束时间
|
||||
*
|
||||
* 即交易订单状态变成 {@link TradeOrderStatusEnum#COMPLETED} 和 {@link TradeOrderStatusEnum#CLOSED} 的时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
// ========== 价格 + 支付基本信息 ==========
|
||||
/**
|
||||
* 购买(商品)总金额,单位:分
|
||||
*/
|
||||
private Integer buyPrice;
|
||||
/**
|
||||
* 优惠总金额,单位:分。
|
||||
*/
|
||||
private Integer discountPrice;
|
||||
/**
|
||||
* 物流金额 (分)
|
||||
*/
|
||||
private Integer logisticsPrice;
|
||||
/**
|
||||
* 最终金额,单位:分
|
||||
*
|
||||
* buyPrice + logisticsPrice - discountPrice = presentPrice
|
||||
*/
|
||||
private Integer presentPrice;
|
||||
/**
|
||||
* 实际已支付金额,单位:分
|
||||
*
|
||||
* 初始时,金额为 0 。等到支付成功后,会进行更新。
|
||||
*/
|
||||
private Integer payPrice;
|
||||
/**
|
||||
* 退款金额,单位:分
|
||||
*
|
||||
* 注意,退款并不会影响 {@link #payPrice} 实际支付金额
|
||||
* 也就说,一个订单最终产生多少金额的收入 = payPrice - refundPrice
|
||||
*/
|
||||
private Integer refundPrice;
|
||||
/**
|
||||
* 付款时间
|
||||
*/
|
||||
private Date payTime;
|
||||
/**
|
||||
* 支付订单编号
|
||||
*
|
||||
* 对接 pay-service 支付服务的支付订单编号
|
||||
*/
|
||||
private Integer payTransactionId;
|
||||
/**
|
||||
* 支付成功的支付渠道
|
||||
*/
|
||||
private Integer payChannel;
|
||||
|
||||
// ========== 收件 + 物流基本信息 ==========
|
||||
/**
|
||||
* 配送类型
|
||||
*
|
||||
* 枚举 {@link LogisticsDeliveryTypeEnum}
|
||||
*/
|
||||
private Integer deliveryType;
|
||||
/**
|
||||
* 发货时间
|
||||
*/
|
||||
private Date deliveryTime;
|
||||
/**
|
||||
* 收货时间
|
||||
*/
|
||||
private Date receiveTime;
|
||||
/**
|
||||
* 收件人名称
|
||||
*/
|
||||
private String receiverName;
|
||||
/**
|
||||
* 收件人手机
|
||||
*/
|
||||
private String receiverMobile;
|
||||
/**
|
||||
* 收件人地区编码
|
||||
*/
|
||||
private Integer receiverAreaCode;
|
||||
/**
|
||||
* 收件人详细地址
|
||||
*/
|
||||
private String receiverDetailAddress;
|
||||
|
||||
// ========== 售后基本信息 ==========
|
||||
/**
|
||||
* 售后状态
|
||||
*
|
||||
* 枚举 {@link TradeOrderAfterSaleStatusEnum}
|
||||
*/
|
||||
private Integer afterSaleStatus;
|
||||
|
||||
// ========== 营销基本信息 ==========
|
||||
/**
|
||||
* 优惠劵编号
|
||||
*/
|
||||
private Integer couponCardId;
|
||||
|
||||
// TODO 芋艿,这块还要结合营销和价格计算,在去优化下。
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.aftersale.AfterSaleOrderDO;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderAfterSaleStatusEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 交易订单的商品项,主要是商品信息等等
|
||||
*
|
||||
* idx_orderId 索引:基于 {@link #orderId} 字段
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-16 14:03
|
||||
*/
|
||||
@TableName(value = "trade_order_item")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TradeOrderItemDO extends DeletableDO {
|
||||
|
||||
// ========== 订单项基本信息 ==========
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
private Integer orderId;
|
||||
/**
|
||||
* 订单项状态
|
||||
*
|
||||
* 枚举 {@link TradeOrderStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== 商品基本信息 ==========
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
private String skuName;
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String skuImage;
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
// ========== 价格 + 支付基本信息 ==========
|
||||
/**
|
||||
* 原始单价,单位:分。
|
||||
*/
|
||||
private Integer originPrice;
|
||||
/**
|
||||
* 购买单价,单位:分
|
||||
*/
|
||||
private Integer buyPrice;
|
||||
/**
|
||||
* 最终单价,单位:分。
|
||||
*/
|
||||
private Integer presentPrice;
|
||||
/**
|
||||
* 购买总金额,单位:分
|
||||
*
|
||||
* 用途类似 {@link #presentTotal}
|
||||
*/
|
||||
private Integer buyTotal;
|
||||
/**
|
||||
* 优惠总金额,单位:分。
|
||||
*/
|
||||
private Integer discountTotal;
|
||||
/**
|
||||
* 最终总金额,单位:分。
|
||||
*
|
||||
* 注意,presentPrice * quantity 不一定等于 presentTotal 。
|
||||
* 因为,存在无法整除的情况。
|
||||
* 举个例子,presentPrice = 8.33 ,quantity = 3 的情况,presentTotal 有可能是 24.99 ,也可能是 25 。
|
||||
* 所以,需要存储一个该字段。
|
||||
*/
|
||||
private Integer presentTotal;
|
||||
// 如上字段,举个例子:
|
||||
// 假设购买三个,即 quantity = 3 。
|
||||
// originPrice = 15
|
||||
// 使用限时折扣(单品优惠)8 折,buyPrice = 12
|
||||
// 开始算总的价格
|
||||
// buyTotal = buyPrice * quantity = 12 * 3 = 36
|
||||
// discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11
|
||||
// presentTotal = buyTotal - discountTotal = 24 - 11 = 13
|
||||
// 最终 presentPrice = presentTotal / quantity = 13 / 3 = 4.33
|
||||
/**
|
||||
* 退款总金额,单位:分
|
||||
*/
|
||||
private Integer refundTotal;
|
||||
// TODO 芋艿:退款单和这个的关联。例如说,一个子单可以退款多次;需要额外新增表
|
||||
|
||||
// ========== 物流基本信息 ==========
|
||||
/**
|
||||
* 物流编号
|
||||
*
|
||||
* 外键 {@link TradeOrderLogisticsDO#getId()}
|
||||
*/
|
||||
private Integer logisticsId;
|
||||
|
||||
// ========== 售后基本信息 ==========
|
||||
/**
|
||||
* 售后状态
|
||||
*
|
||||
* 枚举 {@link TradeOrderAfterSaleStatusEnum}
|
||||
*/
|
||||
private Integer afterSaleStatus;
|
||||
/**
|
||||
* 售后订单编号
|
||||
*
|
||||
* 外键 {@link AfterSaleOrderDO#getId()}
|
||||
*/
|
||||
private Integer afterSaleOrderId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import cn.iocoder.mall.tradeservice.enums.logistics.LogisticsDeliveryTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易订单的物流信息
|
||||
*/
|
||||
@TableName(value = "logistics_order")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class TradeOrderLogisticsDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
* 物流订单号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 配送类型
|
||||
*
|
||||
* 枚举 {@link LogisticsDeliveryTypeEnum}
|
||||
*/
|
||||
private Integer deliveryType;
|
||||
/**
|
||||
* 物流公司编号
|
||||
*
|
||||
* 使用 DataDict 数据字典 EXPRESS
|
||||
*/
|
||||
private Integer expressId;
|
||||
/**
|
||||
* 物流公司单号
|
||||
*/
|
||||
private String expressNo;
|
||||
/**
|
||||
* 交易订单号
|
||||
*
|
||||
* 外键 {@link TradeOrderDO#getId()}
|
||||
*/
|
||||
private Integer tradeOrderId;
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private List<Item> items;
|
||||
|
||||
/**
|
||||
* 商品项
|
||||
*/
|
||||
@Data
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.mapper.cart;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.cart.CartItemDO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemListQueryBO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Repository
|
||||
public interface CartItemMapper extends BaseMapper<CartItemDO> {
|
||||
|
||||
default CartItemDO selectByUserIdAndSkuId(Integer userId, Integer skuId) {
|
||||
return selectOne(new QueryWrapper<CartItemDO>().eq("user_id", userId)
|
||||
.eq("sku_id", skuId));
|
||||
}
|
||||
|
||||
default List<CartItemDO> selectListByUserIdAndSkuIds(Integer userId, Collection<Integer> skuIds) {
|
||||
return selectList(new QueryWrapperX<CartItemDO>().eq("user_id", userId)
|
||||
.inIfPresent("sku_id", skuIds));
|
||||
}
|
||||
|
||||
default void updateByIds(@Param("ids") Set<Integer> ids, @Param("updateObject") CartItemDO updateObject) {
|
||||
// TODO 芋艿:batch update ,在 mybatis plus 做拓展,这里先临时处理
|
||||
ids.forEach(id -> updateById(updateObject.setId(id)));
|
||||
}
|
||||
|
||||
default Integer selectSumQuantityByUserId(Integer userId) {
|
||||
// SQL sum 查询
|
||||
List<Map<String, Object>> result = selectMaps(new QueryWrapper<CartItemDO>()
|
||||
.select("SUM(quantity) AS sumQuantity")
|
||||
.eq("user_id", userId));
|
||||
// 获得数量
|
||||
return ((BigDecimal) result.get(0).get("sumQuantity")).intValue();
|
||||
}
|
||||
|
||||
default List<CartItemDO> selectList(CartItemListQueryBO queryBO) {
|
||||
return selectList(new QueryWrapperX<CartItemDO>().eq("user_id", queryBO.getUserId())
|
||||
.eqIfPresent("selected", queryBO.getSelected()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.mapper.order;
|
||||
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderItemDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface TradeOrderItemMapper extends BaseMapper<TradeOrderItemDO> {
|
||||
|
||||
// TODO 芋艿:后续重构到基础库去支持
|
||||
default void insertList(List<TradeOrderItemDO> entities) {
|
||||
entities.forEach(this::insert);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.iocoder.mall.tradeservice.dal.mysql.mapper.order;
|
||||
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface TradeOrderMapper extends BaseMapper<TradeOrderDO> {
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.cart;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.CartManager;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.*;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 购物车 Rpc 实现
|
||||
*/
|
||||
@DubboService
|
||||
public class CartRpcImpl implements CartRpc {
|
||||
|
||||
@Autowired
|
||||
private CartManager cartManager;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> addCartItem(CartItemAddReqDTO addItemReqDTO) {
|
||||
cartManager.addCartItem(addItemReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateCartItemQuantity(CartItemUpdateQuantityReqDTO updateQuantityReqDTO) {
|
||||
cartManager.updateCartItemSelected(updateQuantityReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateCartItemSelected(CartItemUpdateSelectedReqDTO updateSelectedReqDTO) {
|
||||
cartManager.updateCartItemSelected(updateSelectedReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteCartItems(CartItemDeleteListReqDTO deleteListReqDTO) {
|
||||
cartManager.deleteCartItems(deleteListReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> sumCartItemQuantity(Integer userId) {
|
||||
return success(cartManager.sumCartItemQuantity(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<CartItemRespDTO>> listCartItems(CartItemListReqDTO listReqDTO) {
|
||||
return success(cartManager.listCartItems(listReqDTO));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.mall.tradeservice.rpc.order;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderCreateReqDTO;
|
||||
import cn.iocoder.mall.tradeservice.service.order.TradeOrderService;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 交易订单 Rpc 实现
|
||||
*/
|
||||
@DubboService
|
||||
public class TradeOrderRpcImpl implements TradeOrderRpc {
|
||||
|
||||
@Autowired
|
||||
private TradeOrderService tradeOrderService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> createTradeOrder(TradeOrderCreateReqDTO createReqDTO) {
|
||||
return success(tradeOrderService.createTradeOrder(createReqDTO));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package cn.iocoder.mall.tradeservice.service.cart;
|
||||
|
||||
import cn.iocoder.common.framework.enums.CommonStatusEnum;
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.tradeservice.convert.cart.CartConvert;
|
||||
import cn.iocoder.mall.tradeservice.rpc.cart.dto.*;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.CartService;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemBO;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuRpc;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.mall.tradeservice.enums.OrderErrorCodeConstants.CARD_ITEM_SKU_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* 购物车 Manager
|
||||
*/
|
||||
@Service
|
||||
public class CartManager {
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
||||
private ProductSkuRpc productSkuRpc;
|
||||
|
||||
@Autowired
|
||||
private CartService cartService;
|
||||
|
||||
/**
|
||||
* 添加商品到购物车
|
||||
*
|
||||
* @param addReqDTO 添加商品信息
|
||||
*/
|
||||
public void addCartItem(CartItemAddReqDTO addReqDTO) {
|
||||
// 校验商品 SKU 是否合法
|
||||
ProductSkuRespDTO skuDTO = this.checkProductSku(addReqDTO.getSkuId());
|
||||
// 添加购物车项
|
||||
cartService.addCartItem(CartConvert.INSTANCE.convert(addReqDTO).setSpuId(skuDTO.getSpuId()), skuDTO.getQuantity());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购物车商品数量
|
||||
*
|
||||
* @param updateQuantityReqDTO 更新商品数量
|
||||
*/
|
||||
public void updateCartItemSelected(CartItemUpdateQuantityReqDTO updateQuantityReqDTO) {
|
||||
// 校验商品 SKU 是否合法
|
||||
ProductSkuRespDTO skuDTO = this.checkProductSku(updateQuantityReqDTO.getSkuId());
|
||||
// 更新购物车商品数量
|
||||
cartService.updateCartItemQuantity(updateQuantityReqDTO.getUserId(), updateQuantityReqDTO.getSkuId(),
|
||||
updateQuantityReqDTO.getQuantity(), skuDTO.getQuantity());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购物车商品是否选中
|
||||
*
|
||||
* @param updateSelectedReqDTO 更新商品是否选中 DTO
|
||||
*/
|
||||
public void updateCartItemSelected(CartItemUpdateSelectedReqDTO updateSelectedReqDTO) {
|
||||
cartService.updateCartItemSelected(updateSelectedReqDTO.getUserId(),
|
||||
updateSelectedReqDTO.getSkuIds(), updateSelectedReqDTO.getSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除购物车商品列表
|
||||
*
|
||||
* @param deleteListReqDTO 删除商品列表 DTO
|
||||
*/
|
||||
public void deleteCartItems(CartItemDeleteListReqDTO deleteListReqDTO) {
|
||||
cartService.deleteCartItems(deleteListReqDTO.getUserId(),
|
||||
deleteListReqDTO.getSkuIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户在购物车中的商品数量
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 商品数量
|
||||
*/
|
||||
public Integer sumCartItemQuantity(Integer userId) {
|
||||
return cartService.sumCartItemQuantity(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户在购物车种的商品列表
|
||||
*
|
||||
* @param listReqDTO 查询条件 DTO
|
||||
* @return 购物车中商品列表信息
|
||||
*/
|
||||
public List<CartItemRespDTO> listCartItems(CartItemListReqDTO listReqDTO) {
|
||||
List<CartItemBO> cartItemBOs = cartService.listCartItems(CartConvert.INSTANCE.convert(listReqDTO));
|
||||
return CartConvert.INSTANCE.convertList02(cartItemBOs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验商品 SKU 是否合法
|
||||
* 1. 是否存在
|
||||
* 2. 是否下架
|
||||
*
|
||||
* @param skuId 商品 SKU 编号
|
||||
* @return 商品 SKU 信息
|
||||
*/
|
||||
private ProductSkuRespDTO checkProductSku(Integer skuId) {
|
||||
CommonResult<ProductSkuRespDTO> getProductSkuResult = productSkuRpc.getProductSku(skuId);
|
||||
getProductSkuResult.checkError();
|
||||
ProductSkuRespDTO skuDTO = getProductSkuResult.getData();
|
||||
if (skuDTO == null || CommonStatusEnum.DISABLE.getValue().equals(skuDTO.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_SKU_NOT_FOUND);
|
||||
}
|
||||
return skuDTO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package cn.iocoder.mall.tradeservice.service.cart;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.mall.tradeservice.convert.cart.CartConvert;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.cart.CartItemDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.mapper.cart.CartItemMapper;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemAddBO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemBO;
|
||||
import cn.iocoder.mall.tradeservice.service.cart.bo.CartItemListQueryBO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.mall.tradeservice.enums.OrderErrorCodeConstants.CARD_ITEM_NOT_FOUND;
|
||||
import static cn.iocoder.mall.tradeservice.enums.OrderErrorCodeConstants.CARD_ITEM_SKU_QUANTITY_NOT_ENOUGH;
|
||||
|
||||
/**
|
||||
* 购物车 Service
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class CartService {
|
||||
|
||||
@Autowired
|
||||
private CartItemMapper cartItemMapper;
|
||||
|
||||
/**
|
||||
* 添加商品到购物车
|
||||
*
|
||||
* @param addBO 添加商品信息
|
||||
* @param skuQuantity 商品 SKU 的库存,主要用于库存校验
|
||||
*/
|
||||
public void addCartItem(@Valid CartItemAddBO addBO, Integer skuQuantity) {
|
||||
// 查询 CartItemDO
|
||||
CartItemDO itemDO = cartItemMapper.selectByUserIdAndSkuId(addBO.getUserId(), addBO.getSkuId());
|
||||
// 存在,则进行数量更新
|
||||
if (itemDO != null) {
|
||||
if (addBO.getQuantity() + itemDO.getQuantity() > skuQuantity) {
|
||||
// 校验库存
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_SKU_QUANTITY_NOT_ENOUGH);
|
||||
}
|
||||
cartItemMapper.updateById(new CartItemDO().setId(itemDO.getId()).setSelected(true)
|
||||
.setQuantity(addBO.getQuantity() + itemDO.getQuantity()));
|
||||
return;
|
||||
}
|
||||
// 不存在,则进行插入
|
||||
if (addBO.getQuantity() > skuQuantity) {
|
||||
// 校验库存
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_SKU_QUANTITY_NOT_ENOUGH);
|
||||
}
|
||||
cartItemMapper.insert(CartConvert.INSTANCE.convert(addBO).setSelected(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购物车商品数量
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param skuId 商品 SKU 编号
|
||||
* @param quantity 数量
|
||||
* @param skuQuantity 商品 SKU 的库存,主要用于库存校验
|
||||
*/
|
||||
public void updateCartItemQuantity(Integer userId, Integer skuId, Integer quantity, Integer skuQuantity) {
|
||||
if (quantity > skuQuantity) {
|
||||
// 校验库存
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_SKU_QUANTITY_NOT_ENOUGH);
|
||||
}
|
||||
// 查询 CartItemDO
|
||||
CartItemDO itemDO = cartItemMapper.selectByUserIdAndSkuId(userId, skuId);
|
||||
if (itemDO == null) {
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_NOT_FOUND);
|
||||
}
|
||||
// 更新数量
|
||||
cartItemMapper.updateById(new CartItemDO().setId(itemDO.getId()).setQuantity(quantity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购物车商品是否选中
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param skuIds 商品 SKU 编号数组
|
||||
* @param selected 是否选中
|
||||
*/
|
||||
public void updateCartItemSelected(Integer userId, Collection<Integer> skuIds, Boolean selected) {
|
||||
// 查询 CartItemDO 列表
|
||||
List<CartItemDO> itemDOs = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds);
|
||||
if (skuIds.size() != itemDOs.size()) {
|
||||
throw ServiceExceptionUtil.exception(CARD_ITEM_NOT_FOUND);
|
||||
}
|
||||
// 更新选中
|
||||
cartItemMapper.updateByIds(CollectionUtils.convertSet(itemDOs, CartItemDO::getId),
|
||||
new CartItemDO().setSelected(selected));
|
||||
}
|
||||
|
||||
/**
|
||||
* 购物车删除商品
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param skuIds 商品 SKU 编号的数组
|
||||
*/
|
||||
public void deleteCartItems(Integer userId, List<Integer> skuIds) {
|
||||
// 查询 CartItemDO 列表
|
||||
List<CartItemDO> itemDOs = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds);
|
||||
if (CollectionUtils.isEmpty(itemDOs)) {
|
||||
return;
|
||||
}
|
||||
// 批量标记删除
|
||||
cartItemMapper.deleteBatchIds(CollectionUtils.convertSet(itemDOs, CartItemDO::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户在购物车中的商品数量
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 商品数量
|
||||
*/
|
||||
public Integer sumCartItemQuantity(Integer userId) {
|
||||
return cartItemMapper.selectSumQuantityByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户在购物车种的商品列表
|
||||
*
|
||||
* @param queryBO 查询条件 BO
|
||||
* @return 购物车中商品列表信息
|
||||
*/
|
||||
public List<CartItemBO> listCartItems(CartItemListQueryBO queryBO) {
|
||||
List<CartItemDO> cartItemDOs = cartItemMapper.selectList(queryBO);
|
||||
return CartConvert.INSTANCE.convertList(cartItemDOs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.mall.tradeservice.service.cart.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 购物车添加购物项 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemAddBO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
@NotNull(message = "商品 SPU 编号不能为空")
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@NotNull(message = "数量不能为空")
|
||||
@Min(message = "数量必须大于 0", value = 1L)
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.iocoder.mall.tradeservice.service.cart.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 购物车的商品信息 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemBO {
|
||||
|
||||
// ========= 基础字段 BEGIN =========
|
||||
|
||||
/**
|
||||
* 编号,唯一自增。
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
// ========= 基础字段 END =========
|
||||
|
||||
// ========= 买家信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
// ========= 买家信息 END =========
|
||||
|
||||
// ========= 商品信息 BEGIN =========
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Integer skuId;
|
||||
/**
|
||||
* 商品购买数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
|
||||
// ========= 商品信息 END =========
|
||||
|
||||
// ========= 优惠信息 BEGIN =========
|
||||
|
||||
// /**
|
||||
// * 商品营销活动编号
|
||||
// */
|
||||
// private Integer activityId;
|
||||
// /**
|
||||
// * 商品营销活动类型
|
||||
// */
|
||||
// private Integer activityType;
|
||||
|
||||
// ========= 优惠信息 END =========
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.mall.tradeservice.service.cart.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 购物车的商品信息查询 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CartItemListQueryBO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.mall.tradeservice.service.order;
|
||||
|
||||
import cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderCreateReqDTO;
|
||||
|
||||
/**
|
||||
* 交易订单 Service 接口
|
||||
*/
|
||||
public interface TradeOrderService {
|
||||
|
||||
/**
|
||||
* 创建交易订单
|
||||
*
|
||||
* @param createReqDTO 订单信息
|
||||
* @return 订单编号
|
||||
*/
|
||||
Integer createTradeOrder(TradeOrderCreateReqDTO createReqDTO);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package cn.iocoder.mall.tradeservice.service.order.impl;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.util.DateUtil;
|
||||
import cn.iocoder.common.framework.util.MathUtil;
|
||||
import cn.iocoder.mall.productservice.enums.sku.ProductSkuDetailFieldEnum;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcRespDTO;
|
||||
import cn.iocoder.mall.tradeservice.client.product.ProductSkuClient;
|
||||
import cn.iocoder.mall.tradeservice.client.promotion.CouponCardClient;
|
||||
import cn.iocoder.mall.tradeservice.client.promotion.PriceClient;
|
||||
import cn.iocoder.mall.tradeservice.client.user.UserAddressClient;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.mapper.order.TradeOrderItemMapper;
|
||||
import cn.iocoder.mall.tradeservice.dal.mysql.mapper.order.TradeOrderMapper;
|
||||
import cn.iocoder.mall.tradeservice.enums.logistics.LogisticsDeliveryTypeEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderAfterSaleStatusEnum;
|
||||
import cn.iocoder.mall.tradeservice.enums.order.TradeOrderStatusEnum;
|
||||
import cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderCreateReqDTO;
|
||||
import cn.iocoder.mall.tradeservice.service.order.TradeOrderService;
|
||||
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressRespDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.mall.tradeservice.enums.OrderErrorCodeConstants.*;
|
||||
import static cn.iocoder.mall.userservice.enums.UserErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 交易订单 Service 实现
|
||||
*/
|
||||
@Service
|
||||
public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
|
||||
@Autowired
|
||||
private TradeOrderMapper tradeOrderMapper;
|
||||
@Autowired
|
||||
private TradeOrderItemMapper tradeOrderItemMapper;
|
||||
|
||||
@Autowired // 注入自己,用于调用事务方法
|
||||
private TradeOrderServiceImpl self;
|
||||
|
||||
@Autowired
|
||||
private UserAddressClient userAddressClient;
|
||||
@Autowired
|
||||
private ProductSkuClient productSkuClient;
|
||||
@Autowired
|
||||
private PriceClient priceClient;
|
||||
@Autowired
|
||||
private CouponCardClient couponCardClient;
|
||||
|
||||
@Override
|
||||
// @GlobalTransactional TODO 芋艿,使用 seata 实现分布式事务
|
||||
public Integer createTradeOrder(TradeOrderCreateReqDTO createReqDTO) {
|
||||
// 获得收件地址
|
||||
UserAddressRespDTO userAddressRespDTO = userAddressClient.getUserAddress(createReqDTO.getUserAddressId(),
|
||||
createReqDTO.getUserId());
|
||||
if (userAddressRespDTO == null) {
|
||||
throw ServiceExceptionUtil.exception(USER_ADDRESS_NOT_FOUND);
|
||||
}
|
||||
// 获得商品信息
|
||||
List<ProductSkuRespDTO> listProductSkus = productSkuClient.listProductSkus(
|
||||
CollectionUtils.convertSet(createReqDTO.getOrderItems(), TradeOrderCreateReqDTO.OrderItem::getSkuId),
|
||||
ProductSkuDetailFieldEnum.SPU.getField());
|
||||
if (listProductSkus.size() != createReqDTO.getOrderItems().size()) { // 校验获得的数量,是否匹配
|
||||
throw ServiceExceptionUtil.exception(ORDER_GET_GOODS_INFO_INCORRECT);
|
||||
}
|
||||
// 价格计算
|
||||
PriceProductCalcRespDTO priceProductCalcRespDTO = priceClient.calcProductPrice(createReqDTO.getUserId(),
|
||||
createReqDTO.getOrderItems().stream().map(orderItem -> new PriceProductCalcReqDTO.Item().setSkuId(orderItem.getSkuId())
|
||||
.setQuantity(orderItem.getQuantity()).setSelected(true)).collect(Collectors.toList()),
|
||||
createReqDTO.getCouponCardId());
|
||||
|
||||
// TODO 芋艿,扣除库存
|
||||
|
||||
// 标记优惠劵已使用
|
||||
if (createReqDTO.getCouponCardId() != null) {
|
||||
couponCardClient.useCouponCard(createReqDTO.getUserId(), createReqDTO.getCouponCardId());
|
||||
}
|
||||
|
||||
// 创建交易订单(本地事务)
|
||||
Integer tradeOrderId = self.createTradeOrder0(createReqDTO, listProductSkus, priceProductCalcRespDTO, userAddressRespDTO);
|
||||
|
||||
// 创建支付订单,对接支付服务
|
||||
createPayTransaction();
|
||||
return tradeOrderId;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Integer createTradeOrder0(TradeOrderCreateReqDTO createReqDTO, List<ProductSkuRespDTO> listProductSkus,
|
||||
PriceProductCalcRespDTO priceProductCalcRespDTO, UserAddressRespDTO userAddressRespDTO) {
|
||||
// 构建 TradeOrderDO 对象,并进行保存
|
||||
TradeOrderDO tradeOrderDO = new TradeOrderDO();
|
||||
// 1. 基本信息
|
||||
tradeOrderDO.setUserId(createReqDTO.getUserId()).setOrderNo(generateTradeOrderNo())
|
||||
.setOrderStatus(TradeOrderStatusEnum.WAITING_PAYMENT.getValue()).setRemark(createReqDTO.getRemark());
|
||||
// 2. 价格 + 支付基本信息
|
||||
tradeOrderDO.setBuyPrice(priceProductCalcRespDTO.getFee().getBuyTotal())
|
||||
.setDiscountPrice(priceProductCalcRespDTO.getFee().getDiscountTotal())
|
||||
.setLogisticsPrice(priceProductCalcRespDTO.getFee().getPostageTotal())
|
||||
.setPresentPrice(priceProductCalcRespDTO.getFee().getPresentTotal())
|
||||
.setPayPrice(0).setRefundPrice(0);
|
||||
// 3. 收件 + 物流基本信息
|
||||
tradeOrderDO.setDeliveryType(LogisticsDeliveryTypeEnum.EXPRESS.getDeliveryType())
|
||||
.setReceiverName(userAddressRespDTO.getName()).setReceiverMobile(userAddressRespDTO.getMobile())
|
||||
.setReceiverAreaCode(userAddressRespDTO.getAreaCode()).setReceiverDetailAddress(userAddressRespDTO.getDetailAddress());
|
||||
// 4. 售后基本信息
|
||||
tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NULL.getStatus());
|
||||
// 5. 营销基本信息
|
||||
tradeOrderDO.setCouponCardId(createReqDTO.getCouponCardId());
|
||||
// 最终保存
|
||||
tradeOrderMapper.insert(tradeOrderDO);
|
||||
|
||||
// 创建 TradeOrderItemDO 数组,并进行保存
|
||||
List<TradeOrderItemDO> tradeOrderItemDOs = new ArrayList<>(listProductSkus.size());
|
||||
Map<Integer, ProductSkuRespDTO> listProductSkuMap = CollectionUtils.convertMap(listProductSkus, ProductSkuRespDTO::getId);
|
||||
Map<Integer, PriceProductCalcRespDTO.Item> priceItemMap = new HashMap<>(); // 商品 SKU 价格的映射
|
||||
priceProductCalcRespDTO.getItemGroups().forEach(itemGroup ->
|
||||
itemGroup.getItems().forEach(item -> priceItemMap.put(item.getSkuId(), item)));
|
||||
for (TradeOrderCreateReqDTO.OrderItem orderItem : createReqDTO.getOrderItems()) {
|
||||
TradeOrderItemDO tradeOrderItemDO = new TradeOrderItemDO();
|
||||
tradeOrderItemDOs.add(tradeOrderItemDO);
|
||||
// 1. 基本信息
|
||||
tradeOrderItemDO.setOrderId(tradeOrderDO.getId()).setStatus(tradeOrderDO.getOrderStatus());
|
||||
// 2. 商品基本信息
|
||||
ProductSkuRespDTO productSkuRespDTO = listProductSkuMap.get(orderItem.getSkuId());
|
||||
tradeOrderItemDO.setSpuId(productSkuRespDTO.getSpuId()).setSkuId(productSkuRespDTO.getId())
|
||||
.setSkuName(productSkuRespDTO.getSpu().getName())
|
||||
.setSkuImage(CollectionUtils.getFirst(productSkuRespDTO.getSpu().getPicUrls()))
|
||||
.setQuantity(orderItem.getQuantity());
|
||||
// 3. 价格 + 支付基本信息
|
||||
PriceProductCalcRespDTO.Item priceItem = priceItemMap.get(orderItem.getSkuId());
|
||||
tradeOrderItemDO.setOriginPrice(priceItem.getOriginPrice()).setBuyPrice(priceItem.getBuyPrice())
|
||||
.setPresentPrice(priceItem.getPresentPrice()).setBuyTotal(priceItem.getBuyTotal())
|
||||
.setDiscountTotal(priceItem.getDiscountTotal()).setPresentTotal(priceItem.getPresentTotal())
|
||||
.setRefundTotal(0);
|
||||
// 4. 物流基本信息
|
||||
// 5. 售后基本信息
|
||||
tradeOrderItemDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NULL.getStatus());
|
||||
}
|
||||
// 最终保存
|
||||
tradeOrderItemMapper.insertList(tradeOrderItemDOs);
|
||||
|
||||
return tradeOrderDO.getId();
|
||||
}
|
||||
|
||||
private void createPayTransaction() {
|
||||
|
||||
}
|
||||
|
||||
private String generateTradeOrderNo() {
|
||||
// wx
|
||||
// 2014
|
||||
// 10
|
||||
// 27
|
||||
// 20
|
||||
// 09
|
||||
// 39
|
||||
// 5522657
|
||||
// a690389285100
|
||||
// 目前的算法
|
||||
// 时间序列,年月日时分秒 14 位
|
||||
// 纯随机,6 位 TODO 此处估计是会有问题的,后续在调整
|
||||
return DateUtil.format(new Date(), "yyyyMMddHHmmss") + // 时间序列
|
||||
MathUtil.random(100000, 999999) // 随机。为什么是这个范围,因为偷懒
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
spring:
|
||||
# 数据源配置项
|
||||
datasource:
|
||||
url: jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: 3WLiVUBEwTbvAfsh
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: 400-infra.server.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://400-infra.server.iocoder.cn:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
@@ -0,0 +1,27 @@
|
||||
spring:
|
||||
# 数据源配置项
|
||||
datasource:
|
||||
url: jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: 3WLiVUBEwTbvAfsh
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: 400-infra.server.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
# # Spring 主应用配置
|
||||
# main:
|
||||
# lazy-initialization: true # 开启延迟加载,保证本地开发的性能
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://400-infra.server.iocoder.cn:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
tag: ${DUBBO_TAG} # Dubbo 路由分组
|
||||
@@ -0,0 +1,68 @@
|
||||
spring:
|
||||
# Application 的配置项
|
||||
application:
|
||||
name: trade-service
|
||||
# Profile 的配置项
|
||||
profiles:
|
||||
active: local
|
||||
|
||||
# MyBatis Plus 配置项
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
||||
mapper-locations: classpath*:mapper/*.xml
|
||||
type-aliases-package: cn.iocoder.mall.tradeservice.dal.mysql.dataobject
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Spring Cloud Alibaba Dubbo 专属配置
|
||||
cloud:
|
||||
subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用
|
||||
# Dubbo 提供者的协议
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
# Dubbo 提供服务的扫描基础包
|
||||
scan:
|
||||
base-packages: cn.iocoder.mall.tradeservice.rpc
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
filter: -exception
|
||||
validation: true # 开启 Provider 参数校验
|
||||
version: 1.0.0 # 服务的版本号
|
||||
# Dubbo 服务消费者的配置
|
||||
consumer:
|
||||
ErrorCodeRpc:
|
||||
version: 1.0.0
|
||||
ProductSkuRpc:
|
||||
version: 1.0.0
|
||||
UserAddressRpc:
|
||||
version: 1.0.0
|
||||
PriceRpc:
|
||||
version: 1.0.0
|
||||
CouponCardRpc:
|
||||
version: 1.0.0
|
||||
|
||||
# RocketMQ 配置项
|
||||
rocketmq:
|
||||
name-server: 400-infra.server.iocoder.cn:9876
|
||||
producer:
|
||||
group: ${spring.application.name}-producer-group
|
||||
|
||||
# Actuator 监控配置项
|
||||
management:
|
||||
server.port: 38084 # 独立端口,避免被暴露出去
|
||||
endpoints.web.exposure.include: '*' # 暴露所有监控端点
|
||||
server.port: ${management.server.port} # 设置使用 Actuator 的服务器端口,因为 RPC 服务不需要 Web 端口
|
||||
|
||||
# Mall 配置项
|
||||
mall:
|
||||
# 错误码配置项对应 ErrorCodeProperties 配置类
|
||||
error-code:
|
||||
group: ${spring.application.name}
|
||||
constants-class: cn.iocoder.mall.tradeservice.enums.OrderErrorCodeConstants
|
||||
29
trade-service-project/trade-service-integration-test/pom.xml
Normal file
29
trade-service-project/trade-service-integration-test/pom.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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>
|
||||
<artifactId>trade-service-project</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>trade-service-integration-test</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>trade-service-app</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.mall.tradeservice.service.order.impl;
|
||||
|
||||
import cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderCreateReqDTO;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class TradeOrderServiceImplTest {
|
||||
|
||||
@Autowired
|
||||
private TradeOrderServiceImpl tradeOrderService;
|
||||
|
||||
@Test
|
||||
public void testCreateTradeOrder() {
|
||||
TradeOrderCreateReqDTO createReqDTO = new TradeOrderCreateReqDTO()
|
||||
.setUserId(243)
|
||||
.setIp("127.0.0.1")
|
||||
.setUserAddressId(19)
|
||||
.setCouponCardId(null)
|
||||
.setRemark("我是备注")
|
||||
.setOrderItems(Arrays.asList(
|
||||
new TradeOrderCreateReqDTO.OrderItem().setSkuId(3).setQuantity(1),
|
||||
new TradeOrderCreateReqDTO.OrderItem().setSkuId(4).setQuantity(2)
|
||||
));
|
||||
tradeOrderService.createTradeOrder(createReqDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package cn.iocoder.mall.tradeservice.service.order;
|
||||
Reference in New Issue
Block a user