电商之订单价税拆分实现方案


在做电商项目的时候,会遇到要对订单明细进行纳税金额拆分,即将税额拆分到每个商品上,明确商品的税额,本文记录实现方案,方便备查。

案例数据

本案例模拟的相关数据
订单金额100元【10000分】税率5%,即税额5元【500分】

订单总金额【含税】 payAmount 订单税额 rateAmount
100 3

商品数量,总数量为8个,包含3个商品,下表是各商品的数量。

商品信息 个数
总数量 8
商品1 4
商品2 3
商品3 1

实现思路

1、计算出平均金额

即商品平均金额,税额平均金额,注意要向下取整,保证最后的金额不为负数。

类型 金额
商品平均金额【订单金额/商品数量】 10000/8=1250
税额平均金额【税额/商品数量】 500/8=62

2、计算每个商品的金额

分为两种计算方式,
前n-1个商品计算方式:即计算每个商品的金额,税额,不含税金额,公式为 上一步计算的各项平均数,乘于商品数量,如商品1如下表所示。

类型 金额
商品1金额【平均订单金额*商品数量】 1250*4=5000
商品1税额【税额平均金额*商品数量】 62*4=248

第n个商品计算方式:总的金额 减去 前n-1个商品累计的金额。

实现方案

1、订单 order 实体

order 实体,订单级别的字段,包含商品总数,支付总金额等

import java.io.Serializable;
import java.util.List;
@Data
public class Order implements Serializable{

	/**
	 * 序列号
	 */
	private static final long serialVersionUID = 6652550451095312169L;

	/**
	 * 订单号
	 */
	private String orderNo;
	
	/**
	 * 支付金额
	 */
	private Long payAmount;
	
	/**
	 * 税额
	 */
	private Long rateAmount;

	/**
	 * 商品数量
	 */
	private Long skuNum;
	
	/**
	 * 非含税金额
	 */
	private Long taxtedAmount;
	
	/**
	 * 明细集合
	 */
	private List<OrderDetail> orderDetailList;
}

2、订单明细 orderDetail 实体

orderDetail 实体,订单明细级别的字段,包含商品明细,商品名称,商品数量等

import java.io.Serializable;
@Data
public class OrderDetail implements Serializable{

	/**
	 * 序列号
	 */
	private static final long serialVersionUID = 7157867993602926767L;
	
	/**
	 * 订单号
	 */
	private String orderNo;
	
	/**
	 * 明细ID
	 */
	private String detailId;
	
	/**
	 * 商品名称
	 */
	private String skuName;
	
	/**
	 * 支付金额
	 */
	private Long payAmount;
	
	/**
	 * 税额
	 */
	private Long rateAmount;
	
	/**
	 * 非含税金额
	 */
	private Long taxtedAmount;

	/**
	 * 商品数量
	 */
	private Long skuNum;
}

3、实现类

定义主体方法,实现税额和不含税金额的拆分

 static List<OrderDetail> SplitOrderDetailTest(Order order) {
        System.out.println("进入拆分SplitOrderDetail方法,入参order为:" + order);
        List<OrderDetail> detailList = order.getOrderDetailList();
        // 商品金额
        long amount = order.getPayAmount();
        // 税额
        long rateAmount = order.getRateAmount();
        // 明细数量
        long skuNum = order.getSkuNum();
        // 平均商品成本金额,向下取整
        long aveAmount = (long) Math.floor(amount / skuNum);
        // 平均商品税额金额,向下取整
        long aveRateAmount = (long) Math.floor(rateAmount / skuNum);
        // 平均商品不含税金额【平均商品金额-平均商品税额金额】
        long aveNoRateAmount = aveAmount - aveRateAmount;
        System.out
                .println("计算完毕的rateAmount为:" + rateAmount + ",amount为:" + amount + ",skuNum为:" + skuNum + ",aveAmount为"
                        + aveAmount + ",aveRateAmount为:" + aveRateAmount + ",aveNoRateAmount为:" + aveNoRateAmount);
        // 累计拆分完 金额
        long detailSumAmount = 0l;
        // 累计拆分完 税额
        long rateSumAmount = 0l;
        // 累计拆分完 不含税金额
        long taxedSumAmount = 0l;
        System.out.println("当前detailList.size()为:" + detailList.size());
        for (int i=0; i < detailList.size()-1;i++) {
            System.out.println("当前遍历的detail为:" + JSON.toJSONString(detailList.get(i)));
            OrderDetail orderFinallyDetail = new OrderDetail();
            BeanUtils.copyProperties(detailList.get(i),orderFinallyDetail);

            if ( i < detailList.size()-1) {
                System.out.println("进入循环内:" + JSON.toJSONString(i));
                // 拆分完 金额【平均金额*商品数量】
                long detailAmount = aveAmount * detailList.get(i).getSkuNum();
                detailSumAmount = detailSumAmount + detailAmount;
                System.out.println("计算拆分完的金额detailAmount为:" + detailAmount + ",detailSumAmount为" + detailSumAmount);

                // 拆分完 税额【平均税额*商品数量】
                long rateDetailAmount = aveRateAmount * detailList.get(i).getSkuNum();
                rateSumAmount = rateSumAmount + rateDetailAmount;
                System.out.println("计算税额的rateDetailAmount为:" + rateDetailAmount + ",rateSumAmount为" + rateSumAmount);
                orderFinallyDetail.setRateAmount(rateDetailAmount);

                // 不含税金额【本成本拆分完金额 - 本成本拆分完税额】
                long taxedAmount = detailAmount - rateDetailAmount;
                taxedSumAmount = taxedSumAmount + taxedAmount;
                System.out.println("计算不含税税额的taxedAmount为:" + taxedAmount + ",taxedSumAmount为" + taxedSumAmount);
                orderFinallyDetail.setTaxtedAmount(taxedAmount);
            }
            // list末位采用倒挤方式取值
            else {

                // 末位税额【总税额-累计扣除的税额】
                long taxAmount = rateAmount - rateSumAmount;
                System.out.println("计算末位倒挤税额的taxAmount为:" + taxAmount);
                orderFinallyDetail.setRateAmount(taxAmount);

                // 末位不含税金额【(总金额-税额)-累计扣除的不含税金额】
                long taxedAmount = (amount - rateAmount) - taxedSumAmount;
                System.out.println("计算末位倒挤不含税税额的taxedAmount为:" + taxedAmount);
                orderFinallyDetail.setTaxtedAmount(taxedAmount);

            }
            System.out.println("保存的orderFinallyDetail的信息为:" + JSON.toJSONString(orderFinallyDetail));
            detailList.add(orderFinallyDetail);
        }
        return detailList;
    }

