JAVA订单优惠券、促销、费用等按商品行金额占比分摊算法

例:订单总金额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));
    }
}

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值