Commit 2a9a869e01083b87efcdea0135823f02db4f38e9

Authored by YunaiV
1 parent 5de8fa2e

mall + trade:获得订单结算信息,接入支付接口

Showing 21 changed files with 292 additions and 180 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
1 package cn.iocoder.yudao.module.product.api.sku.dto; 1 package cn.iocoder.yudao.module.product.api.sku.dto;
2 2
  3 +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
3 import lombok.Data; 4 import lombok.Data;
4 5
5 import java.util.List; 6 import java.util.List;
@@ -25,7 +26,7 @@ public class ProductSkuRespDTO { @@ -25,7 +26,7 @@ public class ProductSkuRespDTO {
25 /** 26 /**
26 * 属性数组 27 * 属性数组
27 */ 28 */
28 - private List<Property> properties; 29 + private List<ProductPropertyValueDetailRespDTO> properties;
29 /** 30 /**
30 * 销售价格,单位:分 31 * 销售价格,单位:分
31 */ 32 */
@@ -63,30 +64,4 @@ public class ProductSkuRespDTO { @@ -63,30 +64,4 @@ public class ProductSkuRespDTO {
63 */ 64 */
64 private Double volume; 65 private Double volume;
65 66
66 - /**  
67 - * 商品属性  
68 - */  
69 - @Data  
70 - public static class Property {  
71 -  
72 - /**  
73 - * 属性编号  
74 - */  
75 - private Long propertyId;  
76 - /**  
77 - * 属性名字  
78 - */  
79 - private String propertyName;  
80 -  
81 - /**  
82 - * 属性值编号  
83 - */  
84 - private Long valueId;  
85 - /**  
86 - * 属性值名字  
87 - */  
88 - private String valueName;  
89 -  
90 - }  
91 -  
92 } 67 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
@@ -18,6 +18,9 @@ public class AppProductSpuDetailRespVO { @@ -18,6 +18,9 @@ public class AppProductSpuDetailRespVO {
18 @Schema(description = "商品名称", required = true, example = "芋道") 18 @Schema(description = "商品名称", required = true, example = "芋道")
19 private String name; 19 private String name;
20 20
  21 + @Schema(description = "商品简介", required = true, example = "我是一个快乐简介")
  22 + private String introduction;
  23 +
21 @Schema(description = "商品详情", required = true, example = "我是商品描述") 24 @Schema(description = "商品详情", required = true, example = "我是商品描述")
22 private String description; 25 private String description;
23 26
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java
@@ -93,7 +93,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -93,7 +93,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
93 assertNull(promotion.getId()); 93 assertNull(promotion.getId());
94 assertEquals(promotion.getName(), "会员折扣"); 94 assertEquals(promotion.getName(), "会员折扣");
95 assertEquals(promotion.getType(), PromotionTypeEnum.MEMBER.getType()); 95 assertEquals(promotion.getType(), PromotionTypeEnum.MEMBER.getType());
96 - assertEquals(promotion.getLevel(), PromotionLevelEnum.SKU.getLevel());  
97 assertEquals(promotion.getTotalPrice(), 200); 96 assertEquals(promotion.getTotalPrice(), 200);
98 assertEquals(promotion.getDiscountPrice(), 20); 97 assertEquals(promotion.getDiscountPrice(), 20);
99 assertTrue(promotion.getMatch()); 98 assertTrue(promotion.getMatch());
@@ -264,7 +263,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -264,7 +263,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
264 assertEquals(promotion01.getId(), 1000L); 263 assertEquals(promotion01.getId(), 1000L);
265 assertEquals(promotion01.getName(), "活动 1000 号"); 264 assertEquals(promotion01.getName(), "活动 1000 号");
266 assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); 265 assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
267 - assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel());  
268 assertEquals(promotion01.getTotalPrice(), 350); 266 assertEquals(promotion01.getTotalPrice(), 350);
269 assertEquals(promotion01.getDiscountPrice(), 70); 267 assertEquals(promotion01.getDiscountPrice(), 70);
270 assertTrue(promotion01.getMatch()); 268 assertTrue(promotion01.getMatch());
@@ -283,7 +281,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -283,7 +281,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
283 assertEquals(promotion02.getId(), 2000L); 281 assertEquals(promotion02.getId(), 2000L);
284 assertEquals(promotion02.getName(), "活动 2000 号"); 282 assertEquals(promotion02.getName(), "活动 2000 号");
285 assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); 283 assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
286 - assertEquals(promotion02.getLevel(), PromotionLevelEnum.ORDER.getLevel());  
287 assertEquals(promotion02.getTotalPrice(), 120); 284 assertEquals(promotion02.getTotalPrice(), 120);
288 assertEquals(promotion02.getDiscountPrice(), 60); 285 assertEquals(promotion02.getDiscountPrice(), 60);
289 assertTrue(promotion02.getMatch()); 286 assertTrue(promotion02.getMatch());
@@ -352,7 +349,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -352,7 +349,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
352 assertEquals(promotion01.getId(), 1000L); 349 assertEquals(promotion01.getId(), 1000L);
353 assertEquals(promotion01.getName(), "活动 1000 号"); 350 assertEquals(promotion01.getName(), "活动 1000 号");
354 assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); 351 assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
355 - assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel());  
356 assertEquals(promotion01.getTotalPrice(), 350); 352 assertEquals(promotion01.getTotalPrice(), 350);
357 assertEquals(promotion01.getDiscountPrice(), 0); 353 assertEquals(promotion01.getDiscountPrice(), 0);
358 assertFalse(promotion01.getMatch()); 354 assertFalse(promotion01.getMatch());
@@ -434,7 +430,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -434,7 +430,6 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
434 assertEquals(promotion01.getId(), 1024L); 430 assertEquals(promotion01.getId(), 1024L);
435 assertEquals(promotion01.getName(), "程序员节"); 431 assertEquals(promotion01.getName(), "程序员节");
436 assertEquals(promotion01.getType(), PromotionTypeEnum.COUPON.getType()); 432 assertEquals(promotion01.getType(), PromotionTypeEnum.COUPON.getType());
437 - assertEquals(promotion01.getLevel(), PromotionLevelEnum.COUPON.getLevel());  
438 assertEquals(promotion01.getTotalPrice(), 350); 433 assertEquals(promotion01.getTotalPrice(), 350);
439 assertEquals(promotion01.getDiscountPrice(), 70); 434 assertEquals(promotion01.getDiscountPrice(), 70);
440 assertTrue(promotion01.getMatch()); 435 assertTrue(promotion01.getMatch());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http
1 -### /trade-order/settlement 获得订单结算信息  
2 -GET {{appApi}}/trade/order/settlement?cartIds=1 1 +### /trade-order/settlement 获得订单结算信息(基于商品)
  2 +GET {{appApi}}/trade/order/settlement?type=0&items[0].skuId=1&items[0].count=2&items[1].skuId=2&items[1].count=3&couponId=1
  3 +Authorization: Bearer {{appToken}}
  4 +tenant-id: {{appTenentId}}
  5 +
  6 +### /trade-order/settlement 获得订单结算信息(基于购物车)
  7 +GET {{appApi}}/trade/order/settlement?type=0&items[0].cartId=50&couponId=1
