Commit 92f6c8f4d673b8dcf3b8fd9b7330ce14d711ecb0

Authored by jason
2 parents 910ffa7a 24111c15

Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java
@@ -35,6 +35,17 @@ public class TradeConfigDO extends BaseDO { @@ -35,6 +35,17 @@ public class TradeConfigDO extends BaseDO {
35 @TableId 35 @TableId
36 private Long id; 36 private Long id;
37 37
  38 + // ========== 配送相关 ==========
  39 + // TODO 芋艿:未配置
  40 + /**
  41 + * 是否启用全场包邮
  42 + */
  43 + private Boolean deliveryExpressFreeEnabled;
  44 + /**
  45 + * 全场包邮的最小金额,单位:分
  46 + */
  47 + private Integer deliveryExpressFreePrice;
  48 +
38 // ========== 分销相关 ========== 49 // ========== 分销相关 ==========
39 50
40 /** 51 /**
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
@@ -5,9 +5,11 @@ import cn.hutool.core.lang.Assert; @@ -5,9 +5,11 @@ import cn.hutool.core.lang.Assert;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.module.member.api.address.AddressApi; 6 import cn.iocoder.yudao.module.member.api.address.AddressApi;
7 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 7 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 10 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
10 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
  12 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
11 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; 13 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
12 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; 14 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
13 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; 15 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
@@ -44,6 +46,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -44,6 +46,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
44 private DeliveryPickUpStoreService deliveryPickUpStoreService; 46 private DeliveryPickUpStoreService deliveryPickUpStoreService;
45 @Resource 47 @Resource
46 private DeliveryExpressTemplateService deliveryExpressTemplateService; 48 private DeliveryExpressTemplateService deliveryExpressTemplateService;
  49 + @Resource
  50 + private TradeConfigService tradeConfigService;
47 51
48 @Override 52 @Override
49 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { 53 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
@@ -70,19 +74,25 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -70,19 +74,25 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
70 // ========= 快递发货 ========== 74 // ========= 快递发货 ==========
71 75
72 private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { 76 private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
73 - // 1. 得到收件地址区域 77 + // 0. 得到收件地址区域
74 if (param.getAddressId() == null) { 78 if (param.getAddressId() == null) {
75 throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY); 79 throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
76 } 80 }
77 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); 81 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
78 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); 82 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
79 83
80 - // 2. 过滤出已选中的商品SKU 84 + // 情况一:全局包邮
  85 + if (isGlobalExpressFree(param, result)) {
  86 + return;
  87 + }
  88 +
  89 + // 情况二:
  90 + // 2.1 过滤出已选中的商品SKU
81 List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); 91 List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
82 Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId); 92 Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId);
83 Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap = 93 Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap =
84 deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId()); 94 deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId());
85 - // 3. 计算配送费用 95 + // 2.2 计算配送费用
86 if (CollUtil.isEmpty(expressTemplateMap)) { 96 if (CollUtil.isEmpty(expressTemplateMap)) {
87 log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId()); 97 log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId());
88 throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND); 98 throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND);
@@ -90,6 +100,20 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -90,6 +100,20 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
90 calculateDeliveryPrice(selectedItem, expressTemplateMap, result); 100 calculateDeliveryPrice(selectedItem, expressTemplateMap, result);
91 } 101 }
92 102
  103 + /**
  104 + * 是否全局包邮
  105 + *
  106 + * @param param 计算信息
  107 + * @param result 计算结果
  108 + * @return 是否包邮
  109 + */
  110 + private boolean isGlobalExpressFree(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  111 + TradeConfigDO config = tradeConfigService.getTradeConfig();
  112 + return config != null
  113 + && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮
  114 + && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格
  115 + }
  116 +
93 private void calculateDeliveryPrice(List<OrderItem> selectedSkus, 117 private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
94 Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap, 118 Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap,
95 TradePriceCalculateRespBO result) { 119 TradePriceCalculateRespBO result) {
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java
@@ -4,8 +4,10 @@ import cn.hutool.core.map.MapUtil; @@ -4,8 +4,10 @@ import cn.hutool.core.map.MapUtil;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
5 import cn.iocoder.yudao.module.member.api.address.AddressApi; 5 import cn.iocoder.yudao.module.member.api.address.AddressApi;
6 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 6 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
7 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
  10 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
9 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; 11 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
10 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; 12 import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 13 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
@@ -34,10 +36,14 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -34,10 +36,14 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
34 36
35 @InjectMocks 37 @InjectMocks
36 private TradeDeliveryPriceCalculator calculator; 38 private TradeDeliveryPriceCalculator calculator;
  39 +
37 @Mock 40 @Mock
38 private AddressApi addressApi; 41 private AddressApi addressApi;
  42 +
39 @Mock 43 @Mock
40 private DeliveryExpressTemplateService deliveryExpressTemplateService; 44 private DeliveryExpressTemplateService deliveryExpressTemplateService;
  45 + @Mock
  46 + private TradeConfigService tradeConfigService;
41 47
42 private TradePriceCalculateReqBO reqBO; 48 private TradePriceCalculateReqBO reqBO;
43 private TradePriceCalculateRespBO resultBO; 49 private TradePriceCalculateRespBO resultBO;
@@ -90,8 +96,36 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -90,8 +96,36 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
90 } 96 }
91 97
92 @Test 98 @Test
  99 + @DisplayName("全场包邮")
  100 + public void testCalculate_expressGlobalFree() {
  101 + // mock 方法(全场包邮)
  102 + when(tradeConfigService.getTradeConfig()).thenReturn(new TradeConfigDO().setDeliveryExpressFreeEnabled(true)
  103 + .setDeliveryExpressFreePrice(2200));
  104 +
  105 + // 调用
  106 + calculator.calculate(reqBO, resultBO);
  107 + TradePriceCalculateRespBO.Price price = resultBO.getPrice();
  108 + assertThat(price)
  109 + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice")
  110 + .containsExactly(2200, 0, 0, 0, 0, 2200);
  111 + assertThat(resultBO.getItems()).hasSize(3);
  112 + // 断言:SKU1
  113 + assertThat(resultBO.getItems().get(0))
  114 + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice")
  115 + .containsExactly(100, 2, 0, 0, 0, 0, 200);
  116 + // 断言:SKU2
  117 + assertThat(resultBO.getItems().get(1))
  118 + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice")
  119 + .containsExactly(200, 10, 0, 0, 0, 0, 2000);
  120 + // 断言:SKU3 未选中
  121 + assertThat(resultBO.getItems().get(2))
  122 + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice")
  123 + .containsExactly(300, 1, 0, 0, 0, 0, 300);
  124 + }
  125 +
  126 + @Test
93 @DisplayName("按件计算运费不包邮的情况") 127 @DisplayName("按件计算运费不包邮的情况")
94 - public void testCalculateByExpressTemplateCharge() { 128 + public void testCalculate_expressTemplateCharge() {
95 // SKU 1 : 100 * 2 = 200 129 // SKU 1 : 100 * 2 = 200
96 // SKU 2 :200 * 10 = 2000 130 // SKU 2 :200 * 10 = 2000
97 // 运费 首件 1000 + 续件 2000 = 3000 131 // 运费 首件 1000 + 续件 2000 = 3000
@@ -123,7 +157,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -123,7 +157,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
123 157
124 @Test 158 @Test
125 @DisplayName("按件计算运费包邮的情况") 159 @DisplayName("按件计算运费包邮的情况")
126 - public void testCalculateByExpressTemplateFree() { 160 + public void testCalculate_expressTemplateFree() {
127 // SKU 1 : 100 * 2 = 200 161 // SKU 1 : 100 * 2 = 200
128 // SKU 2 :200 * 10 = 2000 162 // SKU 2 :200 * 10 = 2000
129 // 运费 0 163 // 运费 0