price:完成满减送的价格计算~

plp
YunaiV 4 years ago
parent 4e9fe4bc54
commit 160d619d59

@ -103,6 +103,10 @@ public class PriceCalculateRespDTO {
@Data @Data
public static class OrderItem { public static class OrderItem {
/**
* SPU
*/
private Long spuId;
/** /**
* SKU * SKU
*/ */

@ -30,9 +30,10 @@ public interface PriceConvert {
skuList.forEach(sku -> { skuList.forEach(sku -> {
Integer count = skuIdCountMap.get(sku.getId()); Integer count = skuIdCountMap.get(sku.getId());
PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem() PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem()
.setSkuId(sku.getId()).setCount(count).setOriginalUnitPrice(sku.getPrice()) .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count)
.setOriginalPrice(sku.getPrice() * count).setDiscountPrice(0).setOrderPartPrice(0); .setOriginalUnitPrice(sku.getPrice()).setOriginalPrice(sku.getPrice() * count)
orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOrderDividePrice()); .setDiscountPrice(0).setOrderPartPrice(0);
orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
priceCalculate.getOrder().getItems().add(orderItem); priceCalculate.getOrder().getItems().add(orderItem);
// 补充价格信息到 Order 中 // 补充价格信息到 Order 中
order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()).setPayPrice(order.getOriginalPrice()); order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()).setPayPrice(order.getOriginalPrice());

@ -92,7 +92,7 @@ public class RewardActivityDO extends BaseDO {
/** /**
* *
*/ */
private Integer promotionPrice; private Integer discountPrice;
/** /**
* *
*/ */
@ -100,7 +100,7 @@ public class RewardActivityDO extends BaseDO {
/** /**
* *
*/ */
private Integer integral; private Integer point;
/** /**
* *
*/ */

@ -1,14 +1,19 @@
package cn.iocoder.yudao.module.market.service.price; package cn.iocoder.yudao.module.market.service.price;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.market.convert.price.PriceConvert; import cn.iocoder.yudao.module.market.convert.price.PriceConvert;
import cn.iocoder.yudao.module.market.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.market.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.market.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.market.enums.common.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum; import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum;
import cn.iocoder.yudao.module.market.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.market.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.market.service.discount.DiscountService; import cn.iocoder.yudao.module.market.service.discount.DiscountService;
import cn.iocoder.yudao.module.market.service.reward.RewardService;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -16,12 +21,15 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@ -32,6 +40,11 @@ import static java.util.Collections.singletonList;
* *
* 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384"></a> * 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384"></a>
* *
* TODO
* 1.
* 2.
* 3.
*
* @author * @author
*/ */
@Service @Service
@ -40,6 +53,8 @@ public class PriceServiceImpl implements PriceService {
@Resource @Resource
private DiscountService discountService; private DiscountService discountService;
@Resource
private RewardService rewardService;
@Resource @Resource
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@ -53,7 +68,8 @@ public class PriceServiceImpl implements PriceService {
// 计算商品级别的价格 // 计算商品级别的价格
calculatePriceForSkuLevel(calculateReqDTO.getUserId(), priceCalculate); calculatePriceForSkuLevel(calculateReqDTO.getUserId(), priceCalculate);
// 计算【满减送】促销 TODO 待实现 // 计算订单级别的价格
calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate);
// 计算【优惠劵】促销 TODO 待实现 // 计算【优惠劵】促销 TODO 待实现
return priceCalculate; return priceCalculate;
} }
@ -75,10 +91,12 @@ public class PriceServiceImpl implements PriceService {
return skus; return skus;
} }
// ========== 计算商品级别的价格 ==========
/** /**
* *
* 1. * 1.
* 2. * 2. {@link cn.iocoder.yudao.module.market.dal.dataobject.discount.DiscountActivityDO}
* *
* *
* *
@ -138,10 +156,126 @@ public class PriceServiceImpl implements PriceService {
modifyOrderItemPayPrice(orderItem, promotionPrice, priceCalculate); modifyOrderItemPayPrice(orderItem, promotionPrice, priceCalculate);
} }
// TODO 芋艿:提前实现
private Supplier<Double> getMemberDiscountSupplier(Long userId) {
return Suppliers.memoize(() -> {
if (userId == 1) {
return 90d;
}
if (userId == 2) {
return 80d;
}
return null; // 无优惠
});
}
// ========== 计算商品级别的价格 ==========
/**
*
* 1. {@link cn.iocoder.yudao.module.market.dal.dataobject.reward.RewardActivityDO}
*
* @param userId
* @param priceCalculate
*/
@SuppressWarnings("unused")
private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) {
// 获取 SKU 级别的所有优惠信息
Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId);
Map<RewardActivityDO, Set<Long>> rewardActivities = rewardService.getMatchRewardActivities(spuIds);
// 处理满减送活动
if (CollUtil.isNotEmpty(rewardActivities)) {
rewardActivities.forEach((rewardActivity, activitySpuIds) -> {
List<PriceCalculateRespDTO.OrderItem> orderItems = CollectionUtils.filterList(priceCalculate.getOrder().getItems(),
orderItem -> CollUtil.contains(activitySpuIds, orderItem.getSpuId()));
calculatePriceByRewardActivity(priceCalculate, orderItems, rewardActivity);
});
}
}
private void calculatePriceByRewardActivity(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems,
RewardActivityDO rewardActivity) {
// 获得最大匹配的满减送活动的规格
RewardActivityDO.Rule rule = getLastMatchRewardActivityRule(rewardActivity, orderItems);
if (rule == null) {
// 获取不到的情况下,记录不满足的优惠明细
addNotMeetPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(),
PromotionTypeEnum.REWARD_ACTIVITY.getType(), PromotionLevelEnum.ORDER.getLevel(),
getRewardActivityNotMeetTip(rewardActivity));
return;
}
// 分摊金额
// TODO 芋艿limit 不能超过最大价格
List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice());
// 记录优惠明细
addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(),
PromotionTypeEnum.REWARD_ACTIVITY.getType(), PromotionLevelEnum.ORDER.getLevel(), discountPartPrices,
true, StrUtil.format("满减送:省 {} 元", formatPrice(rule.getDiscountPrice())));
// 修改 SKU 的分摊
for (int i = 0; i < orderItems.size(); i++) {
modifyOrderItemOrderPartPriceFromDiscountPrice(orderItems.get(i), discountPartPrices.get(i), priceCalculate);
}
}
/**
*
*
* @param rewardActivity
* @param orderItems
* @return
*/
private RewardActivityDO.Rule getLastMatchRewardActivityRule(RewardActivityDO rewardActivity,
List<PriceCalculateRespDTO.OrderItem> orderItems) {
Integer count = CollectionUtils.getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getCount, Integer::sum);
// price 的计算逻辑,使用 orderDividePrice 的原因,主要考虑分摊后,这个才是该 SKU 当前真实的支付总价
Integer price = CollectionUtils.getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
assert count != null && price != null;
for (int i = rewardActivity.getRules().size() - 1; i >= 0; i--) {
RewardActivityDO.Rule rule = rewardActivity.getRules().get(i);
if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())
&& price >= rule.getLimit()) {
return rule;
}
if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType())
&& count >= rule.getLimit()) {
return rule;
}
}
return null;
}
/**
*
*
* @param rewardActivity
* @return
*/
private String getRewardActivityNotMeetTip(RewardActivityDO rewardActivity) {
return "TODO"; // TODO 芋艿:后面再想想
}
// ========== 其它相对通用的方法 ==========
/**
* OrderItem
*
* @param priceCalculate
* @param orderItem SKU
* @param id
* @param name
* @param type
* @param level
* @param newPayPrice
* @param meet
* @param meetTip
*/
private void addPromotion(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, private void addPromotion(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
Long id, String name, Integer type, Integer level, Long id, String name, Integer type, Integer level,
Integer newPayPrice, Boolean meet, String meetTip) { Integer newPayPrice, Boolean meet, String meetTip) {
// 创建营销明细 Item // 创建营销明细 Item
// TODO 芋艿orderItem.getPayPrice() 要不要改成 orderDividePrice同时newPayPrice 要不要改成直接传递 discountPrice
PriceCalculateRespDTO.PromotionItem promotionItem = new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId()) PriceCalculateRespDTO.PromotionItem promotionItem = new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId())
.setOriginalPrice(orderItem.getPayPrice()).setDiscountPrice(orderItem.getPayPrice() - newPayPrice); .setOriginalPrice(orderItem.getPayPrice()).setDiscountPrice(orderItem.getPayPrice() - newPayPrice);
// 创建营销明细 // 创建营销明细
@ -152,6 +286,60 @@ public class PriceServiceImpl implements PriceService {
priceCalculate.getPromotions().add(promotion); priceCalculate.getPromotions().add(promotion);
} }
/**
* OrderItem
*
* @param priceCalculate
* @param orderItems SKU
* @param id
* @param name
* @param type
* @param level
* @param discountPrices SKU orderItems
* @param meet
* @param meetTip
*/
private void addPromotion(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems,
Long id, String name, Integer type, Integer level,
List<Integer> discountPrices, Boolean meet, String meetTip) {
// 创建营销明细 Item
List<PriceCalculateRespDTO.PromotionItem> promotionItems = new ArrayList<>(discountPrices.size());
for (int i = 0; i < orderItems.size(); i++) {
PriceCalculateRespDTO.OrderItem orderItem = orderItems.get(i);
promotionItems.add(new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId())
.setOriginalPrice(orderItem.getPayPrice()).setDiscountPrice(discountPrices.get(i)));
}
// 创建营销明细
PriceCalculateRespDTO.Promotion promotion = new PriceCalculateRespDTO.Promotion()
.setId(id).setName(name).setType(type).setLevel(level)
.setOriginalPrice(getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum))
.setDiscountPrice(getSumValue(discountPrices, value -> value, Integer::sum))
.setItems(promotionItems).setMeet(meet).setMeetTip(meetTip);
priceCalculate.getPromotions().add(promotion);
}
private void addNotMeetPromotion(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems,
Long id, String name, Integer type, Integer level, String meetTip) {
// 创建营销明细 Item
List<PriceCalculateRespDTO.PromotionItem> promotionItems = CollectionUtils.convertList(orderItems,
orderItem -> new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId())
.setOriginalPrice(orderItem.getOrderDividePrice()).setDiscountPrice(0));
// 创建营销明细
Integer originalPrice = CollectionUtils.getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
PriceCalculateRespDTO.Promotion promotion = new PriceCalculateRespDTO.Promotion()
.setId(id).setName(name).setType(type).setLevel(level)
.setOriginalPrice(originalPrice).setDiscountPrice(0)
.setItems(promotionItems).setMeet(false).setMeetTip(meetTip);
priceCalculate.getPromotions().add(promotion);
}
/**
* OrderItem payPrice Order payPrice
*
* @param orderItem SKU
* @param newPayPrice payPrice
* @param priceCalculate
*/
private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice, private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice,
PriceCalculateRespDTO priceCalculate) { PriceCalculateRespDTO priceCalculate) {
int diffPayPrice = orderItem.getPayPrice() - newPayPrice; int diffPayPrice = orderItem.getPayPrice() - newPayPrice;
@ -163,17 +351,45 @@ public class PriceServiceImpl implements PriceService {
priceCalculate.getOrder().setPayPrice(priceCalculate.getOrder().getPayPrice() - diffPayPrice); priceCalculate.getOrder().setPayPrice(priceCalculate.getOrder().getPayPrice() - diffPayPrice);
} }
// TODO 芋艿:提前实现 /**
private Supplier<Double> getMemberDiscountSupplier(Long userId) { * OrderItem orderPartPrice Order discountPrice
return Suppliers.memoize(() -> { *
if (userId == 1) { * Order discountPrice OrderItem orderPartPrice
return 90d; *
* @param orderItem SKU
* @param addOrderPartPrice
* @param priceCalculate
*/
private void modifyOrderItemOrderPartPriceFromDiscountPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer addOrderPartPrice,
PriceCalculateRespDTO priceCalculate) {
// 设置 OrderItem 价格相关字段
orderItem.setOrderPartPrice(orderItem.getOrderPartPrice() + addOrderPartPrice);
orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice());
// 设置 Order 相关相关字段
PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
order.setDiscountPrice(order.getDiscountPrice() + addOrderPartPrice);
order.setPayPrice(order.getPayPrice() - addOrderPartPrice);
} }
if (userId == 2) {
return 80d; private List<Integer> dividePrice(List<PriceCalculateRespDTO.OrderItem> orderItems, Integer price) {
List<Integer> prices = new ArrayList<>(orderItems.size());
Integer total = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
assert total != null;
int remainPrice = price;
// 遍历每一个,进行分摊
for (int i = 0; i < orderItems.size(); i++) {
PriceCalculateRespDTO.OrderItem orderItem = orderItems.get(i);
int partPrice;
if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减
partPrice = (int) (price * (1.0D * orderItem.getOrderDividePrice() / total));
remainPrice -= partPrice;
} else {
partPrice = remainPrice;
} }
return null; // 无优惠 Assert.isTrue(partPrice > 0, "分摊金额必须大于 0");
}); prices.add(partPrice);
}
return prices;
} }
private String formatPrice(Integer price) { private String formatPrice(Integer price) {

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.market.service.reward;
import cn.iocoder.yudao.module.market.dal.dataobject.reward.RewardActivityDO;
import java.util.Map;
import java.util.Set;
/**
* Service
*
* @author
*/
public interface RewardService {
/**
* SPU
*
* @param spuIds SPU
* @return SPU value SPU
*/
Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds);
}

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.market.service.reward;
import cn.iocoder.yudao.module.market.dal.dataobject.reward.RewardActivityDO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* Service
*
* @author
*/
@Service
@Validated
public class RewardServiceImpl implements RewardService {
// TODO 芋艿:待实现
@Override
public Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) {
return Collections.emptyMap();
}
}

