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

文章目录

  • 案例数据
  • 实现思路
    • 1、计算出平均金额
    • 2、计算每个商品的金额
  • 实现方案
    • 1、订单 order 实体
    • 2、订单明细 orderDetail 实体
    • 3、实现类
    • 4、测试启动
    • 5、实现结果

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

案例数据

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

订单总金额【含税】 payAmount订单税额 rateAmount
1003

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

商品信息个数
总数量8
商品14
商品23
商品31

实现思路

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<>();// 商品1OrderDetail detailOne = new OrderDetail();detailOne.setDetailId("1111");detailOne.setOrderNo("12345678");detailOne.setSkuNum(4L);detailOne.setSkuName("商品1");detailList.add(detailOne);// 商品2OrderDetail detailTwo = new OrderDetail();detailTwo.setDetailId("2222");detailTwo.setOrderNo("12345678");detailTwo.setSkuNum(3L);detailTwo.setSkuName("商品2");detailList.add(detailTwo);// 商品3OrderDetail 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}]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/870216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 自定义Edittext 和TextView 提示文字和填入内容不同的粗细组件

近期项目中又EditText 以及TextView 这两个组件需要用到提示文字 以及 填入文字要保持不同的粗细程度,所以记录一下 首先 是EditText 组件的自定义 BLEditText 继承的这个组件是一个三方的组件,可以在很大程度上减少drawable的编写,有兴趣的可以去相关的Git去看一下 点击查看,…

