diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java index a0c6d3858..a6704db4f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java +++ b/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 { @TableId private Long id; + // ========== 配送相关 ========== + // TODO 芋艿:未配置 + /** + * 是否启用全场包邮 + */ + private Boolean deliveryExpressFreeEnabled; + /** + * 全场包邮的最小金额,单位:分 + */ + private Integer deliveryExpressFreePrice; + // ========== 分销相关 ========== /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java index 5d9201efa..7a4669801 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java +++ b/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; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; @@ -44,6 +46,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { private DeliveryPickUpStoreService deliveryPickUpStoreService; @Resource private DeliveryExpressTemplateService deliveryExpressTemplateService; + @Resource + private TradeConfigService tradeConfigService; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { @@ -70,19 +74,25 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { // ========= 快递发货 ========== private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { - // 1. 得到收件地址区域 + // 0. 得到收件地址区域 if (param.getAddressId() == null) { throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY); } AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); - // 2. 过滤出已选中的商品SKU + // 情况一:全局包邮 + if (isGlobalExpressFree(param, result)) { + return; + } + + // 情况二: + // 2.1 过滤出已选中的商品SKU List selectedItem = filterList(result.getItems(), OrderItem::getSelected); Set deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId); Map expressTemplateMap = deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId()); - // 3. 计算配送费用 + // 2.2 计算配送费用 if (CollUtil.isEmpty(expressTemplateMap)) { log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId()); throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND); @@ -90,6 +100,20 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { calculateDeliveryPrice(selectedItem, expressTemplateMap, result); } + /** + * 是否全局包邮 + * + * @param param 计算信息 + * @param result 计算结果 + * @return 是否包邮 + */ + private boolean isGlobalExpressFree(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + TradeConfigDO config = tradeConfigService.getTradeConfig(); + return config != null + && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮 + && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格 + } + private void calculateDeliveryPrice(List selectedSkus, Map expressTemplateMap, TradePriceCalculateRespBO result) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java index 0bb44978c..5aa75fd94 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java +++ b/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; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; @@ -34,10 +36,14 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @InjectMocks private TradeDeliveryPriceCalculator calculator; + @Mock private AddressApi addressApi; + @Mock private DeliveryExpressTemplateService deliveryExpressTemplateService; + @Mock + private TradeConfigService tradeConfigService; private TradePriceCalculateReqBO reqBO; private TradePriceCalculateRespBO resultBO; @@ -89,9 +95,37 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { .setCharge(chargeBO).setFree(freeBO)); } + @Test + @DisplayName("全场包邮") + public void testCalculate_expressGlobalFree() { + // mock 方法(全场包邮) + when(tradeConfigService.getTradeConfig()).thenReturn(new TradeConfigDO().setDeliveryExpressFreeEnabled(true) + .setDeliveryExpressFreePrice(2200)); + + // 调用 + calculator.calculate(reqBO, resultBO); + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); + assertThat(price) + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") + .containsExactly(2200, 0, 0, 0, 0, 2200); + assertThat(resultBO.getItems()).hasSize(3); + // 断言:SKU1 + assertThat(resultBO.getItems().get(0)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(100, 2, 0, 0, 0, 0, 200); + // 断言:SKU2 + assertThat(resultBO.getItems().get(1)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(200, 10, 0, 0, 0, 0, 2000); + // 断言:SKU3 未选中 + assertThat(resultBO.getItems().get(2)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(300, 1, 0, 0, 0, 0, 300); + } + @Test @DisplayName("按件计算运费不包邮的情况") - public void testCalculateByExpressTemplateCharge() { + public void testCalculate_expressTemplateCharge() { // SKU 1 : 100 * 2 = 200 // SKU 2 :200 * 10 = 2000 // 运费 首件 1000 + 续件 2000 = 3000 @@ -123,7 +157,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @Test @DisplayName("按件计算运费包邮的情况") - public void testCalculateByExpressTemplateFree() { + public void testCalculate_expressTemplateFree() { // SKU 1 : 100 * 2 = 200 // SKU 2 :200 * 10 = 2000 // 运费 0