4、测试启动

模拟数据,调用方法

public static void main(String[] args) {
        Order order = new Order();
        order.setOrderNo("12345678");
        order.setSkuNum(8L);
        order.setPayAmount(10000L);
        order.setRateAmount(500L);
        List<OrderDetail> detailList = new ArrayList<>();
        // 商品1
        OrderDetail detailOne = new OrderDetail();
        detailOne.setDetailId("1111");
        detailOne.setOrderNo("12345678");
        detailOne.setSkuNum(4L);
        detailOne.setSkuName("商品1");
        detailList.add(detailOne);
        // 商品2
        OrderDetail detailTwo = new OrderDetail();
        detailTwo.setDetailId("2222");
        detailTwo.setOrderNo("12345678");
        detailTwo.setSkuNum(3L);
        detailTwo.setSkuName("商品2");
        detailList.add(detailTwo);
        // 商品3
        OrderDetail detailThree = new OrderDetail();
        detailThree.setDetailId("3333");
        detailThree.setOrderNo("12345678");
        detailThree.setSkuNum(1L);
        detailThree.setSkuName("商品3");
        detailList.add(detailThree);
        System.out.println("构造的detailList的信息为:" + JSON.toJSONString(detailList));
        order.setOrderDetailList(detailList);
        List<OrderDetail> detailFinallyList = SplitOrderDetailTest(order);
        System.out.println("拆分完的detailFinallyList明细信息为:" + JSON.toJSONString(detailFinallyList));
    }

5、实现结果

在这里插入图片描述
拆分结果如下所示。

{"detailId":"1111","orderNo":"12345678","rateAmount":248,"skuName":"商品1","skuNum":4,"taxtedAmount":4752},
{"detailId":"2222","orderNo":"12345678","rateAmount":186,"skuName":"商品2","skuNum":3,"taxtedAmount":3564},
{"detailId":"3333","orderNo":"12345678","rateAmount":66,"skuName":"商品3","skuNum":1,"taxtedAmount":1184}]

相关推荐

  1. 小于开放平台-订单线下发货

    2024-07-11 13:22:02       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 13:22:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 13:22:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 13:22:02       58 阅读
  4. Python语言-面向对象

    2024-07-11 13:22:02       69 阅读

热门阅读

  1. 什么是CNN,它和传统机器学习有什么区别

    2024-07-11 13:22:02       20 阅读
  2. 使用 Vue 3 实现打字机效果

    2024-07-11 13:22:02       23 阅读
  3. 设计模式-单例模式

    2024-07-11 13:22:02       22 阅读
  4. 达梦数据库系列—23. DSC集群搭建

    2024-07-11 13:22:02       18 阅读
  5. RabbitMQ 迁移

    2024-07-11 13:22:02       21 阅读
  6. 【编程范式】理解响应式编程(reactive programming)

    2024-07-11 13:22:02       26 阅读
  7. Python 循环语句

    2024-07-11 13:22:02       21 阅读