| | |
| | | import cn.hutool.core.map.MapUtil; |
| | | import cn.lili.common.enums.PromotionTypeEnum; |
| | | import cn.lili.common.utils.CurrencyUtil; |
| | | import cn.lili.modules.order.cart.entity.dto.SkuMapDTO; |
| | | import cn.lili.modules.order.cart.entity.dto.TradeDTO; |
| | | import cn.lili.modules.order.cart.entity.vo.CartSkuVO; |
| | | import cn.lili.modules.order.order.entity.dto.DiscountPriceItem; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | * @param promotionTypeEnum 促销类型 |
| | | */ |
| | | public static void recountPrice(TradeDTO tradeDTO, Map<String, Double> skuPromotionDetail, Double discountPrice, |
| | | PromotionTypeEnum promotionTypeEnum, String activityId) { |
| | | PromotionTypeEnum promotionTypeEnum, String activityId, Integer goodsUseLimitNum) { |
| | | |
| | | // sku 促销信息非空判定 |
| | | if (skuPromotionDetail == null || skuPromotionDetail.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | //计算总金额 |
| | | Double totalPrice = 0D; |
| | | for (Double value : skuPromotionDetail.values()) { |
| | | totalPrice = CurrencyUtil.add(totalPrice, value); |
| | | } |
| | | |
| | | //极端情况,如果扣减金额小于需要支付的金额,则扣减金额=支付金额,不能成为负数 |
| | | if (discountPrice > totalPrice) { |
| | | discountPrice = totalPrice; |
| | | |
| | | for (String skuId : skuPromotionDetail.keySet()) { |
| | | |
| | | //获取对应商品进行计算 |
| | | for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) { |
| | | |
| | | if (cartSkuVO.getGoodsSku().getId().equals(skuId)) { |
| | | //优惠券金额,则计入优惠券 ,其他则计入总的discount price |
| | | if (promotionTypeEnum == PromotionTypeEnum.COUPON) { |
| | | cartSkuVO.getPriceDetailDTO().setCouponPrice(cartSkuVO.getPriceDetailDTO().getGoodsPrice()); |
| | | } else { |
| | | cartSkuVO.getPriceDetailDTO().setDiscountPrice(cartSkuVO.getPriceDetailDTO().getGoodsPrice()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | //获取购物车信息 |
| | | List<CartSkuVO> skuVOList = tradeDTO.getSkuList(); |
| | | |
| | | // 获取map分配sku的总数,如果是最后一个商品分配金额,则将金额从百分比改为总金额扣减,避免出现小数除不尽 |
| | | AtomicInteger count = new AtomicInteger(skuPromotionDetail.size()); |
| | | |
| | | //已优惠金额 |
| | | AtomicReference<Double> deducted = new AtomicReference<>(0D); |
| | | |
| | | for (String skuId : skuPromotionDetail.keySet()) { |
| | | if (goodsUseLimitNum > 0) { |
| | | // 处理限制商品数量逻辑,只处理一个商品 |
| | | List<SkuMapDTO> skuMapDTOList = new ArrayList<>(); |
| | | for (String skuId : skuPromotionDetail.keySet()) { |
| | | skuMapDTOList.add(new SkuMapDTO(skuId, skuPromotionDetail.get(skuId))); |
| | | } |
| | | skuMapDTOList.sort((o1, o2) -> o2.getPrice().compareTo(o1.getPrice())); |
| | | |
| | | //获取对应商品进行计算 |
| | | final int[] i = {0}; |
| | | for (SkuMapDTO skuMap : skuMapDTOList) { |
| | | |
| | | Double finalDiscountPrice = discountPrice; |
| | | Double finalTotalPrice = totalPrice; |
| | | skuVOList.stream().filter(l -> l.getGoodsSku().getId().equals(skuId)).findFirst().ifPresent(cartSkuVO -> { |
| | | //sku 优惠金额 |
| | | Double skuDiscountPrice; |
| | | count.getAndDecrement(); |
| | | //获取对应商品进行计算 |
| | | Double finalDiscountPrice = discountPrice; |
| | | skuVOList.stream().filter(l -> l.getGoodsSku().getId().equals(skuMap.getSkuId())).findFirst().ifPresent(cartSkuVO -> { |
| | | //sku 优惠金额 |
| | | Double skuDiscountPrice = 0D; |
| | | if (i[0] < 1) { |
| | | |
| | | //非最后一个商品,则按照比例计算 |
| | | if (count.get() > 0) { |
| | | //商品金额占比 |
| | | double point = CurrencyUtil.div(cartSkuVO.getPriceDetailDTO().getGoodsPrice(), finalTotalPrice, 4); |
| | | //商品优惠金额 |
| | | skuDiscountPrice = CurrencyUtil.mul(finalDiscountPrice, point); |
| | | //累加已优惠金额 |
| | | deducted.set(CurrencyUtil.add(deducted.get(), skuDiscountPrice)); |
| | | if (cartSkuVO.getUtilPrice() > finalDiscountPrice) { |
| | | skuDiscountPrice = cartSkuVO.getUtilPrice() - finalDiscountPrice; |
| | | } else { |
| | | skuDiscountPrice = cartSkuVO.getUtilPrice(); |
| | | } |
| | | //累加已优惠金额 |
| | | deducted.set(CurrencyUtil.add(deducted.get(), skuDiscountPrice)); |
| | | i[0] = i[0] + 1; |
| | | } |
| | | calculateCartSkuPromotionsPrice(cartSkuVO, skuDiscountPrice, promotionTypeEnum, activityId); |
| | | }); |
| | | discountPrice = deducted.get(); |
| | | } |
| | | } else { |
| | | for (Double value : skuPromotionDetail.values()) { |
| | | totalPrice = CurrencyUtil.add(totalPrice, value); |
| | | } |
| | | |
| | | //极端情况,如果扣减金额小于需要支付的金额,则扣减金额=支付金额,不能成为负数 |
| | | if (discountPrice > totalPrice) { |
| | | discountPrice = totalPrice; |
| | | |
| | | for (String skuId : skuPromotionDetail.keySet()) { |
| | | |
| | | //获取对应商品进行计算 |
| | | for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) { |
| | | |
| | | if (cartSkuVO.getGoodsSku().getId().equals(skuId)) { |
| | | //优惠券金额,则计入优惠券 ,其他则计入总的discount price |
| | | if (promotionTypeEnum == PromotionTypeEnum.COUPON) { |
| | | cartSkuVO.getPriceDetailDTO().setCouponPrice(cartSkuVO.getPriceDetailDTO().getGoodsPrice()); |
| | | } else { |
| | | cartSkuVO.getPriceDetailDTO().setDiscountPrice(cartSkuVO.getPriceDetailDTO().getGoodsPrice()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // 如果是最后一个商品 则减去之前优惠的金额来进行计算 |
| | | else { |
| | | skuDiscountPrice = CurrencyUtil.sub(finalDiscountPrice, deducted.get()); |
| | | } |
| | | } |
| | | |
| | | calculateCartSkuPromotionsPrice(cartSkuVO, skuDiscountPrice, promotionTypeEnum, activityId); |
| | | }); |
| | | // 获取map分配sku的总数,如果是最后一个商品分配金额,则将金额从百分比改为总金额扣减,避免出现小数除不尽 |
| | | AtomicInteger count = new AtomicInteger(skuPromotionDetail.size()); |
| | | |
| | | |
| | | for (String skuId : skuPromotionDetail.keySet()) { |
| | | |
| | | //获取对应商品进行计算 |
| | | |
| | | Double finalDiscountPrice = discountPrice; |
| | | Double finalTotalPrice = totalPrice; |
| | | skuVOList.stream().filter(l -> l.getGoodsSku().getId().equals(skuId)).findFirst().ifPresent(cartSkuVO -> { |
| | | //sku 优惠金额 |
| | | Double skuDiscountPrice; |
| | | count.getAndDecrement(); |
| | | |
| | | //非最后一个商品,则按照比例计算 |
| | | if (count.get() > 0) { |
| | | //商品金额占比 |
| | | double point = CurrencyUtil.div(cartSkuVO.getPriceDetailDTO().getGoodsPrice(), finalTotalPrice, 4); |
| | | //商品优惠金额 |
| | | skuDiscountPrice = CurrencyUtil.mul(finalDiscountPrice, point); |
| | | //累加已优惠金额 |
| | | deducted.set(CurrencyUtil.add(deducted.get(), skuDiscountPrice)); |
| | | } |
| | | // 如果是最后一个商品 则减去之前优惠的金额来进行计算 |
| | | else { |
| | | skuDiscountPrice = CurrencyUtil.sub(finalDiscountPrice, deducted.get()); |
| | | } |
| | | |
| | | calculateCartSkuPromotionsPrice(cartSkuVO, skuDiscountPrice, promotionTypeEnum, activityId); |
| | | }); |
| | | |
| | | } |
| | | } |
| | | |
| | | calculateNotEnoughPromotionsPrice(skuVOList, skuPromotionDetail, discountPrice, totalPrice, promotionTypeEnum, activityId); |
| | | |
| | | } |
| | |
| | | // 如果还有剩余金额,则继续分摊 |
| | | if (balance.get() > 0) { |
| | | skuPromotionDetailClone.remove(lastSkuId.toString()); |
| | | double lastDiscountPrice = CurrencyUtil.sub(discountPrice, skuPromotionDetail.get(lastSkuId.toString())); |
| | | double lastTotalPrice = CurrencyUtil.sub(totalPrice, skuPromotionDetail.get(lastSkuId.toString())); |
| | | filterEnoughSku(skuVOList, skuPromotionDetailClone, lastDiscountPrice, lastTotalPrice, balance, lastSkuId, promotionTypeEnum, activityId); |
| | | if (skuPromotionDetail.containsKey(lastSkuId.toString())) { |
| | | double lastDiscountPrice = CurrencyUtil.sub(discountPrice, skuPromotionDetail.get(lastSkuId.toString())); |
| | | double lastTotalPrice = CurrencyUtil.sub(totalPrice, skuPromotionDetail.get(lastSkuId.toString())); |
| | | filterEnoughSku(skuVOList, skuPromotionDetailClone, lastDiscountPrice, lastTotalPrice, balance, lastSkuId, promotionTypeEnum, activityId); |
| | | } |
| | | } else { |
| | | break; |
| | | } |
| | |
| | | |
| | | |
| | | private static void filterEnoughSku(List<CartSkuVO> skuVOList, Map<String, Double> skuPromotionDetail, |
| | | Double discountPrice, Double totalPrice, |
| | | AtomicReference<Double> balance, StringBuilder lastSkuId, |
| | | PromotionTypeEnum promotionTypeEnum, String activityId) { |
| | | Double discountPrice, Double totalPrice, |
| | | AtomicReference<Double> balance, StringBuilder lastSkuId, |
| | | PromotionTypeEnum promotionTypeEnum, String activityId) { |
| | | AtomicInteger count = new AtomicInteger(skuPromotionDetail.size()); |
| | | AtomicReference<Double> countPrice = new AtomicReference<>(0D); |
| | | for (String skuId : skuPromotionDetail.keySet()) { |