优惠金额分配算法

import com.alibaba.fastjson.JSON;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 订单优惠均摊算法
 * 由于小数精度问题导致金额分配不完全
 * 订单总金额为				a
 * 订单明细金额为			b1,b2,b3....
 * a=b1+b2+...
 * 订单使用总优惠券金额为		c
 * 订单明细使用优惠券金额为	d1,d2,d3...
 * c=d1+d2...
 * <p>
 * 正常算法为
 * 明细金额占比为 			b1/a
 * 优惠券分摊金额为			d1=a*(b1/a)
 * d1=(1/3)无限循环的小数导致订单明细优惠金额与优惠金额有出入
 * <p>
 * 解决思路
 * d1=a*(b1/a)
 * d1 末位小数0舍1进
 * 例如	0.11 ->0.12
 * 0.10->0.10
 * d2=(c-d1)*(b2/(a-b1))
 * d2 末位小数0舍1进
 * 依次类推...
 *
 */
public class DiscountEqualizationUtil {

    /**
     * 优惠金额分配算法
     *
     * @param map         明细金额集合
     * @param couponMoney 优惠金额
     */
    public static Map<Long, BigDecimal> algorithm(Map<Long, BigDecimal> map, BigDecimal couponMoney) {
        Map<Long, BigDecimal> discountMap = new HashMap<>();

        //明细总和
        BigDecimal sum = BigDecimal.ZERO;
        for (Long key : map.keySet()) {
            sum = sum.add(map.get(key));
        }
        for (Long key : map.keySet()) {
            BigDecimal oneMoney = map.get(key);
            //单个明细分配的优惠金额
            BigDecimal lastMoney = BigDecimal.ZERO;
            if (couponMoney.compareTo(BigDecimal.ZERO) == 0) {
                System.out.println(lastMoney);
                discountMap.put(key, lastMoney);
                continue;
            }
            //优惠券金额大于等于合计金额
            if (couponMoney.compareTo(sum) > -1) {
                lastMoney = oneMoney;
                System.out.println(lastMoney);
                discountMap.put(key, lastMoney);
                continue;
            }
            //舍0进1
            //单个明细金额占比
            BigDecimal oneMoneyScope = oneMoney.divide(sum, 2, BigDecimal.ROUND_UP);
            //分配优惠券金额按比例 优惠金额末位舍0进1
            lastMoney = oneMoneyScope.multiply(couponMoney).setScale(2, BigDecimal.ROUND_UP);
            //如果分配比例大于金额 则等于金额
            if (lastMoney.compareTo(oneMoney) == 1) {
                lastMoney = oneMoney;
            }
            //优惠金额去除本次优惠金额
            couponMoney = couponMoney.subtract(lastMoney);
            //总金额减去本次商品金额
            sum = sum.subtract(oneMoney);

            System.out.println(lastMoney);
            discountMap.put(key, lastMoney);
        }
        System.out.println("===>" + JSON.toJSON(map));
        System.out.println("===>" + JSON.toJSON(discountMap));
        return discountMap;
    }

    public static void main(String[] args) {
        Map<Long, BigDecimal> map = new HashMap<>();
        map.put(1L, new BigDecimal("1"));
        map.put(2L, new BigDecimal("1"));
        map.put(3L, new BigDecimal("1"));
        BigDecimal couponMoney = new BigDecimal("1");
        DiscountEqualizationUtil.algorithm(map, couponMoney);
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值