@@ -1,5 +1,6 @@
package cn.lili.modules.order.cart.render.util ;
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.TradeDTO ;
@@ -10,7 +11,8 @@ import lombok.extern.slf4j.Slf4j;
import java.util.Date ;
import java.util.List ;
import java.util.Map ;
import java.util.stream.Collectors ;
import java.util.concurrent.atomic.AtomicInteger ;
import java.util.concurrent.atomic.AtomicReference ;
/**
* 促销价格计算业务层实现
@@ -33,7 +35,7 @@ public class PromotionPriceUtil {
PromotionTypeEnum promotionTypeEnum , String activityId ) {
// sku 促销信息非空判定
if ( skuPromotionDetail = = null | | skuPromotionDetail . size ( ) = = 0 ) {
if ( skuPromotionDetail = = null | | skuPromotionDetail . isEmpty ( ) ) {
return ;
}
@@ -68,40 +70,39 @@ public class PromotionPriceUtil {
List < CartSkuVO > skuVOList = tradeDTO . getSkuList ( ) ;
// 获取map分配sku的总数, 如果是最后一个商品分配金额, 则将金额从百分比改为总金额扣减, 避免出现小数除不尽
int count = skuPromotionDetail . size ( ) ;
AtomicInteger count = new AtomicInteger ( skuPromotionDetail . size ( ) ) ;
//已优惠金额
Double deducted = 0D ;
AtomicReference < Double> deducted = new AtomicReference < > ( 0D ) ;
for ( String skuId : skuPromotionDetail . keySet ( ) ) {
//获取对应商品进行计算
for ( CartSkuVO cartSkuVO : skuVOList ) {
if ( cartSkuVO . getGoodsSku ( ) . getId ( ) . equals ( skuId ) ) {
count - - ;
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 > 0 ) {
if ( count . get ( ) > 0 ) {
//商品金额占比
double point = CurrencyUtil . div ( cartSkuVO . getPriceDetailDTO ( ) . getGoodsPrice ( ) , t otalPrice, 4 ) ;
double point = CurrencyUtil . div ( cartSkuVO . getPriceDetailDTO ( ) . getGoodsPrice ( ) , finalT otalPrice, 4 ) ;
//商品优惠金额
skuDiscountPrice = CurrencyUtil . mul ( d iscountPrice, point ) ;
skuDiscountPrice = CurrencyUtil . mul ( finalD iscountPrice, point ) ;
//累加已优惠金额
deducted = CurrencyUtil . add ( deducted , skuDiscountPrice ) ;
deducted . set ( CurrencyUtil . add ( deducted . get ( ) , skuDiscountPrice ) ) ;
}
// 如果是最后一个商品 则减去之前优惠的金额来进行计算
else {
skuDiscountPrice = CurrencyUtil . sub ( d iscountPrice, deducted ) ;
skuDiscountPrice = CurrencyUtil . sub ( finalD iscountPrice, deducted . get ( ) );
}
calculateCartSkuPromotionsPrice ( cartSkuVO , skuDiscountPrice , promotionTypeEnum , activityId ) ;
}
}
}) ;
}
calculateNotEnoughPromotionsPrice ( skuVOList , skuPromotionDetail , discountPrice , totalPrice , promotionTypeEnum , activityId ) ;
@@ -186,51 +187,100 @@ public class PromotionPriceUtil {
// 特殊情况处理,如参与多个促销活动,部分商品在其他促销计算后的金额不足以满足与当前参与的促销活动的优惠金额
// 但当前购物车内存在当前当前促销活动的其他商品且剩余金额也满足分摊不足商品的不足金额,则分摊到其他商品上
// 满足当前促销的总优惠金额
if ( skuPromotionDetail = = null | | skuPromotionDetail . isEmpty ( ) ) {
if ( skuPromotionDetail = = null | | skuPromotionDetail . size ( ) < 2 ) {
return ;
}
// clone skuPromotionDetail
Map < String , Double > skuPromotionDetailClone = MapUtil . sortByValue ( skuPromotionDetail , false ) ;
// 未满足优惠金额的商品
long matchPromotionsZeroCount =
skuVOList . stream ( ) . filter ( l - > l . getPriceDetailDTO ( ) . getFlowPrice ( ) = = 0 & & skuPromotionDetail . containsKey ( l . getGoodsSku ( ) . getId ( ) ) ) . count ( ) ;
long matchPromotionsCount = skuVOList . stream ( ) . filter ( l - > skuPromotionDetail . containsKey ( l . getGoodsSku ( ) . getId ( ) ) ) . count ( ) ;
skuVOList . stream ( ) . filter ( l - > l . getPriceDetailDTO ( ) . getFlowPrice ( ) = = 0 & & skuPromotionDetailClone . containsKey ( l . getGoodsSku ( ) . getId ( ) ) ) . count ( ) ;
// 参与当前促销活动的商品
long matchPromotionsCount = skuVOList . stream ( ) . filter ( l - > skuPromotionDetailClone . containsKey ( l . getGoodsSku ( ) . getId ( ) ) ) . count ( ) ;
if ( matchPromotionsZeroCount = = matchPromotionsCount ) {
return ;
}
// 获取剩余金额不足 优惠金额的商品
List < CartSkuVO > unEnoughSku = skuVOList . stream ( ) . filter ( k - > {
if ( skuPromotionDetail . containsKey ( k . getGoodsSku ( ) . getId ( ) ) & & skuPromotionDetail . size ( ) > = 2 ) {
//商品金额占比
double point = CurrencyUtil . div ( k . getPriceDetailDTO ( ) . getGoodsPrice ( ) , totalPrice , 4 ) ;
//商品优惠金额
Double skuDiscountPrice = CurrencyUtil . mul ( discountPrice , point ) ;
return k . getPriceDetailDTO ( ) . getCouponPrice ( ) > 0 & & skuDiscountPrice > k . getPriceDetailDTO ( ) . getCouponPrice ( ) ;
}
return false ;
} ) . collect ( Collectors . toList ( ) ) ;
if ( ! unEnoughSku . isEmpty ( ) ) {
if ( unEnoughSku . size ( ) = = skuVOList . size ( ) ) {
return ;
}
for ( Car tSkuVO cartSkuVO : skuVOList ) {
if ( unEnough Sku. isEmpty ( ) ) {
// 分配到其他商品的 优惠金额
AtomicReference < Double > balance = new AtomicReference < > ( 0D ) ;
StringBuilder lastSkuId = new StringBuilder ( ) ;
// 计数器
int count = 0 ;
// 检查是否有不满足优惠金额的商品
filterEnoughSku ( skuVOList , skuPromotionDetailClone , discountPrice , totalPrice , balance , lastSkuId , promotionTypeEnum , activityId ) ;
// 循环 优惠金额分摊,直到所有商品都满足优惠金额
while ( true ) {
// 如果还有剩余金额,则继续分摊
if ( balance . get ( ) > 0 ) {
skuPromotionDetailClone . remove ( las tSkuId . toString ( ) ) ;
double lastDiscountPrice = CurrencyUtil . sub ( discountPrice , skuPromotionDetail . get ( last SkuId . toString ( ) ) ) ;
double lastTotalPrice = CurrencyUtil . sub ( totalPrice , skuPromotionDetail . get ( lastSkuId . toString ( ) ) ) ;
filterEnoughSku ( skuVOList , skuPromotionDetailClone , lastDiscountPrice , lastTotalPrice , balance , lastSkuId , promotionTypeEnum , activityId ) ;
} else {
break ;
}
if ( skuPromotionDetail . containsKey ( cartSkuVO . getGoodsSku ( ) . getId ( ) ) & & unEnoughSku . stream ( ) . noneMatch ( k - > k . getGoodsSku ( ) . getId ( ) . equals ( cartSkuVO . getGoodsSku ( ) . getId ( ) ) ) ) {
count + + ;
// 防止死循环
if ( count > skuPromotionDetail . size ( ) ) {
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 ) {
AtomicInteger count = new AtomicInteger ( skuPromotionDetail . size ( ) ) ;
AtomicReference < Double > countPrice = new AtomicReference < > ( 0D ) ;
for ( String skuId : skuPromotionDetail . keySet ( ) ) {
skuVOList . forEach ( l - > {
if ( l . getGoodsSku ( ) . getId ( ) . equals ( skuId ) ) {
count . getAndDecrement ( ) ;
//商品金额占比
double point = CurrencyUtil . div ( cartSkuVO . getPriceDetailDTO ( ) . getGoodsPrice ( ) , totalPrice , 4 ) ;
double point = CurrencyUtil . div ( l . getPriceDetailDTO ( ) . getGoodsPrice ( ) , totalPrice , 4 ) ;
//商品优惠金额
Double skuDiscountPrice = CurrencyUtil . mul ( discountPrice , point ) ;
// 商品优惠金额 - 不足优惠金额 = 差额
Double sub = CurrencyUtil . sub ( skuDiscountPrice , unEnoughSku . get ( 0 ) . getPriceDetailDTO ( ) . getCouponPrice ( ) ) ;
// 分摊到其他商品: 其他商品原优惠金额 + 差额
calculateCartSkuPromotionsPrice ( cartSkuVO , sub , promotionTypeEnum , activityId ) ;
// 从不足商品列表中移除
unEnoughSku . remove ( 0 ) ;
}
}
Double skuDiscountPrice ;
if ( count . get ( ) > 0 ) {
//非最后一个商品,则按照比例计算
skuDiscountPrice = CurrencyUtil . mul ( discountPrice , point ) ;
} else {
return ;
// 如果是最后一个商品 则减去之前优惠的金额来进行计算
skuDiscountPrice = CurrencyUtil . sub ( discountPrice , countPrice . get ( ) ) ;
}
if ( balance . get ( ) > 0 ) {
// 分摊到其他商品: 其他商品原优惠金额 + 差额
calculateCartSkuPromotionsPrice ( l , balance . get ( ) , promotionTypeEnum , activityId ) ;
}
// 如果商品优惠金额大于商品金额,则取商品金额。差额分摊到其他商品
if ( skuDiscountPrice > l . getPriceDetailDTO ( ) . getGoodsPrice ( ) ) {
balance . set ( CurrencyUtil . sub ( skuDiscountPrice , l . getPriceDetailDTO ( ) . getGoodsPrice ( ) ) ) ;
lastSkuId . append ( skuId ) ;
skuDiscountPrice = l . getPriceDetailDTO ( ) . getGoodsPrice ( ) ;
} else {
balance . set ( 0D ) ;
}
countPrice . set ( CurrencyUtil . add ( countPrice . get ( ) , skuDiscountPrice ) ) ;
}
} ) ;
}
calculateNotEnoughPromotionsPrice ( skuVOList , skuPromotionDetail , discountPrice , totalPrice , promotionTypeEnum , activityId ) ;
}
/**