mall + trade:创建订单逻辑,接入新的价格接口

This commit is contained in:
YunaiV 2023-06-03 09:14:51 +08:00
parent 2a9a869e01
commit 636b14ccce
6 changed files with 96 additions and 140 deletions

View File

@ -8,27 +8,22 @@ GET {{appApi}}/trade/order/settlement?type=0&items[0].cartId=50&couponId=1
Authorization: Bearer {{appToken}} Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}} tenant-id: {{appTenentId}}
### /trade-order/confirm-create-order-info-from-cart 基于购物车,确认创建订单 ### /trade-order/create 创建订单(基于商品)
GET {{shop-api-base-url}}/trade-order/confirm-create-order-info-from-cart
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{user-access-token}}
### /trade-order/create 基于商品,创建订单
POST {{appApi}}/trade/order/create POST {{appApi}}/trade/order/create
Content-Type: application/json Content-Type: application/json
Authorization: Bearer {{appToken}} Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}} tenant-id: {{appTenentId}}
{ {
"type": 0,
"addressId": 21, "addressId": 21,
"remark": "我是备注",
"fromCart": false,
"items": [ "items": [
{ {
"skuId": 29, "skuId": 1,
"count": 1 "count": 2
} }
] ],
"remark": "我是备注"
} }
### 获得订单交易的分页 ### 获得订单交易的分页

View File

@ -22,7 +22,6 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -30,6 +29,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 交易订单") @Tag(name = "用户 App - 交易订单")
@ -58,15 +58,9 @@ public class AppTradeOrderController {
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建订单") @Operation(summary = "创建订单")
@PreAuthenticated @PreAuthenticated
public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
HttpServletRequest servletRequest) { Long orderId = tradeOrderService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
return success(1L); return success(orderId);
// // 获取登录用户用户 IP 地址
// Long loginUserId = getLoginUserId();
// String clientIp = ServletUtils.getClientIP(servletRequest);
// // 创建交易订单预支付记录
// Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO);
// return success(orderId);
} }
@PostMapping("/update-paid") @PostMapping("/update-paid")

View File