3 Authorization: Bearer {{appToken}} 8 Authorization: Bearer {{appToken}}
4 tenant-id: {{appTenentId}} 9 tenant-id: {{appTenentId}}
5 10
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; 6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
7 import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; 7 import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
8 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; 8 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
9 -import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;  
10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; 9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
11 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; 10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
12 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; 11 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
@@ -25,7 +24,6 @@ import org.springframework.web.bind.annotation.*; @@ -25,7 +24,6 @@ import org.springframework.web.bind.annotation.*;
25 import javax.annotation.Resource; 24 import javax.annotation.Resource;
26 import javax.servlet.http.HttpServletRequest; 25 import javax.servlet.http.HttpServletRequest;
27 import javax.validation.Valid; 26 import javax.validation.Valid;
28 -import java.util.ArrayList;  
29 import java.util.HashMap; 27 import java.util.HashMap;
30 import java.util.List; 28 import java.util.List;
31 import java.util.Map; 29 import java.util.Map;
@@ -53,78 +51,8 @@ public class AppTradeOrderController { @@ -53,78 +51,8 @@ public class AppTradeOrderController {
53 @GetMapping("/settlement") 51 @GetMapping("/settlement")
54 @Operation(summary = "获得订单结算信息") 52 @Operation(summary = "获得订单结算信息")
55 @PreAuthenticated 53 @PreAuthenticated
56 - public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(  
57 - @Valid AppTradeOrderSettlementReqVO settlementReqVO) {  
58 - if (true) {  
59 - return success(tradeOrderService.settlementOrder(getLoginUserId(), settlementReqVO));  
60 - }  
61 -// return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId));  
62 - AppTradeOrderSettlementRespVO settlement = new AppTradeOrderSettlementRespVO();  
63 -  
64 - AppTradeOrderSettlementRespVO.Price price = new AppTradeOrderSettlementRespVO.Price();  
65 - price.setTotalPrice(1000);  
66 - price.setDeliveryPrice(200);  
67 - price.setCouponPrice(100);  
68 - price.setPointPrice(50);  
69 - price.setPayPrice(950);  
70 -  
71 - List<AppTradeOrderSettlementRespVO.Item> skus = new ArrayList<>();  
72 -  
73 - AppTradeOrderSettlementRespVO.Item item1 = new AppTradeOrderSettlementRespVO.Item();  
74 - item1.setCartId(1L);  
75 - item1.setSpuId(2048L);  
76 - item1.setSpuName("Apple iPhone 12");  
77 - item1.setSkuId(1024);  
78 - item1.setPrice(500);  
79 - item1.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg");  
80 - item1.setCount(2);  
81 - List<AppProductPropertyValueDetailRespVO> properties1 = new ArrayList<>();  
82 - AppProductPropertyValueDetailRespVO property1 = new AppProductPropertyValueDetailRespVO();  
83 - property1.setPropertyId(1L);  
84 - property1.setPropertyName("尺寸");  
85 - property1.setValueId(2L);  
86 - property1.setValueName("大");  
87 - properties1.add(property1);  
88 - item1.setProperties(properties1);  
89 -  
90 - AppTradeOrderSettlementRespVO.Item item2 = new AppTradeOrderSettlementRespVO.Item();  
91 - item2.setCartId(2L);  
92 - item2.setSpuId(3072L);  
93 - item2.setSpuName("Samsung Galaxy S21");  
94 - item2.setSkuId(2048);  
95 - item2.setPrice(800);  
96 - item2.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg");  
97 - item2.setCount(1);  
98 - List<AppProductPropertyValueDetailRespVO> properties2 = new ArrayList<>();  
99 - AppProductPropertyValueDetailRespVO property2 = new AppProductPropertyValueDetailRespVO();  
100 - property2.setPropertyId(10L);  
101 - property2.setPropertyName("颜色");  
102 - property2.setValueId(20L);  
103 - property2.setValueName("白色");  
104 - properties2.add(property2);  
105 - item2.setProperties(properties2);  
106 -  
107 - skus.add(item1);  
108 - skus.add(item2);  
109 -  
110 - settlement.setItems(skus);  
111 - settlement.setPrice(price);  
112 -  
113 - AppTradeOrderSettlementRespVO.Address address = new AppTradeOrderSettlementRespVO.Address();  
114 - address.setId(1L);  
115 - address.setName("John");  
116 - address.setMobile("18888888888");  
117 - address.setProvinceId(1L);  
118 - address.setProvinceName("Beijing");  
119 - address.setCityId(1L);  
120 - address.setCityName("Beijing");  
121 - address.setDistrictId(1L);  
122 - address.setDistrictName("Chaoyang Distripct");  
123 - address.setDetailAddress("No. 10, Xinzhong Street, Chaoyang District");  
124 - address.setDefaulted(true);  
125 - settlement.setAddress(address);  
126 -  
127 - return success(settlement); 54 + public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(@Valid AppTradeOrderSettlementReqVO settlementReqVO) {
  55 + return success(tradeOrderService.settlementOrder(getLoginUserId(), settlementReqVO));
128 } 56 }
129 57
130 @PostMapping("/create") 58 @PostMapping("/create")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
1 package cn.iocoder.yudao.module.trade.controller.app.order.vo; 1 package cn.iocoder.yudao.module.trade.controller.app.order.vo;
2 2
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  5 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.v3.oas.annotations.media.Schema; 6 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 7 import lombok.Data;
5 8
6 -import javax.validation.constraints.NotEmpty; 9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.AssertTrue;
  11 +import javax.validation.constraints.Min;
  12 +import javax.validation.constraints.NotNull;
7 import java.util.List; 13 import java.util.List;
8 14
9 @Schema(description = "用户 App - 交易订单结算 Request VO") 15 @Schema(description = "用户 App - 交易订单结算 Request VO")
10 @Data 16 @Data
11 public class AppTradeOrderSettlementReqVO { 17 public class AppTradeOrderSettlementReqVO {
12 18
  19 + @NotNull(message = "交易类型不能为空")
  20 + @InEnum(value = TradeOrderTypeEnum.class, message = "交易类型必须是 {value}")
  21 + private Integer type;
  22 +
  23 + @Schema(description = "商品项数组", required = true)
  24 + @NotNull(message = "商品不能为空")
  25 + private List<Item> items;
  26 +
13 @Schema(description = "收件地址编号", example = "1") 27 @Schema(description = "收件地址编号", example = "1")
14 private Long addressId; 28 private Long addressId;
15 29
16 @Schema(description = "优惠劵编号", example = "1024") 30 @Schema(description = "优惠劵编号", example = "1024")
17 private Long couponId; 31 private Long couponId;
18 32
19 - @Schema(description = "购物车项的编号数组", required = true, example = "true")  
20 - @NotEmpty(message = "购物车项不能为空")  
21 - private List<Long> cartIds; 33 + @Data
  34 + @Schema(description = "用户 App - 商品项")
  35 + @Valid
  36 + public static class Item {
  37 +
  38 + @Schema(description = "商品 SKU 编号", example = "2048")
  39 + private Long skuId;
  40 + @Schema(description = "购买数量", example = "1")
  41 + @Min(value = 1, message = "购买数量最小值为 {value}")
  42 + private Integer count;
  43 +
  44 + @Schema(description = "购物车项的编号", example = "1024")
  45 + private Long cartId;
  46 +
  47 + @AssertTrue(message = "商品不正确")
  48 + @JsonIgnore
  49 + public boolean isValid() {
  50 + // 组合一:skuId + count 使用商品 SKU
  51 + if (skuId != null && count != null) {
  52 + return true;
  53 + }
  54 + // 组合二:cartId 使用购物车项
  55 + return cartId != null;
  56 + }
  57 +
  58 + }
22 59
23 } 60 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java
@@ -91,17 +91,17 @@ public class AppTradeOrderSettlementRespVO { @@ -91,17 +91,17 @@ public class AppTradeOrderSettlementRespVO {
91 private String mobile; 91 private String mobile;
92 92
93 @Schema(description = "省份编号", required = true, example = "1") 93 @Schema(description = "省份编号", required = true, example = "1")
94 - private Long provinceId; 94 + private Integer provinceId;
95 @Schema(description = "省份名字", required = true, example = "北京") 95 @Schema(description = "省份名字", required = true, example = "北京")
96 private String provinceName; 96 private String provinceName;
97 97
98 @Schema(description = "城市编号", required = true, example = "1") 98 @Schema(description = "城市编号", required = true, example = "1")
99 - private Long cityId; 99 + private Integer cityId;
100 @Schema(description = "城市名字", required = true, example = "北京") 100 @Schema(description = "城市名字", required = true, example = "北京")
101 private String cityName; 101 private String cityName;
102 102
103 @Schema(description = "地区编号", required = true, example = "1") 103 @Schema(description = "地区编号", required = true, example = "1")
104 - private Long districtId; 104 + private Integer districtId;
105 @Schema(description = "地区名字", required = true, example = "朝阳区") 105 @Schema(description = "地区名字", required = true, example = "朝阳区")
106 private String districtName; 106 private String districtName;
107 107
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.ip.core.Area;
6 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 7 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
7 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 8 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
@@ -18,14 +19,15 @@ import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.Prod @@ -18,14 +19,15 @@ import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.Prod
18 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; 19 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO;
19 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO; 20 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO;
20 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; 21 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
21 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;  
22 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderDetailRespVO;  
23 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageItemRespVO; 22 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
24 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; 23 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
  24 +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
25 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 25 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
26 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 26 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
27 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; 27 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
28 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 28 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  29 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  30 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
29 import org.mapstruct.Mapper; 31 import org.mapstruct.Mapper;
30 import org.mapstruct.Mapping; 32 import org.mapstruct.Mapping;
31 import org.mapstruct.Mappings; 33 import org.mapstruct.Mappings;
@@ -241,4 +243,45 @@ public interface TradeOrderConvert { @@ -241,4 +243,45 @@ public interface TradeOrderConvert {
241 243
242 AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean); 244 AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean);
243 245
  246 + default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
  247 + List<TradeCartDO> cartList) {
  248 + TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();
  249 + reqBO.setUserId(userId).setType(settlementReqVO.getType())
  250 + .setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId())
  251 + .setItems(new ArrayList<>(settlementReqVO.getItems().size()));
  252 + // 商品项的构建
  253 + Map<Long, TradeCartDO> cartMap = convertMap(cartList, TradeCartDO::getId);
  254 + for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {
  255 + // 情况一:skuId + count
  256 + if (item.getSkuId() != null) {
  257 + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(item.getSkuId()).setCount(item.getCount())
  258 + .setSelected(true)); // true 的原因,下单一定选中
  259 + continue;
  260 + }
  261 + // 情况二:cartId
  262 + TradeCartDO cart = cartMap.get(item.getCartId());
  263 + if (cart == null) {
  264 + continue;
  265 + }
  266 + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(cart.getSkuId()).setCount(cart.getCount())
  267 + .setCartId(item.getCartId()).setSelected(true)); // true 的原因,下单一定选中
  268 + }
  269 + return reqBO;
  270 + }
  271 +
  272 + default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, AddressRespDTO address) {
  273 + AppTradeOrderSettlementRespVO respVO = convert0(calculate, address);
  274 + if (address != null) {
  275 + Area area = AreaUtils.getArea(address.getAreaId());
  276 + respVO.getAddress().setDistrictId(area.getId());
  277 + respVO.getAddress().setDistrictName(area.getName());
  278 + respVO.getAddress().setCityId(area.getParent().getId());
  279 + respVO.getAddress().setCityName(area.getParent().getName());
  280 + respVO.getAddress().setProvinceId(area.getParent().getParent().getId());
  281 + respVO.getAddress().setProvinceName(area.getParent().getParent().getName());
  282 + }
  283 + return respVO;
  284 + }
  285 + AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
  286 +
