mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-31 17:40:05 +08:00
trade:全局配送价格配置
This commit is contained in:
parent
35569c5ec8
commit
5949727c8d
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user