@ -1,20 +1,27 @@
package cn.iocoder.yudao.module.market.service.price; package cn.iocoder.yudao.module.market.service.price;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.market.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.market.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.market.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.market.enums.common.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum; import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum;
import cn.iocoder.yudao.module.market.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.market.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.market.service.discount.DiscountService; import cn.iocoder.yudao.module.market.service.discount.DiscountService;
import cn.iocoder.yudao.module.market.service.reward.RewardService;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -36,6 +43,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
@Mock @Mock
private DiscountService discountService; private DiscountService discountService;
@Mock @Mock
private RewardService rewardService;
@Mock
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@Test @Test
@ -46,7 +55,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
.setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2))); .setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2)));
// mock 方法(商品 SKU 信息) // mock 方法(商品 SKU 信息)
ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100)); ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));
when(productSkuApi.getSkuList(eq(SetUtils.asSet(10L)))).thenReturn(singletonList(productSku)); when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku));
// 调用 // 调用
PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
@ -96,13 +105,13 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
// mock 方法(商品 SKU 信息) // mock 方法(商品 SKU 信息)
ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100)); ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));
ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50)); ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50));
when(productSkuApi.getSkuList(eq(SetUtils.asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02));
// mock 方法(限时折扣 DiscountActivity 信息) // mock 方法(限时折扣 DiscountActivity 信息)
DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号") DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号")
.setSkuId(10L).setPromotionPrice(80)); .setSkuId(10L).setPromotionPrice(80));
DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号") DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号")
.setSkuId(20L).setPromotionPrice(40)); .setSkuId(20L).setPromotionPrice(40));
when(discountService.getMatchDiscountProducts(eq(SetUtils.asSet(10L, 20L)))).thenReturn( when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn(
MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map());
// 调用 // 调用
@ -167,4 +176,182 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
assertEquals(promotionItem02.getDiscountPrice(), 30); assertEquals(promotionItem02.getDiscountPrice(), 30);
} }
/**
*
*/
@Test
public void testCalculatePrice_rewardActivity() {
// 准备参数
PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId())
.setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2),
new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3),
new PriceCalculateReqDTO.Item().setSkuId(30L).setCount(4)));
// mock 方法(商品 SKU 信息)
ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100).setSpuId(1L));
ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50).setSpuId(2L));
ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L));
when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03));
// mock 方法(限时折扣 DiscountActivity 信息)
RewardActivityDO rewardActivity01 = randomPojo(RewardActivityDO.class, o -> o.setId(1000L).setName("活动 1000 号")
.setSpuIds(asList(10L, 20L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType())
.setRules(singletonList(new RewardActivityDO.Rule().setLimit(200).setDiscountPrice(70))));
RewardActivityDO rewardActivity02 = randomPojo(RewardActivityDO.class, o -> o.setId(2000L).setName("活动 2000 号")
.setSpuIds(singletonList(30L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType())
.setRules(asList(new RewardActivityDO.Rule().setLimit(1).setDiscountPrice(10),
new RewardActivityDO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个
new RewardActivityDO.Rule().setLimit(10).setDiscountPrice(100))));
Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
matchRewardActivities.put(rewardActivity01, asSet(1L, 2L));
matchRewardActivities.put(rewardActivity02, asSet(3L));
when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities);
// 调用
PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 470);
assertEquals(order.getDiscountPrice(), 130);
assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 0);
assertEquals(order.getPayPrice(), 340);
assertNull(order.getCouponId());
// 断言 OrderItem 部分
assertEquals(order.getItems().size(), 3);
PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0);
assertEquals(orderItem01.getSkuId(), 10L);
assertEquals(orderItem01.getCount(), 2);
assertEquals(orderItem01.getOriginalPrice(), 200);
assertEquals(orderItem01.getOriginalUnitPrice(), 100);
assertEquals(orderItem01.getDiscountPrice(), 0);
assertEquals(orderItem01.getPayPrice(), 200);
assertEquals(orderItem01.getOrderPartPrice(), 40);
assertEquals(orderItem01.getOrderDividePrice(), 160);
PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1);
assertEquals(orderItem02.getSkuId(), 20L);
assertEquals(orderItem02.getCount(), 3);
assertEquals(orderItem02.getOriginalPrice(), 150);
assertEquals(orderItem02.getOriginalUnitPrice(), 50);
assertEquals(orderItem02.getDiscountPrice(), 0);
assertEquals(orderItem02.getPayPrice(), 150);
assertEquals(orderItem02.getOrderPartPrice(), 30);
assertEquals(orderItem02.getOrderDividePrice(), 120);
PriceCalculateRespDTO.OrderItem orderItem03 = order.getItems().get(2);
assertEquals(orderItem03.getSkuId(), 30L);
assertEquals(orderItem03.getCount(), 4);
assertEquals(orderItem03.getOriginalPrice(), 120);
assertEquals(orderItem03.getOriginalUnitPrice(), 30);
assertEquals(orderItem03.getDiscountPrice(), 0);
assertEquals(orderItem03.getPayPrice(), 120);
assertEquals(orderItem03.getOrderPartPrice(), 60);
assertEquals(orderItem03.getOrderDividePrice(), 60);
// 断言 Promotion 部分(第一个)
assertEquals(priceCalculate.getPromotions().size(), 2);
PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0);
assertEquals(promotion01.getId(), 1000L);
assertEquals(promotion01.getName(), "活动 1000 号");
assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel());
assertEquals(promotion01.getOriginalPrice(), 350);
assertEquals(promotion01.getDiscountPrice(), 70);
assertTrue(promotion01.getMeet());
assertEquals(promotion01.getMeetTip(), "满减送:省 0.70 元");
assertEquals(promotion01.getItems().size(), 2);
PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0);
assertEquals(promotionItem011.getSkuId(), 10L);
assertEquals(promotionItem011.getOriginalPrice(), 200);
assertEquals(promotionItem011.getDiscountPrice(), 40);
PriceCalculateRespDTO.PromotionItem promotionItem012 = promotion01.getItems().get(1);
assertEquals(promotionItem012.getSkuId(), 20L);
assertEquals(promotionItem012.getOriginalPrice(), 150);
assertEquals(promotionItem012.getDiscountPrice(), 30);
// 断言 Promotion 部分(第二个)
PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1);
assertEquals(promotion02.getId(), 2000L);
assertEquals(promotion02.getName(), "活动 2000 号");
assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
assertEquals(promotion02.getLevel(), PromotionLevelEnum.ORDER.getLevel());
assertEquals(promotion02.getOriginalPrice(), 120);
assertEquals(promotion02.getDiscountPrice(), 60);
assertTrue(promotion02.getMeet());
assertEquals(promotion02.getMeetTip(), "满减送:省 0.60 元");
PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0);
assertEquals(promotion02.getItems().size(), 1);
assertEquals(promotionItem02.getSkuId(), 30L);
assertEquals(promotionItem02.getOriginalPrice(), 120);
assertEquals(promotionItem02.getDiscountPrice(), 60);
}
/**
*
*/
@Test
public void testCalculatePrice_rewardActivityNotMeet() {
// 准备参数
PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId())
.setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2),
new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3)));
// mock 方法(商品 SKU 信息)
ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100).setSpuId(1L));
ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50).setSpuId(2L));
when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02));
// mock 方法(限时折扣 DiscountActivity 信息)
RewardActivityDO rewardActivity01 = randomPojo(RewardActivityDO.class, o -> o.setId(1000L).setName("活动 1000 号")
.setSpuIds(asList(10L, 20L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType())
.setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70))));
Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
matchRewardActivities.put(rewardActivity01, asSet(1L, 2L));
when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities);
// 调用
PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 350);
assertEquals(order.getDiscountPrice(), 0);
assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 0);
assertEquals(order.getPayPrice(), 350);
assertNull(order.getCouponId());
// 断言 OrderItem 部分
assertEquals(order.getItems().size(), 2);
PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0);
assertEquals(orderItem01.getSkuId(), 10L);
assertEquals(orderItem01.getCount(), 2);
assertEquals(orderItem01.getOriginalPrice(), 200);
assertEquals(orderItem01.getOriginalUnitPrice(), 100);
assertEquals(orderItem01.getDiscountPrice(), 0);
assertEquals(orderItem01.getPayPrice(), 200);
assertEquals(orderItem01.getOrderPartPrice(), 0);
assertEquals(orderItem01.getOrderDividePrice(), 200);
PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1);
assertEquals(orderItem02.getSkuId(), 20L);
assertEquals(orderItem02.getCount(), 3);
assertEquals(orderItem02.getOriginalPrice(), 150);
assertEquals(orderItem02.getOriginalUnitPrice(), 50);
assertEquals(orderItem02.getDiscountPrice(), 0);
assertEquals(orderItem02.getPayPrice(), 150);
assertEquals(orderItem02.getOrderPartPrice(), 0);
assertEquals(orderItem02.getOrderDividePrice(), 150);
// 断言 Promotion 部分
assertEquals(priceCalculate.getPromotions().size(), 1);
PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0);
assertEquals(promotion01.getId(), 1000L);
assertEquals(promotion01.getName(), "活动 1000 号");
assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType());
assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel());
assertEquals(promotion01.getOriginalPrice(), 350);
assertEquals(promotion01.getDiscountPrice(), 0);
assertFalse(promotion01.getMeet());
assertEquals(promotion01.getMeetTip(), "TODO"); // TODO 芋艿:后面再想想
assertEquals(promotion01.getItems().size(), 2);
PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0);
assertEquals(promotionItem011.getSkuId(), 10L);
assertEquals(promotionItem011.getOriginalPrice(), 200);
assertEquals(promotionItem011.getDiscountPrice(), 0);
PriceCalculateRespDTO.PromotionItem promotionItem012 = promotion01.getItems().get(1);
assertEquals(promotionItem012.getSkuId(), 20L);
assertEquals(promotionItem012.getOriginalPrice(), 150);
assertEquals(promotionItem012.getDiscountPrice(), 0);
}
} }

Loading…
Cancel
Save