@ -3,26 +3,9 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "用户 App - 交易订单创建 Request VO") @Schema(description = "用户 App - 交易订单创建 Request VO")
@Data @Data
public class AppTradeOrderCreateReqVO { public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
@Schema(description = "收件地址编号", required = true, example = "1")
@NotNull(message = "收件地址不能为空")
private Long addressId;
@Schema(description = "优惠劵编号", example = "1024")
private Long couponId;
@Schema(description = "购物车项的编号数组", required = true, example = "true")
@NotEmpty(message = "购物车项不能为空")
private List<Long> cartIds;
// ========== AppTradeOrderSettlementReqVO 字段 ==========
@Schema(description = "备注", example = "这个是我的订单哟") @Schema(description = "备注", example = "这个是我的订单哟")
private String remark; private String remark;

View File

@ -9,11 +9,8 @@ import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; 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.trade.controller.admin.base.member.user.MemberUserRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO;
@ -50,32 +47,32 @@ public interface TradeOrderConvert {
@Mapping(source = "createReqVO.couponId", target = "couponId"), @Mapping(source = "createReqVO.couponId", target = "couponId"),
@Mapping(target = "remark", ignore = true), @Mapping(target = "remark", ignore = true),
@Mapping(source = "createReqVO.remark", target = "userRemark"), @Mapping(source = "createReqVO.remark", target = "userRemark"),
@Mapping(source = "createReqVO.type", target = "type"),
@Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"),
@Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"),
@Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
@Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"),
@Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"),
@Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"),
@Mapping(source = "address.name", target = "receiverName"), @Mapping(source = "address.name", target = "receiverName"),
@Mapping(source = "address.mobile", target = "receiverMobile"), @Mapping(source = "address.mobile", target = "receiverMobile"),
@Mapping(source = "address.areaId", target = "receiverAreaId"), @Mapping(source = "address.areaId", target = "receiverAreaId"),
@Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"),
}) })
TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
PriceCalculateRespDTO.Order order, AddressRespDTO address); TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address);
@Mappings({ default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
@Mapping(target = "id", ignore = true), return CollectionUtils.convertList(calculateRespBO.getItems(), item -> {
@Mapping(source = "sku.spuId", target = "spuId"), TradeOrderItemDO orderItem = convert(item);
}) orderItem.setOrderId(tradeOrderDO.getId());
TradeOrderItemDO convert(PriceCalculateRespDTO.OrderItem orderItem, ProductSkuRespDTO sku); orderItem.setUserId(tradeOrderDO.getUserId());
orderItem.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, orderItem.setCommentStatus(false);
List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { return orderItem;
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
return CollectionUtils.convertList(orderItems, orderItem -> {
TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId()));
tradeOrderItemDO.setOrderId(tradeOrderDO.getId());
tradeOrderItemDO.setUserId(tradeOrderDO.getUserId());
tradeOrderItemDO.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); // 退款信息
// tradeOrderItemDO.setCommented(false);
return tradeOrderItemDO;
}); });
} }
TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);
@Mapping(source = "userId" , target = "userId") @Mapping(source = "userId" , target = "userId")
PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId); PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
@ -87,19 +84,20 @@ public interface TradeOrderConvert {
ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);
List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
default PayOrderCreateReqDTO convert(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
List<ProductSpuRespDTO> spus, TradeOrderProperties tradeOrderProperties) { TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) {
PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO()
.setAppId(tradeOrderProperties.getAppId()).setUserIp(tradeOrderDO.getUserIp()); .setAppId(orderProperties.getAppId()).setUserIp(order.getUserIp());
// 商户相关字段 // 商户相关字段
createReqDTO.setMerchantOrderId(String.valueOf(tradeOrderDO.getId())); createReqDTO.setMerchantOrderId(String.valueOf(order.getId()));
String subject = spus.get(0).getName(); String subject = calculateRespBO.getItems().get(0).getSpuName();
if (spus.size() > 1) { if (calculateRespBO.getItems().size() > 1) {
subject += " 等多件"; subject += " 等多件";
} }
createReqDTO.setSubject(subject); createReqDTO.setSubject(subject);
createReqDTO.setBody(subject); // TODO 芋艿临时写死
// 订单相关字段 // 订单相关字段
createReqDTO.setAmount(tradeOrderDO.getPayPrice()).setExpireTime(addTime(tradeOrderProperties.getExpireTime())); createReqDTO.setAmount(order.getPayPrice()).setExpireTime(addTime(orderProperties.getExpireTime()));
return createReqDTO; return createReqDTO;
} }
@ -113,6 +111,7 @@ public interface TradeOrderConvert {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
// TODO 芋艿可简化
default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems,
List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { List<ProductPropertyValueDetailRespDTO> propertyValueDetails) {
Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId);
@ -149,6 +148,7 @@ public interface TradeOrderConvert {
TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items); TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items);
ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean);
// TODO 芋艿可简化
default TradeOrderDetailRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems, default TradeOrderDetailRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
List<ProductPropertyValueDetailRespDTO> propertyValueDetails, MemberUserRespDTO user) { List<ProductPropertyValueDetailRespDTO> propertyValueDetails, MemberUserRespDTO user) {
TradeOrderDetailRespVO orderVO = convert2(order, orderItems); TradeOrderDetailRespVO orderVO = convert2(order, orderItems);
@ -179,6 +179,7 @@ public interface TradeOrderConvert {
TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items); TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items);
MemberUserRespVO convert(MemberUserRespDTO bean); MemberUserRespVO convert(MemberUserRespDTO bean);
// TODO 芋艿可简化
default PageResult<AppTradeOrderPageItemRespVO> convertPage02(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, default PageResult<AppTradeOrderPageItemRespVO> convertPage02(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems,
List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { List<ProductPropertyValueDetailRespDTO> propertyValueDetails) {
Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId);

View File

@ -166,12 +166,25 @@ public class TradeOrderItemDO extends BaseDO {
* 关联 ProductPropertyDO id 编号 * 关联 ProductPropertyDO id 编号
*/ */
private Long propertyId; private Long propertyId;
/**
* 属性名字
*
* 关联 ProductPropertyDO name 字段
*/
private String propertyName;
/** /**
* 属性值编号 * 属性值编号
* *
* 关联 ProductPropertyValueDO id 编号 * 关联 ProductPropertyValueDO id 编号
*/ */
private Long valueId; private Long valueId;
/**
* 属性值名字
*
* 关联 ProductPropertyValueDO name 字段
*/
private String valueName;
} }

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.module.trade.service.order; package cn.iocoder.yudao.module.trade.service.order;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
@ -18,15 +18,9 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@ -40,6 +34,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.enums.order.*;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; import cn.iocoder.yudao.module.trade.service.cart.TradeCartService;
@ -55,7 +50,8 @@ import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -79,13 +75,9 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Resource @Resource
private TradePriceService tradePriceService; private TradePriceService tradePriceService;
@Resource
private PriceApi priceApi;
@Resource @Resource
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@Resource @Resource
private ProductSpuApi productSpuApi;
@Resource
private PayOrderApi payOrderApi; private PayOrderApi payOrderApi;
@Resource @Resource
private AddressApi addressApi; private AddressApi addressApi;
@ -142,53 +134,29 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// 2. 计算价格 // 2. 计算价格
TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList); TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList);
calculateReqBO.getItems().forEach(item -> Assert.isTrue(item.getSelected(), // 防御性编程保证都是选中的
"商品({}) 未设置为选中", item.getSkuId()));
return tradePriceService.calculatePrice(calculateReqBO); return tradePriceService.calculatePrice(calculateReqBO);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 商品 SKU 检查可售状态库存 // 1. 用户收件地址的校验
// List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); // TODO 芋艿临时关闭
List<ProductSkuRespDTO> skus = null;
// 商品 SPU 检查可售状态
List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
// 用户收件地址的校验
AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId());
// 价格计算 // 2. 价格计算
PriceCalculateRespDTO priceResp = priceApi.calculatePrice(TradeOrderConvert.INSTANCE.convert(createReqVO, userId)); TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
// 插入 TradeOrderDO 订单 // 3.1 插入 TradeOrderDO 订单
TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address); TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO, address);
// 插入 TradeOrderItemDO 订单项 // 3.2 插入 TradeOrderItemDO 订单项
List<TradeOrderItemDO> tradeOrderItems = createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO);
// 订单创建完后的逻辑 // 订单创建完后的逻辑
afterCreateTradeOrder(userId, createReqVO, tradeOrderDO, tradeOrderItems, spus); afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
return tradeOrderDO.getId(); return order.getId();
}
/**
* 校验商品 SPU 是否可出售
*
* @param spuIds 商品 SPU 编号数组
* @return 商品 SPU 数组
*/
private List<ProductSpuRespDTO> validateSpuSaleable(Set<Long> spuIds) {
List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(spuIds);
// SPU 不存在
if (spus.size() != spuIds.size()) {
throw exception(ORDER_CREATE_SPU_NOT_FOUND);
}
// 校验是否存在禁用的 SPU
ProductSpuRespDTO spu = CollectionUtils.findFirst(spus,
spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus()));
if (spu != null) {
throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE);
}
return spus;
} }
/** /**
@ -200,33 +168,35 @@ public class TradeOrderServiceImpl implements TradeOrderService {
*/ */
private AddressRespDTO validateAddress(Long userId, Long addressId) { private AddressRespDTO validateAddress(Long userId, Long addressId) {
AddressRespDTO address = addressApi.getAddress(addressId, userId); AddressRespDTO address = addressApi.getAddress(addressId, userId);
if (Objects.isNull(address)) { if (address == null) {
throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND); throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND);
} }
return address; return address;
} }
private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
PriceCalculateRespDTO.Order order, AddressRespDTO address) { TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address) {
TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, order, address); TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的;
tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); order.setType(TradeOrderTypeEnum.NORMAL.getType());
tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息 // 支付信息
tradeOrderDO.setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus()); // 物流信息 order.setAdjustPrice(0).setPayed(false);
tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 // 物流信息 TODO 芋艿暂时写死物流方式应该是前端选择的
tradeOrderMapper.insert(tradeOrderDO); order.setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode()).setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
return tradeOrderDO; // 退款信息
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
tradeOrderMapper.insert(order);
return order;
} }
private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO);
List<TradeOrderItemDO> tradeOrderItemDOs = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, orderItems, skus); tradeOrderItemMapper.insertBatch(orderItems);
tradeOrderItemMapper.insertBatch(tradeOrderItemDOs); return orderItems;
return tradeOrderItemDOs;
} }
/** /**
@ -237,12 +207,13 @@ public class TradeOrderServiceImpl implements TradeOrderService {
* @param userId 用户编号 * @param userId 用户编号
* @param createReqVO 创建订单请求 * @param createReqVO 创建订单请求
* @param tradeOrderDO 交易订单 * @param tradeOrderDO 交易订单
* @param calculateRespBO 订单价格计算结果
*/ */
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
List<ProductSpuRespDTO> spus) { TradePriceCalculateRespBO calculateRespBO) {
// 下单时扣减商品库存 // 下单时扣减商品库存
productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(tradeOrderItemDOs))); productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(orderItems)));
// 删除购物车商品 TODO 芋艿待实现 // 删除购物车商品 TODO 芋艿待实现
@ -255,20 +226,19 @@ public class TradeOrderServiceImpl implements TradeOrderService {
} }
// 生成预支付 // 生成预支付
createPayOrder(tradeOrderDO, tradeOrderItemDOs, spus); createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
// 增加订单日志 TODO 芋艿待实现 // 增加订单日志 TODO 芋艿待实现
} }
private void createPayOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
List<ProductSpuRespDTO> spus) {
// 创建支付单用于后续的支付 // 创建支付单用于后续的支付
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); order, orderItems, calculateRespBO, tradeOrderProperties);
Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO); Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO);
// 更新到交易单上 // 更新到交易单上
tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setPayOrderId(payOrderId));
} }
@Override @Override