例:订单总金额100,使用优惠券5元,需要把5元优惠券按照商品行金额占比分摊到商品行上去。
订单号:1000001,商品总金额:100元,优惠券:5元,实际支付金额:95元 | ||||
商品名称 | 单价 | 优惠券分摊算法 | 优惠券分摊金额 | |
苹果 | 60元 | 5*(60/100) | 3元 | |
香蕉 | 30元 | (5-3)*(30/(100-60)) | 1.5元 | |
橘子 | 10元 | (5-3-1.5)*(10/(100-60-30)) | 0.5元 |
计算公式为:(需要分摊金额-已分摊金额) * (当前商品行金额 / (商品行总金额-已使用商品行金额))=当前行分摊金额
代码实例如下:
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class AmountShareService {
/**
* 处理商品行需要分摊的优惠券、促销、营销费用等,需要按照每一行商品金额占比来分摊
* @param rowAmountList 分行商品金额集合
* @param shareAmount 需要分摊的金额
* @return List<BigDecimal> 返回每一行商品上的分摊占比金额
*/
public static List<BigDecimal> handleAmountShare(List<BigDecimal> rowAmountList, BigDecimal shareAmount) {
List<BigDecimal> amountShareList = new ArrayList<>();
if (CollectionUtils.isEmpty(rowAmountList)) {
log.error("参与分摊的商品集合不能为空,rowAmountList:{}", JSON.toJSONString(rowAmountList));
return amountShareList;
}
//商品集合金额合计
BigDecimal sum = rowAmountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
for (BigDecimal nowMoney : rowAmountList) {
BigDecimal lastMoney = BigDecimal.ZERO;
if (shareAmount.compareTo(BigDecimal.ZERO) == 0) {
log.error("参与分摊金额不能为0!shareAmount: {}", JSON.toJSONString(shareAmount));
break;
}
//分摊金额不能大于等于合计金额
if (shareAmount.compareTo(sum) > -1) {
log.error("参与分摊金额:{},不能大于商品总金额:{}", shareAmount, sum);
break;
}
//当前商品行金额,在未使用商品行总金额中的占比,四舍五入保留两位小数
BigDecimal oneMoneyScope = nowMoney.divide(sum, 2, BigDecimal.ROUND_UP);
//占比 * 还未分摊金额,四舍五入保留两位小数
lastMoney = oneMoneyScope.multiply(shareAmount).setScale(2, BigDecimal.ROUND_UP);
//计算出来的当前行分摊金额不能大于当前行商品金额
if (lastMoney.compareTo(nowMoney) == 1) {
log.error("当前商品行分摊金额:{},不能大于当前行商品金额:{}", lastMoney, nowMoney);
break;
}
amountShareList.add(lastMoney);
//剩余分摊金额=剩余分摊金额-当前商品行已分摊金额
shareAmount = shareAmount.subtract(lastMoney);
//未参与分摊商品行总金额=未参与分摊商品行总金额-当前商品行金额
sum = sum.subtract(nowMoney);
}
return amountShareList;
}
public static void main(String[] args) {
List<BigDecimal> list = new ArrayList<>();
list.add(new BigDecimal("60"));
list.add(new BigDecimal("30"));
list.add(new BigDecimal("10"));
List<BigDecimal> result = handleAmountShare(list, new BigDecimal("5"));
System.out.println(JSON.toJSONString(list));
System.out.println(JSON.toJSONString(result));
}
}