[leetcode]maximum-binary-tree 最大二叉树

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {return construct(nums, 0, nums.size() - 1);}TreeNode* construct(const vector<int>& nums, int left, int right) {if …

人工智能算法工程师(中级)课程4-sklearn机器学习之回归问题与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程4-sklearn机器学习之回归问题与代码详解。回归分析是统计学和机器学习中的一种重要方法&#xff0c;用于研究因变量和自变量之间的关系。在机器学习中&#xff0c;回归算法被广泛应用于…

软件开发23种设计模式

一、设计模式分类 软件开发的23种模式&#xff0c;主要分类有创建型模式&#xff0c;结构型模式&#xff0c;行为型模式三种&#xff0c;相关分类如下&#xff1a; 设计模式是一种面向对象编程的思想&#xff0c;它是由Gamma等人在《设计模式&#xff1a;可复用面向对象软件的…

中新青年领导人交流营走进李良济,零距离感受中医药文化的魅力

7月8日晚&#xff0c;2024中新青年领导人交流营在苏州正式启动。该交流营主题为“青年创业和可持续发展”&#xff0c;由中华全国青年联合会、新加坡全国青年理事会主办&#xff0c;江苏省、北京市青年联合会与苏州市人民政府承办&#xff0c;苏州市青年联合会与苏州工业园区管…

k8s核心操作_Ingress统一网关入口_域名访问配置_ingress域名转发规则配置_根据域名访问不同服务---分布式云原生部署架构搭建026

上一节我们已经把 ingress 安装好了可以看到 kubectl get svc -A 可以看到 出现了ingress-nginx 的service,在ingre-nginx这个命名空间中,有两个,一个是 ingress-nginx-controller 开了两个一个是对应http,一个对应https 一个是 ingress-nginx-controller-admission 对…

银河麒麟(Kylin)KYSEC使用

1.推荐使用方法 *.临时禁用指令: setstatus disable--禁用 注&#xff1a;执行reboot后系统会自动启动 2.选用指令&#xff1a; *.永久禁用指令&#xff1a; setstatus disable -p *.重启后,KYSEC还是处理关闭关状态。 *.使用如下指令启用&#xff1a;setstatus enable …

Linux(一)线程——何为线程???Linux线程控制

文章目录 什么是线程&#xff1f;&#xff1f;&#xff1f;线程和进程的区别和联系Linux线程控制POSIX线程库创建线程线程等待线程终止线程分离 什么是线程&#xff1f;&#xff1f;&#xff1f; 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的…

python用selenium网页模拟时无法定位元素解决方法1

进行网页模拟时&#xff0c;有时我们明明可以复制出元素的xpath&#xff0c;但是用selenium的xpath click无法点击到元素。这种情况有几种原因&#xff0c;本文写其中一种——iframe 比如下图网址&#xff0c;第二行出现iframe&#xff0c;则往下的行内元素都会定位不到&#…

2024最新最全【Java】全栈,零基础入门到精通

Java基础 本文章是作者的学习笔记&#xff0c;帮助初学者快速入门&#xff0c;内容讲的不是很细&#xff0c;适合初学者&#xff0c;不定时更新。 目录 Java基础数据类型1.基本类型(primitive type)1-1 整数类型1-2 浮点类型1-3 字符类型1-4 boolean类型 2.引用数据类型3.类型…

java:将集合中的数据放到文件中

代码实现目标&#xff1a; 将集合中的数据写道文件中通过字符缓冲输出流实现 代码展示 public static void main(String[] args) throws IOException {//创建ArrayList集合ArrayList<Student> array new ArrayList<>();//创建学生对象Student s1 new Student(&…

面试总结-基础js

一、变量提升&#xff08;函数里面先形参赋值&#xff0c;再变量提升&#xff0c;最后执行代码&#xff09; 1、概念&#xff1a;当浏览器开辟出供代码执行的栈内存后&#xff0c;代码并没有自上而下立即执行&#xff0c;而是继续做了一些事情&#xff0c;把当前作用域所有带v…

【前端】有时候你可能需要SSE而不是WebSocket

深度解析&#xff1a;轮询、SSE 和 WebSocket 在构建实时应用时&#xff0c;开发者面临多种选择&#xff0c;其中最常见的是轮询&#xff08;Polling&#xff09;、服务器推送事件&#xff08;Server-Sent Events&#xff0c;SSE&#xff09;和 WebSocket。本文将深入解析这三…

kind kubernetes(k8s虚拟环境)使用本地docker的镜像

kubernetes中&#xff0c;虽然下载镜像使用docker&#xff0c;但是存储在docker image里的镜像是不能被k8s直接使用的&#xff0c;但是kind不同&#xff0c;可以使用下面的方法&#xff0c;让kind kubernetes环境使用docker image里的镜像。 kind – Quick Start 例如&#x…

M12电源分配器:高效率与可靠性的工业解决方案

关键词&#xff1a;M12电源分配器、M12电源接线盒、M12电源分线盒 摘要 M12电源分配器是工业环境中实现高效与可靠电源管理的现代化解决方案。该设备采用坚固的金属外壳和封闭式设计&#xff0c;保证了在严苛工业条件下的稳定运行&#xff0c;达到IP67等级的防护性能&#xf…

FastAPI 学习之路(三十八)Static Files

如果使用前后台不分离的开发方式&#xff0c;那么模版文件中使用的静态文件&#xff0c;比如css/js等文件的目录需要在后台进行配置&#xff0c;以便模版渲染是能够正确读取到这些静态文件的。那么我们如何处理呢&#xff1f; 首先安装依赖 pip install aiofiles 我们看下如何…

蓝队必备技能--yara-让自己编写AVVT

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

51单片机STC89C52RC——16.1 五线四相步进电机

目录 目的/效果 一&#xff0c;STC单片机模块 二&#xff0c;步进电机 2.2 什么是步进电机&#xff1f; 2.2.1 步进电机驱动板 静态参数 动态参数 2.2.2 五线四相 单相激励步进 双相激励步进 混合激励驱动 2.3 细分驱动 2.4 通过数字信号控制旋转位置和转速。 2…

基于Java+Vue的场馆预约系统源码体育馆羽毛球馆篮球馆预约

市场前景 市场需求持续增长&#xff1a;近年来&#xff0c;随着人们生活水平的提高和休闲娱乐需求的多样化&#xff0c;各类场馆&#xff08;如体育馆、图书馆、博物馆、剧院等&#xff09;的访问量不断增加。然而&#xff0c;传统的预约方式往往存在效率低下、信息不透明等问…

AI算力中心研究分析

中国 AI 算力中心研究报告 算力产业稳健发展&#xff0c;算力创新能力持续增强&#xff0c;推动我国数字经济量质齐升。 2022 年我国算力规模稳步扩张&#xff0c;算力发展为拉动我国 GDP 增长做出突出贡献&#xff0c;在 2016-2022 年期间&#xff0c;我国算力规模平均每年增…