244 } 287 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java
@@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
12 import java.util.Collection; 12 import java.util.Collection;
13 import java.util.List; 13 import java.util.List;
14 import java.util.Map; 14 import java.util.Map;
  15 +import java.util.Set;
15 16
16 @Mapper 17 @Mapper
17 public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { 18 public interface TradeCartMapper extends BaseMapperX<TradeCartDO> {
@@ -70,4 +71,10 @@ public interface TradeCartMapper extends BaseMapperX&lt;TradeCartDO&gt; { @@ -70,4 +71,10 @@ public interface TradeCartMapper extends BaseMapperX&lt;TradeCartDO&gt; {
70 update(updateObject, new LambdaQueryWrapper<TradeCartDO>().in(TradeCartDO::getId, ids)); 71 update(updateObject, new LambdaQueryWrapper<TradeCartDO>().in(TradeCartDO::getId, ids));
71 } 72 }
72 73
  74 + default List<TradeCartDO> selectListByUserId(Long userId, Set<Long> ids) {
  75 + return selectList(new LambdaQueryWrapper<TradeCartDO>()
  76 + .eq(TradeCartDO::getUserId, userId)
  77 + .in(TradeCartDO::getId, ids));
  78 + }
  79 +
73 } 80 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java
@@ -4,10 +4,13 @@ import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO @@ -4,10 +4,13 @@ import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO
4 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; 4 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO;
5 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; 5 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO;
6 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; 6 import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
7 8
8 import javax.validation.Valid; 9 import javax.validation.Valid;
9 import java.util.Collection; 10 import java.util.Collection;
  11 +import java.util.List;
10 import java.util.Map; 12 import java.util.Map;
  13 +import java.util.Set;
11 14
12 /** 15 /**
13 * 购物车 Service 接口 16 * 购物车 Service 接口
@@ -68,6 +71,15 @@ public interface TradeCartService { @@ -68,6 +71,15 @@ public interface TradeCartService {
68 AppTradeCartListRespVO getCartList(Long userId); 71 AppTradeCartListRespVO getCartList(Long userId);
69 72
70 /** 73 /**
  74 + * 查询用户的购物车列表
  75 + *
  76 + * @param userId 用户编号
  77 + * @param ids 购物项的编号
  78 + * @return 购物车列表
  79 + */
  80 + List<TradeCartDO> getCartList(Long userId, Set<Long> ids);
  81 +
  82 + /**
71 * 获得用户的购物车商品 SPU 数量的 Map 83 * 获得用户的购物车商品 SPU 数量的 Map
72 * 84 *
73 * @param userId 用户编号 85 * @param userId 用户编号
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java
@@ -17,10 +17,7 @@ import org.springframework.transaction.annotation.Transactional; @@ -17,10 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
17 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
18 18
19 import javax.annotation.Resource; 19 import javax.annotation.Resource;
20 -import java.util.Collection;  
21 -import java.util.Comparator;  
22 -import java.util.List;  
23 -import java.util.Map; 20 +import java.util.*;
24 21
25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 23 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@@ -166,6 +163,14 @@ public class TradeCartServiceImpl implements TradeCartService { @@ -166,6 +163,14 @@ public class TradeCartServiceImpl implements TradeCartService {
166 return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); 163 return TradeCartConvert.INSTANCE.convertList(carts, spus, skus);
167 } 164 }
168 165
  166 + @Override
  167 + public List<TradeCartDO> getCartList(Long userId, Set<Long> ids) {
  168 + if (CollUtil.isEmpty(ids)) {
  169 + return Collections.emptyList();
  170 + }
  171 + return cartMapper.selectListByUserId(userId, ids);
  172 + }
  173 +
169 private void deleteCartIfSpuDeleted(List<TradeCartDO> carts, List<ProductSpuRespDTO> spus) { 174 private void deleteCartIfSpuDeleted(List<TradeCartDO> carts, List<ProductSpuRespDTO> spus) {
170 // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 175 // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除
171 carts.removeIf(cart -> { 176 carts.removeIf(cart -> {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
@@ -34,6 +34,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageRe @@ -34,6 +34,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageRe
34 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; 34 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
35 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; 35 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
36 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; 36 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  37 +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
37 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 38 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
38 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 39 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
39 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; 40 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
@@ -41,6 +42,10 @@ import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; @@ -41,6 +42,10 @@ import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
41 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; 42 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
42 import cn.iocoder.yudao.module.trade.enums.order.*; 43 import cn.iocoder.yudao.module.trade.enums.order.*;
43 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 44 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  45 +import cn.iocoder.yudao.module.trade.service.cart.TradeCartService;
  46 +import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
  47 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  48 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
44 import lombok.extern.slf4j.Slf4j; 49 import lombok.extern.slf4j.Slf4j;
45 import org.springframework.stereotype.Service; 50 import org.springframework.stereotype.Service;
46 import org.springframework.transaction.annotation.Transactional; 51 import org.springframework.transaction.annotation.Transactional;
@@ -50,8 +55,7 @@ import java.time.LocalDateTime; @@ -50,8 +55,7 @@ import java.time.LocalDateTime;
50 import java.util.*; 55 import java.util.*;
51 56
52 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 57 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
53 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;  
54 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; 58 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
55 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; 59 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
56 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 60 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
57 61
@@ -71,6 +75,11 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -71,6 +75,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
71 private TradeOrderItemMapper tradeOrderItemMapper; 75 private TradeOrderItemMapper tradeOrderItemMapper;
72 76
73 @Resource 77 @Resource
  78 + private TradeCartService tradeCartService;
  79 + @Resource
  80 + private TradePriceService tradePriceService;
  81 +
  82 + @Resource
74 private PriceApi priceApi; 83 private PriceApi priceApi;
75 @Resource 84 @Resource
76 private ProductSkuApi productSkuApi; 85 private ProductSkuApi productSkuApi;
@@ -92,7 +101,48 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -92,7 +101,48 @@ public class TradeOrderServiceImpl implements TradeOrderService {
92 101
93 @Override 102 @Override
94 public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { 103 public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) {
95 - return null; 104 + // 1. 获得收货地址
  105 + AddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId());
  106 + if (address != null) {
  107 + settlementReqVO.setAddressId(address.getId());
  108 + }
  109 +
  110 + // 2. 计算价格
  111 + TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, settlementReqVO);
  112 +
  113 + // 3. 拼接返回
  114 + return TradeOrderConvert.INSTANCE.convert(calculateRespBO, address);
  115 + }
  116 +
  117 + /**
  118 + * 获得用户地址
  119 + *
  120 + * @param userId 用户编号
  121 + * @param addressId 地址编号
  122 + * @return 地址
  123 + */
  124 + private AddressRespDTO getAddress(Long userId, Long addressId) {
  125 + if (addressId != null) {
  126 + return addressApi.getAddress(addressId, userId);
  127 + }
  128 + return addressApi.getDefaultAddress(userId);
  129 + }
  130 +
  131 + /**
  132 + * 计算订单价格
  133 + *
  134 + * @param userId 用户编号
  135 + * @param settlementReqVO 结算信息
  136 + * @return 订单价格
  137 + */
  138 + private TradePriceCalculateRespBO calculatePrice(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) {
  139 + // 1. 如果来自购物车,则获得购物车的商品
  140 + List<TradeCartDO> cartList = tradeCartService.getCartList(userId,
  141 + convertSet(settlementReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId));
  142 +
  143 + // 2. 计算价格
  144 + TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList);
  145 + return tradePriceService.calculatePrice(calculateReqBO);
96 } 146 }
97 147
98 @Override 148 @Override
@@ -120,29 +170,6 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -120,29 +170,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
120 return tradeOrderDO.getId(); 170 return tradeOrderDO.getId();
121 } 171 }
122 172
123 -// /**  
124 -// * 校验商品 SKU 是否可出售  
125 -// *  
126 -// * @param items 商品 SKU  
127 -// * @return 商品 SKU 数组  
128 -// */  
129 -// private List<ProductSkuRespDTO> validateSkuSaleable(List<Item> items) {  
130 -// List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId));  
131 -// // SKU 不存在  
132 -// if (items.size() != skus.size()) {  
133 -// throw exception(ORDER_CREATE_SKU_NOT_FOUND);  
134 -// }  
135 -// // 校验库存不足  
136 -// Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);  
137 -// items.forEach(item -> {  
138 -// ProductSkuRespDTO sku = skuMap.get(item.getSkuId());  
139 -// if (item.getCount() > sku.getStock()) {  
140 -// throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH);  
141 -// }  
142 -// });  
143 -// return skus;  
144 -// }  
145 -  
146 /** 173 /**
147 * 校验商品 SPU 是否可出售 174 * 校验商品 SPU 是否可出售
148 * 175 *
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.trade.service.price; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.trade.service.price;
3 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 3 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
4 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 4 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
5 5
  6 +import javax.validation.Valid;
  7 +
6 /** 8 /**
7 * 价格计算 Service 接口 9 * 价格计算 Service 接口
8 * 10 *
@@ -16,6 +18,6 @@ public interface TradePriceService { @@ -16,6 +18,6 @@ public interface TradePriceService {
16 * @param calculateReqDTO 计算信息 18 * @param calculateReqDTO 计算信息
17 * @return 计算结果 19 * @return 计算结果
18 */ 20 */
19 - TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqDTO); 21 + TradePriceCalculateRespBO calculatePrice(@Valid TradePriceCalculateReqBO calculateReqDTO);
20 22
21 } 23 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
@@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.trade.service.price; @@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.trade.service.price;
2 2
3 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 3 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
4 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 4 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  5 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  6 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  7 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
5 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 8 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
6 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 9 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
7 import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; 10 import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator;
8 import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; 11 import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper;
9 import lombok.extern.slf4j.Slf4j; 12 import lombok.extern.slf4j.Slf4j;
10 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
  14 +import org.springframework.validation.annotation.Validated;
