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 @@ - - - - - - - - +
+ + +
- +
@@ -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; + } + +}