mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	trade:全局配送价格配置
This commit is contained in:
		@@ -35,6 +35,17 @@ public class TradeConfigDO extends BaseDO {
 | 
				
			|||||||
    @TableId
 | 
					    @TableId
 | 
				
			||||||
    private Long id;
 | 
					    private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== 配送相关 ==========
 | 
				
			||||||
 | 
					    // TODO 芋艿:未配置
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否启用全场包邮
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Boolean deliveryExpressFreeEnabled;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 全场包邮的最小金额,单位:分
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Integer deliveryExpressFreePrice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ========== 分销相关 ==========
 | 
					    // ========== 分销相关 ==========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,11 @@ import cn.hutool.core.lang.Assert;
 | 
				
			|||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
					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.AddressApi;
 | 
				
			||||||
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 | 
					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.dal.dataobject.delivery.DeliveryPickUpStoreDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
 | 
					import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 | 
					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.DeliveryExpressTemplateService;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
 | 
					import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 | 
					import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 | 
				
			||||||
@@ -44,6 +46,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
 | 
				
			|||||||
    private DeliveryPickUpStoreService deliveryPickUpStoreService;
 | 
					    private DeliveryPickUpStoreService deliveryPickUpStoreService;
 | 
				
			||||||
    @Resource
 | 
					    @Resource
 | 
				
			||||||
    private DeliveryExpressTemplateService deliveryExpressTemplateService;
 | 
					    private DeliveryExpressTemplateService deliveryExpressTemplateService;
 | 
				
			||||||
 | 
					    @Resource
 | 
				
			||||||
 | 
					    private TradeConfigService tradeConfigService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
 | 
					    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
 | 
				
			||||||
@@ -70,19 +74,25 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
 | 
				
			|||||||
    // ========= 快递发货 ==========
 | 
					    // ========= 快递发货 ==========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
 | 
					    private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
 | 
				
			||||||
        // 1. 得到收件地址区域
 | 
					        // 0. 得到收件地址区域
 | 
				
			||||||
        if (param.getAddressId() == null) {
 | 
					        if (param.getAddressId() == null) {
 | 
				
			||||||
            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
 | 
					            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDRESS_IS_EMPTY);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
 | 
					        AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
 | 
				
			||||||
        Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
 | 
					        Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 2. 过滤出已选中的商品SKU
 | 
					        // 情况一:全局包邮
 | 
				
			||||||
 | 
					        if (isGlobalExpressFree(param, result)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 情况二:
 | 
				
			||||||
 | 
					        // 2.1 过滤出已选中的商品SKU
 | 
				
			||||||
        List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
 | 
					        List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
 | 
				
			||||||
        Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId);
 | 
					        Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId);
 | 
				
			||||||
        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap =
 | 
					        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap =
 | 
				
			||||||
                deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId());
 | 
					                deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId());
 | 
				
			||||||
        // 3. 计算配送费用
 | 
					        // 2.2 计算配送费用
 | 
				
			||||||
        if (CollUtil.isEmpty(expressTemplateMap)) {
 | 
					        if (CollUtil.isEmpty(expressTemplateMap)) {
 | 
				
			||||||
            log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId());
 | 
					            log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId());
 | 
				
			||||||
            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND);
 | 
					            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND);
 | 
				
			||||||
@@ -90,6 +100,20 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
 | 
				
			|||||||
        calculateDeliveryPrice(selectedItem, expressTemplateMap, result);
 | 
					        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<OrderItem> selectedSkus,
 | 
					    private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
 | 
				
			||||||
                                        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap,
 | 
					                                        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap,
 | 
				
			||||||
                                        TradePriceCalculateRespBO result) {
 | 
					                                        TradePriceCalculateRespBO result) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,10 @@ import cn.hutool.core.map.MapUtil;
 | 
				
			|||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
					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.AddressApi;
 | 
				
			||||||
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 | 
					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.DeliveryExpressChargeModeEnum;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 | 
					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.DeliveryExpressTemplateService;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 | 
					import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 | 
				
			||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 | 
					import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 | 
				
			||||||
@@ -34,10 +36,14 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @InjectMocks
 | 
					    @InjectMocks
 | 
				
			||||||
    private TradeDeliveryPriceCalculator calculator;
 | 
					    private TradeDeliveryPriceCalculator calculator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Mock
 | 
					    @Mock
 | 
				
			||||||
    private AddressApi addressApi;
 | 
					    private AddressApi addressApi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Mock
 | 
					    @Mock
 | 
				
			||||||
    private DeliveryExpressTemplateService deliveryExpressTemplateService;
 | 
					    private DeliveryExpressTemplateService deliveryExpressTemplateService;
 | 
				
			||||||
 | 
					    @Mock
 | 
				
			||||||
 | 
					    private TradeConfigService tradeConfigService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private TradePriceCalculateReqBO reqBO;
 | 
					    private TradePriceCalculateReqBO reqBO;
 | 
				
			||||||
    private TradePriceCalculateRespBO resultBO;
 | 
					    private TradePriceCalculateRespBO resultBO;
 | 
				
			||||||
@@ -89,9 +95,37 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
 | 
				
			|||||||
                        .setCharge(chargeBO).setFree(freeBO));
 | 
					                        .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
 | 
					    @Test
 | 
				
			||||||
    @DisplayName("按件计算运费不包邮的情况")
 | 
					    @DisplayName("按件计算运费不包邮的情况")
 | 
				
			||||||
    public void testCalculateByExpressTemplateCharge() {
 | 
					    public void testCalculate_expressTemplateCharge() {
 | 
				
			||||||
        // SKU 1 : 100 * 2  = 200
 | 
					        // SKU 1 : 100 * 2  = 200
 | 
				
			||||||
        // SKU 2 :200 * 10 = 2000
 | 
					        // SKU 2 :200 * 10 = 2000
 | 
				
			||||||
        // 运费  首件 1000 +  续件 2000 = 3000
 | 
					        // 运费  首件 1000 +  续件 2000 = 3000
 | 
				
			||||||
@@ -123,7 +157,7 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    @DisplayName("按件计算运费包邮的情况")
 | 
					    @DisplayName("按件计算运费包邮的情况")
 | 
				
			||||||
    public void testCalculateByExpressTemplateFree() {
 | 
					    public void testCalculate_expressTemplateFree() {
 | 
				
			||||||
        // SKU 1 : 100 * 2  = 200
 | 
					        // SKU 1 : 100 * 2  = 200
 | 
				
			||||||
        // SKU 2 :200 * 10 = 2000
 | 
					        // SKU 2 :200 * 10 = 2000
 | 
				
			||||||
        // 运费  0
 | 
					        // 运费  0
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user