11 15
12 import javax.annotation.Resource; 16 import javax.annotation.Resource;
13 import java.util.List; 17 import java.util.List;
@@ -15,8 +19,8 @@ import java.util.Map; @@ -15,8 +19,8 @@ import java.util.Map;
15 19
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
18 -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;  
19 -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; 22 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  23 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; 24 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL;
21 25
22 /** 26 /**
@@ -25,22 +29,28 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_C @@ -25,22 +29,28 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_C
25 * @author 芋道源码 29 * @author 芋道源码
26 */ 30 */
27 @Service 31 @Service
  32 +@Validated
28 @Slf4j 33 @Slf4j
29 public class TradePriceServiceImpl implements TradePriceService { 34 public class TradePriceServiceImpl implements TradePriceService {
30 35
31 @Resource 36 @Resource
32 private ProductSkuApi productSkuApi; 37 private ProductSkuApi productSkuApi;
33 @Resource 38 @Resource
  39 + private ProductSpuApi productSpuApi;
  40 +
  41 + @Resource
34 private List<TradePriceCalculator> priceCalculators; 42 private List<TradePriceCalculator> priceCalculators;
35 43
36 @Override 44 @Override
37 public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { 45 public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) {
38 - // 1. 获得商品 SKU 数组  
39 - List<ProductSkuRespDTO> skuList = checkSkus(calculateReqBO); 46 + // 1.1 获得商品 SKU 数组
  47 + List<ProductSkuRespDTO> skuList = checkSkuList(calculateReqBO);
  48 + // 1.2 获得商品 SPU 数组
  49 + List<ProductSpuRespDTO> spuList = checkSpuList(skuList);
40 50
41 // 2.1 计算价格 51 // 2.1 计算价格
42 TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper 52 TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper
43 - .buildCalculateResp(calculateReqBO, skuList); 53 + .buildCalculateResp(calculateReqBO, spuList, skuList);
44 priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); 54 priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO));
45 // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 55 // 2.2 如果最终支付金额小于等于 0,则抛出业务异常
46 if (calculateRespBO.getPrice().getPayPrice() <= 0) { 56 if (calculateRespBO.getPrice().getPayPrice() <= 0) {
@@ -51,7 +61,7 @@ public class TradePriceServiceImpl implements TradePriceService { @@ -51,7 +61,7 @@ public class TradePriceServiceImpl implements TradePriceService {
51 return calculateRespBO; 61 return calculateRespBO;
52 } 62 }
53 63
54 - private List<ProductSkuRespDTO> checkSkus(TradePriceCalculateReqBO reqBO) { 64 + private List<ProductSkuRespDTO> checkSkuList(TradePriceCalculateReqBO reqBO) {
55 // 获得商品 SKU 数组 65 // 获得商品 SKU 数组
56 Map<Long, Integer> skuIdCountMap = convertMap(reqBO.getItems(), 66 Map<Long, Integer> skuIdCountMap = convertMap(reqBO.getItems(),
57 TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount); 67 TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount);
@@ -70,4 +80,20 @@ public class TradePriceServiceImpl implements TradePriceService { @@ -70,4 +80,20 @@ public class TradePriceServiceImpl implements TradePriceService {
70 return skus; 80 return skus;
71 } 81 }
72 82
  83 + private List<ProductSpuRespDTO> checkSpuList(List<ProductSkuRespDTO> skuList) {
  84 + // 获得商品 SPU 数组
  85 + List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(convertSet(skuList, ProductSkuRespDTO::getSpuId));
  86 +
  87 + // 校验商品 SPU
  88 + spus.forEach(spu -> {
  89 + if (spu == null) {
  90 + throw exception(SPU_NOT_EXISTS);
  91 + }
  92 + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
  93 + throw exception(SPU_NOT_ENABLE);
  94 + }
  95 + });
  96 + return spus;
  97 + }
  98 +
73 } 99 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
@@ -21,7 +21,7 @@ public class TradePriceCalculateReqBO { @@ -21,7 +21,7 @@ public class TradePriceCalculateReqBO {
21 * 21 *
22 * 枚举 {@link TradeOrderTypeEnum} 22 * 枚举 {@link TradeOrderTypeEnum}
23 */ 23 */
24 - private Integer orderType; 24 + private Integer type;
25 25
26 /** 26 /**
27 * 用户编号 27 * 用户编号
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
1 package cn.iocoder.yudao.module.trade.service.price.bo; 1 package cn.iocoder.yudao.module.trade.service.price.bo;
2 2
  3 +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
3 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; 4 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
4 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 5 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
5 import lombok.Data; 6 import lombok.Data;
@@ -23,7 +24,7 @@ public class TradePriceCalculateRespBO { @@ -23,7 +24,7 @@ public class TradePriceCalculateRespBO {
23 * 24 *
24 * 枚举 {@link TradeOrderTypeEnum} 25 * 枚举 {@link TradeOrderTypeEnum}
25 */ 26 */
26 - private Integer orderType; 27 + private Integer type;
27 28
28 /** 29 /**
29 * 订单价格 30 * 订单价格
@@ -163,7 +164,26 @@ public class TradePriceCalculateRespBO { @@ -163,7 +164,26 @@ public class TradePriceCalculateRespBO {
163 */ 164 */
164 private Integer payPrice; 165 private Integer payPrice;
165 166
166 - // TODO 芋艿:这里补充下基本信息,简单一点。 167 + // ========== 商品信息 ==========
  168 + /**
  169 + * 商品名
  170 + */
  171 + private String spuName;
  172 + /**
  173 + * 商品图片
  174 + *
  175 + * 优先级:SKU.picUrl > SPU.picUrl
  176 + */
  177 + private String picUrl;
  178 + /**
  179 + * 分类编号
  180 + */
  181 + private Long categoryId;
  182 +
  183 + /**
  184 + * 商品属性数组
  185 + */
  186 + private List<ProductPropertyValueDetailRespDTO> properties;
167 187
168 } 188 }
169 189
@@ -190,12 +210,6 @@ public class TradePriceCalculateRespBO { @@ -190,12 +210,6 @@ public class TradePriceCalculateRespBO {
190 */ 210 */
191 private Integer type; 211 private Integer type;
192 /** 212 /**
193 - * 营销级别  
194 - *  
195 - * 枚举 {@link PromotionLevelEnum}  
196 - */  
197 - private Integer level;  
198 - /**  
199 * 计算时的原价(总),单位:分 213 * 计算时的原价(总),单位:分
200 */ 214 */
201 private Integer totalPrice; 215 private Integer totalPrice;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  6 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
6 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 7 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
7 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 8 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
8 9
@@ -14,6 +15,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -14,6 +15,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
14 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; 15 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
15 import static java.util.Collections.singletonList; 16 import static java.util.Collections.singletonList;
16 17
  18 +// TODO 芋艿:改成父类
  19 +
17 /** 20 /**
18 * {@link TradePriceCalculator} 的工具类 21 * {@link TradePriceCalculator} 的工具类
19 * 22 *
@@ -24,25 +27,42 @@ import static java.util.Collections.singletonList; @@ -24,25 +27,42 @@ import static java.util.Collections.singletonList;
24 public class TradePriceCalculatorHelper { 27 public class TradePriceCalculatorHelper {
25 28
26 public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param, 29 public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param,
27 - List<ProductSkuRespDTO> skuList) { 30 + List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
28 // 创建 PriceCalculateRespDTO 对象 31 // 创建 PriceCalculateRespDTO 对象
29 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); 32 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
30 - result.setOrderType(param.getOrderType()); 33 + result.setType(param.getType());
  34 + result.setPromotions(new ArrayList<>());
  35 +
31 // 创建它的 OrderItem 属性 36 // 创建它的 OrderItem 属性
32 - Map<Long, TradePriceCalculateReqBO.Item> skuItemMap = convertMap(param.getItems(),  
33 - TradePriceCalculateReqBO.Item::getSkuId);  
34 - result.setItems(new ArrayList<>(skuItemMap.size()));  
35 - skuList.forEach(sku -> {  
36 - TradePriceCalculateReqBO.Item skuItem = skuItemMap.get(sku.getId());  
37 - TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem()  
38 - // SKU 字段  
39 - .setSpuId(sku.getSpuId()).setSkuId(sku.getId())  
40 - .setCount(skuItem.getCount()).setCartId(skuItem.getCartId()).setSelected(skuItem.getSelected())  
41 - // 价格字段  
42 - .setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * skuItem.getCount())  
43 - .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); 37 + result.setItems(new ArrayList<>(param.getItems().size()));
  38 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  39 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skuList, ProductSkuRespDTO::getId);
  40 + param.getItems().forEach(item -> {
  41 + ProductSkuRespDTO sku = skuMap.get(item.getSkuId());
  42 + if (sku == null) {
  43 + return;
  44 + }
  45 + ProductSpuRespDTO spu = spuMap.get(sku.getSpuId());
  46 + if (spu == null) {
  47 + return;
  48 + }
  49 + // 商品项
  50 + TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem();
44 result.getItems().add(orderItem); 51 result.getItems().add(orderItem);
  52 + orderItem.setSpuId(sku.getSpuId()).setSkuId(sku.getId())
  53 + .setCount(item.getCount()).setCartId(item.getCartId()).setSelected(item.getSelected());
  54 + // sku 价格
  55 + orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount())
  56 + .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0);
  57 + // sku 信息
  58 + orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties());
  59 + // spu 信息
  60 + orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId());
  61 + if (orderItem.getPicUrl() == null) {
  62 + orderItem.setPicUrl(spu.getPicUrl());
  63 + }
45 }); 64 });
  65 +
46 // 创建它的 Price 属性 66 // 创建它的 Price 属性
47 result.setPrice(new TradePriceCalculateRespBO.Price()); 67 result.setPrice(new TradePriceCalculateRespBO.Price());
48 recountAllPrice(result); 68 recountAllPrice(result);
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java
@@ -69,7 +69,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { @@ -69,7 +69,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
69 .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); 69 .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
70 // mock 方法(交易订单项) 70 // mock 方法(交易订单项)
71 TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> { 71 TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> {
72 - o.setOrderId(111L).setUserId(userId).setOrderDividePrice(200); 72 + o.setOrderId(111L).setUserId(userId).setPayPrice(200);
73 o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); 73 o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
74 }); 74 });
75 when(tradeOrderService.getOrderItem(eq(1024L), eq(1L))) 75 when(tradeOrderService.getOrderItem(eq(1024L), eq(1L)))
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApi.java
@@ -18,4 +18,12 @@ public interface AddressApi { @@ -18,4 +18,12 @@ public interface AddressApi {
18 */ 18 */
19 AddressRespDTO getAddress(Long id, Long userId); 19 AddressRespDTO getAddress(Long id, Long userId);
20 20
  21 + /**
  22 + * 获得用户默认收件地址
  23 + *
  24 + * @param userId 用户编号
  25 + * @return 用户收件地址
  26 + */
  27 + AddressRespDTO getDefaultAddress(Long userId);
  28 +
21 } 29 }
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/AddressRespDTO.java
@@ -29,7 +29,7 @@ public class AddressRespDTO { @@ -29,7 +29,7 @@ public class AddressRespDTO {
29 /** 29 /**
30 * 地区编号 30 * 地区编号
31 */ 31 */
32 - private Long areaId; 32 + private Integer areaId;
33 /** 33 /**
34 * 邮编 34 * 邮编
35 */ 35 */
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApiImpl.java
@@ -25,4 +25,9 @@ public class AddressApiImpl implements AddressApi { @@ -25,4 +25,9 @@ public class AddressApiImpl implements AddressApi {
25 return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); 25 return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id));
26 } 26 }
27 27
  28 + @Override
  29 + public AddressRespDTO getDefaultAddress(Long userId) {
  30 + return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId));
  31 + }
  32 +
28 } 33 }