diff --git a/cart/cart-service-impl/src/main/resources/config/application.properties b/cart/cart-service-impl/src/main/resources/config/application.properties
deleted file mode 100644
index 125191e0..00000000
--- a/cart/cart-service-impl/src/main/resources/config/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-##################### 业务模块 #####################
\ No newline at end of file
diff --git a/cart/cart-service-impl/src/main/resources/mybatis-config.xml b/cart/cart-service-impl/src/main/resources/mybatis-config.xml
deleted file mode 100644
index 7f604cc7..00000000
--- a/cart/cart-service-impl/src/main/resources/mybatis-config.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/mobile-web/src/page/cart/index.vue b/mobile-web/src/page/cart/index.vue
index 47cce44f..807ed6b5 100644
--- a/mobile-web/src/page/cart/index.vue
+++ b/mobile-web/src/page/cart/index.vue
@@ -14,20 +14,19 @@
-
-
-
-
-
-
-
-
+
+
+
+ 满减送
+ {{ formatFullPrivilegeText(itemGroup.activity) }}
+
+
@@ -47,13 +46,14 @@
- 全选
+ 全选
@@ -87,6 +87,39 @@ export default {
},
},
methods: {
+ formatFullPrivilegeText(activity) {
+ let text = '';
+ let fullPrivilege = activity.fullPrivilege;
+ for (let i in fullPrivilege.privileges) {
+ let privilege = fullPrivilege.privileges[i];
+ if (i > 0) {
+ text += ';';
+ }
+ if (fullPrivilege.cycled) {
+ text += '每';
+ }
+ if (privilege.meetType === 1) {
+ text += '满 ' + privilege.meetValue / 100.0 + ' 元,';
+ } else if (privilege.meetType === 2) {
+ text += '满 ' + privilege.meetValue + ' 件,';
+ }
+ if (privilege.preferentialType === 1) {
+ text += '减 ' + privilege.preferentialValue / 100.0 + ' 元';
+ } else if (privilege.preferentialType === 2) {
+ text += '打 ' + privilege.preferentialValue / 10.0 + ' 折';
+ }
+ }
+ return text;
+ },
+ formatItemGroupDiscountPriceText() {
+ let price = 0;
+ for (let i in this.itemGroups) {
+ let itemGroup = this.itemGroups[i];
+ price += itemGroup.fee.discountTotal;
+ }
+ return price > 0 ? '立减 ' + price / 100.0 + ' 元' : '';
+ },
+
calCheckedItemIds() {
// debugger;
let itemIds = [];
@@ -122,11 +155,10 @@ export default {
// 计算 checkedItemIds + checkedAll
this.calCheckedItemIds();
},
- onItemSelectedChange(newVal) {
+ onItemSelectedChange(newVal) { // TODO 芋艿,后续研究下。这样的处理方式,很奇怪。
if (!this.checkedItemIds) {
return;
}
- // debugger;
let selected;
let diffItemIds;
if (newVal.length > this.oldCheckedItemIds.length) { // 新增
@@ -152,9 +184,17 @@ export default {
if (this.checkedAll === undefined) {
return;
}
- updateCartSelected(this.getItemIds(), newVal).then(data => {
- this.handleData(data);
- })
+ // debugger;
+ // updateCartSelected(this.getItemIds(), newVal).then(data => {
+ // this.handleData(data);
+ // })
+ if (newVal) {
+ this.onItemSelectedChange(this.getItemIds());
+ } else {
+ // alert('有 bug ,后续修复');
+ // this.onItemSelectedChange(this.getItemIds());
+ // TODO 芋艿,暂时有 bug 。后续修复
+ }
},
onSubmit() {
this.$router.push('/order?from=cart')
@@ -164,7 +204,7 @@ export default {
return {
...item.spu,
quantity: item.buyQuantity,
- price: item.price,
+ price: item.discountPrice || item.price,
sku: {
...item,
spu: undefined,
diff --git a/mobile-web/src/page/product/detail.vue b/mobile-web/src/page/product/detail.vue
index fd709d01..fe7b0bdb 100644
--- a/mobile-web/src/page/product/detail.vue
+++ b/mobile-web/src/page/product/detail.vue
@@ -248,7 +248,7 @@
text += '每';
}
if (privilege.meetType === 1) {
- text += '满 ' + privilege.meetValue + ' 元,';
+ text += '满 ' + privilege.meetValue / 100.0 + ' 元,';
} else if (privilege.meetType === 2) {
text += '满 ' + privilege.meetValue + ' 件,';
}
diff --git a/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersCartDetailVO.java b/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersCartDetailVO.java
index 05ed39d7..f63d3ad2 100644
--- a/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersCartDetailVO.java
+++ b/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersCartDetailVO.java
@@ -1,6 +1,7 @@
package cn.iocoder.mall.order.application.vo;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
+import cn.iocoder.mall.promotion.api.bo.PromotionActivityBO;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -30,12 +31,30 @@ public class UsersCartDetailVO {
@Accessors(chain = true)
public static class ItemGroup {
- // TODO 优惠活动
- private Object activity;
+ /**
+ * 优惠活动
+ */
+ private PromotionActivityBO activity; // TODO 芋艿,偷懒
+ /**
+ * 优惠活动是否生效
+ *
+ * 多个商品,参与某个活动,因为并发达到条件,所以会存在未生效的情况。所以一共有三种情况
+ *
+ * 1. activity 非空,activityEffectEffective 为 true,参与活动,且生效
+ * 2. activity 非空,activityEffectEffective 为 false ,参与活动,并未生效
+ * 3. activity 为空,activityEffectEffective 为空,并未参与活动。
+ */
+ private Boolean activityEffectEffective;
/**
* 商品数组
*/
private List items;
+ /**
+ * 费用
+ *
+ * TODO 芋艿,这里先偷懒,postageTotal 字段用不到。
+ */
+ private Fee fee;
}
@@ -79,6 +98,20 @@ public class UsersCartDetailVO {
* 是否选中
*/
private Boolean selected;
+ /**
+ * 优惠活动
+ */
+ private PromotionActivityBO activity;
+ /**
+ * 折扣价
+ */
+ private Integer discountPrice;
+ /**
+ * 费用
+ *
+ * TODO 芋艿,这里先偷懒,postageTotal 字段用不到。
+ */
+ private Fee fee;
}
@@ -151,7 +184,7 @@ public class UsersCartDetailVO {
}
/**
- * 邮费信息
+ * 邮费信息 TODO 芋艿,未完成
*/
@Data
@Accessors(chain = true)
diff --git a/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersOrderConfirmCreateVO.java b/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersOrderConfirmCreateVO.java
index a735cec4..3ab835a8 100644
--- a/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersOrderConfirmCreateVO.java
+++ b/order/order-application/src/main/java/cn/iocoder/mall/order/application/vo/UsersOrderConfirmCreateVO.java
@@ -1,6 +1,7 @@
package cn.iocoder.mall.order.application.vo;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
+import cn.iocoder.mall.promotion.api.bo.PromotionActivityBO;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -28,8 +29,12 @@ public class UsersOrderConfirmCreateVO {
@Accessors(chain = true)
public static class ItemGroup {
- // TODO 优惠活动
- private Object activity;
+ /**
+ * 优惠活动
+ */
+ // TODO 芋艿,目前只会有【满减送】的情况,未来有新的促销方式,可能需要改成数组
+ // TODO 芋艿,后面改成 VO
+ private PromotionActivityBO activity;
/**
* 商品数组
*/
@@ -73,6 +78,10 @@ public class UsersOrderConfirmCreateVO {
* 购买数量
*/
private Integer buyQuantity;
+ /**
+ * 折扣价
+ */
+ private Integer discountPrice;
}
diff --git a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CalcOrderPriceBO.java b/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CalcOrderPriceBO.java
index 1c80edd8..8ecfe80c 100644
--- a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CalcOrderPriceBO.java
+++ b/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CalcOrderPriceBO.java
@@ -41,10 +41,26 @@ public class CalcOrderPriceBO {
*/
// TODO 芋艿,目前只会有【满减送】的情况,未来有新的促销方式,可能需要改成数组
private PromotionActivityBO activity;
+ /**
+ * 优惠活动是否生效
+ *
+ * 多个商品,参与某个活动,因为并发达到条件,所以会存在未生效的情况。所以一共有三种情况
+ *
+ * 1. activity 非空,activityEffectEffective 为 true,参与活动,且生效
+ * 2. activity 非空,activityEffectEffective 为 false ,参与活动,并未生效
+ * 3. activity 为空,activityEffectEffective 为空,并未参与活动。
+ */
+ private Boolean activityEffectEffective;
/**
* 商品数组
*/
private List- items;
+ /**
+ * 费用
+ *
+ * TODO 芋艿,这里先偷懒,postageTotal 字段用不到。
+ */
+ private Fee fee;
}
@@ -70,6 +86,10 @@ public class CalcOrderPriceBO {
* TODO 芋艿,这里先偷懒,postageTotal 字段用不到。
*/
private Fee fee;
+ /**
+ * 折扣价
+ */
+ private Integer discountPrice;
}
diff --git a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CartBO.java b/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CartBO.java
deleted file mode 100644
index 077878d3..00000000
--- a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/CartBO.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cn.iocoder.mall.order.api.bo;
-
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-import java.util.List;
-
-/**
- * 购物车明细 BO
- */
-@Data
-@Accessors(chain = true)
-public class CartBO {
-
- /**
- * 商品分组数组
- */
- private List itemGroups;
- /**
- * 费用
- */
- private FeeMessageBO fee;
-
-}
diff --git a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/FeeDetailBO.java b/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/FeeDetailBO.java
deleted file mode 100644
index d45dd09e..00000000
--- a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/FeeDetailBO.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package cn.iocoder.mall.order.api.bo;
-
-public class FeeDetailBO {
-}
diff --git a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/MerchantItemGroup.java b/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/MerchantItemGroup.java
deleted file mode 100644
index ca18bc77..00000000
--- a/order/order-service-api/src/main/java/cn/iocoder/mall/order/api/bo/MerchantItemGroup.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.iocoder.mall.order.api.bo;
-
-import java.util.List;
-
-/**
- * 商家商品分组
- */
-public class MerchantItemGroup {
-
- /**
- * 商品分组数组
- */
- private List itemGroups;
- /**
- * 运费详情
- */
- private PostageDetailBO postageDetail;
-
-}
diff --git a/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/CartServiceImpl.java b/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/CartServiceImpl.java
index 7ffd16b7..c899254f 100644
--- a/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/CartServiceImpl.java
+++ b/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/CartServiceImpl.java
@@ -18,12 +18,11 @@ import cn.iocoder.mall.product.api.bo.ProductSkuBO;
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
import cn.iocoder.mall.promotion.api.PromotionActivityService;
import cn.iocoder.mall.promotion.api.bo.PromotionActivityBO;
-import cn.iocoder.mall.promotion.api.constant.PreferentialTypeEnum;
-import cn.iocoder.mall.promotion.api.constant.PromotionActivityStatusEnum;
-import cn.iocoder.mall.promotion.api.constant.PromotionActivityTypeEnum;
+import cn.iocoder.mall.promotion.api.constant.*;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
import java.util.*;
import java.util.stream.Collectors;
@@ -155,43 +154,41 @@ public class CartServiceImpl implements CartService {
public CommonResult calcOrderPrice(CalcOrderPriceDTO calcOrderPriceDTO) {
// 校验商品都存在
Map calcOrderItemMap = calcOrderPriceDTO.getItems().stream()
- .collect(Collectors.toMap(CalcOrderPriceDTO.Item::getSkuId, item -> item));
+ .collect(Collectors.toMap(CalcOrderPriceDTO.Item::getSkuId, item -> item)); // KEY:skuId
List skus = productSpuService.getProductSkuDetailList(calcOrderItemMap.keySet()).getData();
if (skus.size() != calcOrderPriceDTO.getItems().size()) {
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_ITEM_SOME_NOT_EXISTS.getCode());
}
// TODO 库存相关
- // TODO 获得促销活动
- // TODO 处理促销相关信息
- // 拼装结果
+ // 查询促销活动
+ CommonResult
> activityListResult = promotionActivityService.getPromotionActivityListBySpuIds(
+ skus.stream().map(sku -> sku.getSpu().getId()).collect(Collectors.toSet()),
+ Collections.singletonList(PromotionActivityStatusEnum.RUN.getValue()));
+ if (activityListResult.isError()) {
+ return CommonResult.error(activityListResult);
+ }
+ List activityList = activityListResult.getData();
+ // 拼装结果(主要是计算价格)
CalcOrderPriceBO calcOrderPriceBO = new CalcOrderPriceBO();
- // 1. 商品分组
- CalcOrderPriceBO.ItemGroup itemGroup0 = new CalcOrderPriceBO.ItemGroup()
- .setItems(new ArrayList<>());
- for (ProductSkuDetailBO sku : skus) {
- CalcOrderPriceBO.Item item = CartConvert.INSTANCE.convert(sku);
- // 将是否选中,购物数量,复制到 item 中
- CalcOrderPriceDTO.Item calcOrderItem = calcOrderItemMap.get(sku.getId());
- item.setSelected(calcOrderItem.getSelected());
- item.setBuyQuantity(calcOrderItem.getQuantity());
- // 添加到 itemGroup 中
- itemGroup0.getItems().add(item);
- }
- calcOrderPriceBO.setItemGroups(Collections.singletonList(itemGroup0));
- // 2. 计算价格
- CalcOrderPriceBO.Fee fee = new CalcOrderPriceBO.Fee(0, 0, 0, 0);
+ // 1. 创建初始的每一项的数组
+ List items = initCalcOrderPriceItems(skus, calcOrderItemMap);
+ // 2. 计算【限时折扣】促销
+ modifyPriceByTimeLimitDiscount(items, activityList);
+ // 3. 计算【满减送】促销
+ List itemGroups = groupByFullPrivilege(items, activityList);
+ calcOrderPriceBO.setItemGroups(itemGroups);
+ // 4. 计算最终的价格
+ Integer originalTotal = 0;
+ Integer presentTotal = 0;
+ Integer discountTotal = 0;
for (CalcOrderPriceBO.ItemGroup itemGroup : calcOrderPriceBO.getItemGroups()) {
- int originalTotal = 0;
- for (CalcOrderPriceBO.Item item : itemGroup.getItems()) {
- if (!item.getSelected()) { // 未选中,则不计算到其中
- continue;
- }
- originalTotal += item.getPrice() * item.getBuyQuantity();
- }
- fee.setOriginalTotal(fee.getOriginalTotal() + originalTotal);
- fee.setPresentTotal(fee.getOriginalTotal()); // TODO 芋艿,后续要计算优惠价格
+ originalTotal += itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getFee().getOriginalTotal() : 0).sum();
+ discountTotal += itemGroup.getFee().getDiscountTotal() + itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getFee().getDiscountTotal() : 0).sum();
+ presentTotal += itemGroup.getFee().getPresentTotal();
}
- calcOrderPriceBO.setFee(fee);
+ Assert.isTrue(originalTotal - discountTotal == presentTotal,
+ String.format("价格合计( %d - %d == %d )不正确", originalTotal, discountTotal, presentTotal));
+ calcOrderPriceBO.setFee(new CalcOrderPriceBO.Fee(originalTotal, discountTotal, 0, presentTotal));
// 返回
return CommonResult.success(calcOrderPriceBO);
}
@@ -229,7 +226,107 @@ public class CartServiceImpl implements CartService {
.setOriginalPrice(sku.getPrice()).setPresentPrice(presentPrice));
}
+ private List initCalcOrderPriceItems(List skus,
+ Map calcOrderItemMap) {
+ List items = new ArrayList<>();
+ for (ProductSkuDetailBO sku : skus) {
+ CalcOrderPriceBO.Item item = CartConvert.INSTANCE.convert(sku);
+ items.add(item);
+ // 将是否选中,购物数量,复制到 item 中
+ CalcOrderPriceDTO.Item calcOrderItem = calcOrderItemMap.get(sku.getId());
+ item.setSelected(calcOrderItem.getSelected());
+ item.setBuyQuantity(calcOrderItem.getQuantity());
+ // 计算初始价格
+ CalcOrderPriceBO.Fee fee = new CalcOrderPriceBO.Fee(0, 0, 0, 0);
+ fee.setOriginalTotal(item.getPrice() * item.getBuyQuantity());
+ fee.setPresentTotal(fee.getOriginalTotal());
+ item.setFee(fee);
+ }
+ return items;
+ }
+
+ private void modifyPriceByTimeLimitDiscount(List items, List activityList) {
+ for (CalcOrderPriceBO.Item item : items) {
+ // 获得符合条件的限时折扣
+ PromotionActivityBO timeLimitedDiscount = activityList.stream()
+ .filter(activity -> PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())
+ && activity.getTimeLimitedDiscount().getItems().stream().anyMatch(item0 -> item0.getSpuId().equals(item.getSpu().getId())))
+ .findFirst().orElse(null);
+ if (timeLimitedDiscount == null) {
+ continue;
+ }
+ // 计算价格
+ ProductSkuBO sku = new ProductSkuBO().setId(item.getId()).setSpuId(item.getSpu().getId()).setPrice(item.getPrice());
+ Integer newPrice = calcSkuPriceByTimeLimitDiscount(sku, timeLimitedDiscount);
+ if (newPrice.equals(item.getPrice())) {
+ continue;
+ }
+ // 设置优惠
+ item.setActivity(timeLimitedDiscount);
+ // 设置价格
+ item.setDiscountPrice(newPrice);
+ CalcOrderPriceBO.Fee fee = item.getFee();
+ fee.setDiscountTotal(fee.getDiscountTotal() + (item.getPrice() - newPrice) * item.getBuyQuantity());
+ fee.setPresentTotal(fee.getOriginalTotal() - fee.getDiscountTotal() + fee.getPostageTotal());
+ }
+ }
+
+ private List groupByFullPrivilege(List items, List activityList) {
+ List itemGroups = new ArrayList<>();
+ // 获得所有满减送促销
+ List fullPrivileges = activityList.stream()
+ .filter(activity -> PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()))
+ .collect(Collectors.toList());
+ // 基于满减送促销,进行分组
+ if (!fullPrivileges.isEmpty()) {
+ items = new ArrayList<>(items); // 因为下面会修改数组,进行浅拷贝,避免影响传入的 items 。
+ for (PromotionActivityBO fullPrivilege : fullPrivileges) {
+ // 创建 fullPrivilege 对应的分组
+ CalcOrderPriceBO.ItemGroup itemGroup = new CalcOrderPriceBO.ItemGroup()
+ .setActivity(fullPrivilege)
+ .setItems(new ArrayList<>());
+ // 筛选商品到分组中
+ for (Iterator iterator = items.iterator(); iterator.hasNext(); ) {
+ CalcOrderPriceBO.Item item = iterator.next();
+ if (!isSpuMatchFullPrivilege(item.getSpu().getId(), fullPrivilege)) {
+ continue;
+ }
+ itemGroup.getItems().add(item);
+ iterator.remove();
+ }
+ // 如果匹配到,则添加到 itemGroups 中
+ if (!itemGroup.getItems().isEmpty()) {
+ itemGroups.add(itemGroup);
+ }
+ }
+ }
+ // 处理未参加活动的商品,形成一个分组
+ if (!items.isEmpty()) {
+ CalcOrderPriceBO.ItemGroup itemGroup = new CalcOrderPriceBO.ItemGroup()
+ .setItems(items);
+ itemGroups.add(itemGroup);
+ }
+ // 计算每个分组的价格
+ for (CalcOrderPriceBO.ItemGroup itemGroup : itemGroups) {
+ itemGroup.setFee(calcSkuPriceByFullPrivilege(itemGroup));
+ itemGroup.setActivityEffectEffective(itemGroup.getFee().getDiscountTotal() > 0);
+ }
+ // 返回结果
+ return itemGroups;
+ }
+
+ /**
+ * 计算指定 SKU 在限时折扣下的价格
+ *
+ * @param sku SKU
+ * @param timeLimitedDiscount 限时折扣促销。
+ * 传入的该活动,要保证该 SKU 在该促销下一定有优惠。
+ * @return 计算后的价格
+ */
private Integer calcSkuPriceByTimeLimitDiscount(ProductSkuBO sku, PromotionActivityBO timeLimitedDiscount) {
+ if (timeLimitedDiscount == null) {
+ return sku.getPrice();
+ }
// 获得对应的优惠项
PromotionActivityBO.TimeLimitedDiscount.Item item = timeLimitedDiscount.getTimeLimitedDiscount().getItems().stream()
.filter(item0 -> item0.getSpuId().equals(sku.getSpuId()))
@@ -244,15 +341,84 @@ public class CartServiceImpl implements CartService {
return presentPrice >= 0 ? presentPrice : sku.getPrice(); // 如果计算优惠价格小于 0 ,则说明无法使用优惠。
}
if (PreferentialTypeEnum.DISCOUNT.getValue().equals(item.getPreferentialType())) { // 打折
- return sku.getPrice() * item.getPreferentialValue() / 10;
+ return sku.getPrice() * item.getPreferentialValue() / 100;
}
throw new IllegalArgumentException(String.format("折扣活动(%s) 的优惠类型不正确", timeLimitedDiscount.toString()));
}
+ private CalcOrderPriceBO.Fee calcSkuPriceByFullPrivilege(CalcOrderPriceBO.ItemGroup itemGroup) {
+ if (itemGroup.getActivity() == null) {
+ Integer originalTotal = itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getFee().getPresentTotal() : 0).sum();
+ return new CalcOrderPriceBO.Fee(originalTotal, 0, 0, originalTotal);
+ }
+ PromotionActivityBO activity = itemGroup.getActivity();
+ Assert.isTrue(PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()),
+ "传入的必须的满减送活动必须是满减送");
+ // 获得优惠信息
+ Integer itemCnt = itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getBuyQuantity() : 0).sum();
+ Integer originalTotal = itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getFee().getPresentTotal() : 0).sum();
+ List privileges = activity.getFullPrivilege().getPrivileges().stream()
+ .filter(privilege -> {
+ if (MeetTypeEnum.PRICE.getValue().equals(privilege.getMeetType())) {
+ return originalTotal >= privilege.getMeetValue();
+ }
+ if (MeetTypeEnum.QUANTITY.getValue().equals(privilege.getMeetType())) {
+ return itemCnt >= privilege.getMeetValue();
+ }
+ throw new IllegalArgumentException(String.format("满减送活动(%s) 的匹配(%s)不正确", itemGroup.getActivity().toString(), privilege.toString()));
+ }).collect(Collectors.toList());
+ // 获得不到优惠信息,返回原始价格
+ if (privileges.isEmpty()) {
+ return new CalcOrderPriceBO.Fee(originalTotal, 0, 0, originalTotal);
+ }
+ // 获得到优惠信息,进行价格计算
+ PromotionActivityBO.FullPrivilege.Privilege privilege = privileges.get(privileges.size() - 1);
+ Integer presentTotal;
+ if (PreferentialTypeEnum.PRICE.getValue().equals(privilege.getPreferentialType())) { // 减价
+ // 计算循环次数。这样,后续优惠的金额就是相乘了
+ Integer cycleCount = 1;
+ if (activity.getFullPrivilege().getCycled()) {
+ if (MeetTypeEnum.PRICE.getValue().equals(privilege.getMeetType())) {
+ cycleCount = originalTotal / privilege.getMeetValue();
+ } else if (MeetTypeEnum.QUANTITY.getValue().equals(privilege.getMeetType())) {
+ cycleCount = itemCnt / privilege.getMeetValue();
+ }
+ }
+ presentTotal = originalTotal - cycleCount * privilege.getMeetValue();
+ if (presentTotal < 0) { // 如果计算优惠价格小于 0 ,则说明无法使用优惠。
+ presentTotal = originalTotal;
+ }
+ } else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(privilege.getPreferentialType())) { // 打折
+ presentTotal = originalTotal * privilege.getPreferentialValue() / 100;
+ } else {
+ throw new IllegalArgumentException(String.format("满减送促销(%s) 的优惠类型不正确", activity.toString()));
+ }
+ return new CalcOrderPriceBO.Fee(originalTotal, originalTotal - presentTotal, 0, presentTotal);
+ }
+
private PromotionActivityBO findPromotionActivityByType(List activityList, PromotionActivityTypeEnum type) {
return activityList.stream()
.filter(activity -> type.getValue().equals(activity.getActivityType()))
.findFirst().orElse(null);
}
+ private List findPromotionActivityListByType(List activityList, PromotionActivityTypeEnum type) {
+ return activityList.stream()
+ .filter(activity -> type.getValue().equals(activity.getActivityType()))
+ .collect(Collectors.toList());
+ }
+
+ private boolean isSpuMatchFullPrivilege(Integer spuId, PromotionActivityBO activity) {
+ Assert.isTrue(PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()),
+ "传入的必须的促销活动必须是满减送");
+ PromotionActivityBO.FullPrivilege fullPrivilege = activity.getFullPrivilege();
+ if (RangeTypeEnum.ALL.getValue().equals(fullPrivilege.getRangeType())) {
+ return true;
+ } else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(fullPrivilege.getRangeType())) {
+ return fullPrivilege.getRangeValues().contains(spuId);
+ } else {
+ throw new IllegalArgumentException(String.format("促销活动(%s) 可用范围的类型是不正确", activity.toString()));
+ }
+ }
+
}
diff --git a/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/bo/PromotionActivityBO.java b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/bo/PromotionActivityBO.java
index fcf6ec31..272aa36a 100644
--- a/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/bo/PromotionActivityBO.java
+++ b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/bo/PromotionActivityBO.java
@@ -128,6 +128,10 @@ public class PromotionActivityBO implements Serializable {
* 指定可用商品列表
*/
private List rangeValues;
+ /**
+ * 是否循环
+ */
+ private Boolean cycled;
/**
* 优惠数组
*/
diff --git a/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/MeetTypeEnum.java b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/MeetTypeEnum.java
new file mode 100644
index 00000000..eef76187
--- /dev/null
+++ b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/MeetTypeEnum.java
@@ -0,0 +1,33 @@
+package cn.iocoder.mall.promotion.api.constant;
+
+/**
+ * 匹配类型枚举
+ */
+public enum MeetTypeEnum {
+
+ PRICE(1, "金额"),
+ QUANTITY(2, "数量"),;
+
+ /**
+ * 值
+ */
+ private final Integer value;
+ /**
+ * 名字
+ */
+ private final String name;
+
+ MeetTypeEnum(Integer value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ public Integer getValue() {
+ return value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}