首发于 网易技术专栏
线上开票系统设计实践

线上开票系统设计实践

2020年9月29日,税务总局等十三部门联合发布《关于推进纳税缴费便利化改革优化税收营商环境若干措施的通知》,指出要稳步推进发票电子化改革,促进办税提速增效降负,2020年底前基本实现新办纳税人增值税专用发票电子化。

为了提升业务效率,更好的服务于企业客户,同时响应政策号召,网易云信2020年9月起支持线上开具电子发票,增值税普通电子发票将可以脱离线下人工开票流程,直接在线上完成自动开票。小小的一张发票背后,是一套集用户后台、业务后台、第三方平台于一体的线上开票系统。线上开票场景适用于各类行业,只要发生线上交易,无论toB 还是 toC,均会涉及。本文主要从财税知识科普、产品设计、技术设计多个维度分享线上增值税开票系统的实践,希望能对大家有所帮助。

推荐好友奖励升级,现在推荐好友使用网易云信,最低拿3000元京东卡奖励, 立即推荐>>

财务知识科普

在进行线上开票系统的设计之前,需要深入了解相关背景知识,这样才能理解整个业务流程。相关说明主要基于内部设计展开,仅供参考。

  1. 传统开票方式

一家新企业需要先到税局申请发票,再向税控服务公司购买税控设备。税控设备安装好后,再携带税盘(金税盘或税控盘)到主管税务机关初始发行,发行后到柜台领用发票。之后企业税务人员就可以安装开票软件,进行企业内部的线下开票了(纸质或电子)。

金税盘、税控盘:俗称白盘,黑盘,分属于两个不同的协税公司,金税盘属于航天信息,税控盘属于百旺。

发票信息

以电子普通发票为例,一张发票主要涉及以下几个重点信息,了解了这些信息对后续第三方平台的对接会有很大帮助。


购买方信息:

订单信息:

*商品名称*商品服务类型
若供应两种不同税率的应税项目,且合并开具发票的,其商品或劳务的名称、计量单位、数量、单价、金额,必须按不同税率分别填写。对供应的货物既有应税货物,又有免税货物的,供应的免税货物应单独开具普通发票,不得和应税货物合并开具增值税专用发票。

销售方信息:

销货清单:

当发票上的订单信息超过​货物或应税劳务、服务名称​一栏展示范围时,会生成用于记录完整订单信息的​销售货物或者提供应税劳务、服务清单​,发票​货物或应税劳务、服务名称​一栏内容为​(详见销货清单)​。

发票类型

常见术语

蓝票、红票:正常开具发票为“蓝票”,出现退货或开具的发票有错误,需要作废发票或开具“红票”(也叫负票)用以冲减当期开票方的销售收入(也叫红冲)。

如果是增值税专用发票,在同一个月开票退货且发票未认证的,可直接作废发票;跨月退票的,需要红冲,开具负(红字)发票,冲减当期销售;如已通过同认证的,需购货方税务局出具《开具红字发票通知单》,销货方凭此《通知单》才能开具红字(负数)发票。此流程一般需要线下处理。

产品设计

熟悉了基本知识,在正式进入线上开票系统的产品设计之前,需要进行第三方开票平台的选型。确定选型后结合第三方平台的接口,梳理业务流程及相关功能点。

第三方开票平台

中国电子发票产业链的核心环节包括税控设备商和第三方电子发票服务平台。税控设备商是国有控股的爱信诺、百旺双寡头格局。第三方电子发票服务平台主要分为三大阵营,包括百望股份、高灯科技为代表的新兴企业;由税控设备商、传统纸质发票印刷商租成的老牌发票服务商;以用友、金蝶为代表的老牌软件服务商。可以根据企业情况,选择第三方开票平台。

企业可通过第三方平台接口完成于自有系统对接,可选择自行同步发票,也可选择扫码开票。后者在线下门店开票中较为常见。

业务流程

根据业务特点进行需求分析,设计适合自己业务的开票流程。此过程建议与财税同学保持密切沟通,避免设计出来的开票流程不符合财税要求。

订单支付完成后,以电子发票线上开票及退票为例,主要业务流程(含状态流转)参考如下:

说明:

功能

线上开票系统主要涉及用户和业务后台,核心功能点参考下图:


说明:

其他业务场景

实际业务中,还会涉及一些特殊场景,如提前开票、退款退票等。

提前开票,即客户先开发票再进行支付。很多大企业内部报销审核严格,需要销售方先开具发票,然后根据发票报销打款。

退款退票,即客户购买后,由于各种原因进行了退款操作,包含全部退款或部分退款。如果已经开具发票,则需要同步完成退票流程。针对全部退款的情况,只需要走正常退票流程即可。但针对部分退款的情况,原来已经开具发票的需要整体退票之后,再开具剩余未退款金额的发票。

这些特殊场景也需要完成线上化,通过系统闭环所有开票流程,其优先级可根据自身业务需求制定。

技术设计

对于技术人员来说,在设计任何一个系统时首先都会遇到以下个问题:

  1. 系统面向的使用者是谁?
  2. 租户隔离要隔离什么数据?
  3. 系统的外部依赖有哪些,逻辑架构应该怎样设计?

解决了上述问题后,就轮到我们的开票系统独有的内部业务问题了:

  1. 发票上的各项金额分别代表什么含义,如何计算?
  2. 多订单合并开票或大额订单开票时,发票应该如何拆分?

理顺了内部业务逻辑,最后就该思考如何对外提供服务,并尽量提升服务体验,也就是要解决以下问题:

  1. 接口时序是怎样的,哪些步骤应该异步化?

系统使用者

通常对于一个集团公司来说,业务结构是呈现金字塔形状的,即集团公司下有不同的子公司,子公司下有不同的产品线,但也偶尔有一些产品线是由不同的子公司甚至外部公司组成。

因此我们应该把终端产品线作为租户。

租户隔离

明确了系统使用者,接下来就需要考虑租户应该隔离哪些数据。

目前市面上的开票供应商提供的都是销方账户隔离,有两点限制:

  1. 同一销方账户内订单号必须唯一;
  2. 销方账户每张发票的不含税金额有上限;

而在实际的线下开票中,我们还会碰到以下场景:

  1. 相同的税收分类编码在不同产品线中有不同的商品名称;
  2. 相同的商品在不同产品线或者同一产品线中有不同的商品规格、商品单价;

因此,我们的租户对应的数据映射关系如下:

  1. 租户和销方账户是1对1的关系;
  2. 租户和单张发票不含税金额上限是1对1的关系;
  3. 租户和订单编号是1对N的关系;
  4. 租户和允许开票的商品SKU(即允许的名称/税收分类编码/规格/单价组合)是1对N的关系;

逻辑架构

发票的生成需要以下必要元素:

  1. 发票主体;
  2. 订单信息;
  3. 商品信息;
  4. 实际开票能力;

按微服务来说,就是我们要依赖4个外部服务:

  1. 用户中心负责提供经过实名认证的发票主体信息;
  2. 订单中心负责提供订单编号以及包含的商品SKU购买数量数据;
  3. 商品中心负责提供商品SKU的名称、税收分类编码、商品规格、含税单价数据;
  4. 开票供应商负责提供实际的电子开票能力;

于是,我们的逻辑架构图应该如下图:

金额计算

发票里的各项属性的含义可以参考上文,通过各项金额的定义,我们可以得到以下计算公式:

发票拆分

各个产品线在申请开票时都是希望订单和发票会一一对应,但实际情况是,受限于企业资质,销方开出的每张发票是有不含税金额上限的,超出上限就不能开具发票。

底层的开票供应商通常都具有自动拆票功能,即一笔订单的不含税金额超过上限,就会自动拆分成多张发票。但开票供应商通常会建议我们自己封装一套拆票逻辑,这是因为供应商的拆票是面向单笔订单的,如果业务上是多笔订单合并开票,供应商拆票后就会出现某几张发票的金额远小于上限,造成发票份数的浪费。

税务每月能从税务局领取的发票份数是有限的。

蓝票拆分

首先,我们把蓝票开票流程中涉及的对象实体进行抽象:

  1. 把产品线提交的一次蓝票开票请求抽象为一个主流程,一个蓝票主流程包含一笔或多笔订单;
  2. 把拆分后的单张蓝票抽象为一个子流程,所以一个蓝票主流程有一个到多个蓝票子流程;
  3. 每张蓝票有一行或多行发票明细项目,所以一个蓝票子流程有一条到多条发票明细项目;
  4. 单张发票的不含税金额上限作为拆分时的不含税金额阈值;

然后我们来进行拆分规则的制定;

  1. 商品的不含税单价不得大于不含税金额阈值,如果有超过阈值的会被拆分成一组到2组商品:一组商品的单价等于不含税金额阈值,数量为​原商品不含税金额/拆分不含税金额阈值​;如果还有剩余不含税金额,则拆分成一个单价为剩余不含税金额,数量为1的商品,订单编号、商品名称、税收分类编码不变;
    1. 例如​订单1/商品A/税收分类编码TC1/数量2件/单价18万​会被拆分成​订单1/商品A/税收分类编码TC1/数量3件/单价10万​和​订单1/商品A/税收分类编码TC1/数量1件/单价6万​;
    2. 例如​订单1/商品A/税收分类编码TC1/数量2件/单价15万​会被拆分成​订单1/商品A/税收分类编码TC1/数量3件/单价10万​;
  2. 将(订单+商品名称+税收分类编码+不含税单价)作为拆分维度的最小单位,商品数量最小为1,如果当前发票含税金额的剩余额度小于商品单价则自动开具下一张发票,如果当前发票含税金额的剩余额度大于商品单价,则当前发票最多可放置当前商品的数量=​min((剩余额度/商品单价), 商品数量)​,如果全部商品数量都可以放下则切换到下一个商品,否则将剩余商品数量放到下一张发票里;
上述的规则说明中是以技术服务类这种没有规格的商品作为说明的,如果是实体类商品则需把商品规格也加入到拆分维度中。

详细拆分步骤见流程图:

拆分示例:

假设销方单张发票的不含税金额上限为10万,产品线提交的原始开票订单以及商品列表如下:

我们期望不含税单价溢出商品拆分后,单价溢出的​商品8​被拆分成两组商品

我们期望最终的拆分结果为7张发票

红票拆分

红票是根据对应蓝票来开具的,红票和蓝票有以下映射关系:

  1. 红票发票明细和蓝票发票明细一一对应,除了商品数量、不含税金额、税额、含税金额是对应蓝票发票明细的负数外,其他各项属性都是相同的;
  2. 红票的发票备注中需要以​"对应正数发票代码:xxxxxxxxxxxx号码:xxxxxxxx"​的形式填充上对应蓝票的发票代码和发票号码;

所以只需要根据蓝票的拆分结果就能完成红票拆分。参照蓝票拆分中的实体定义,对红票开票流程中涉及的对象实体进行抽象:

  1. 把产品线提交的一次红票开票请求抽象为一个主流程,一个红票主流程必须关联且只关联一个蓝票主流程;
  2. 把拆分后的单张红票抽象为一个子流程,一个红票主流程有一个到多个红票子流程,每个红票子流程和蓝票主流程关联的蓝票子流程一一对应,红票子流程的发票备注以​"对应正数发票代码:xxxxxxxxxxxx号码:xxxxxxxx"​的形式填充上对应蓝票子流程的发票代码和发票号码;
  3. 每张红票有一行或多行发票明细项目,每个红票发票明细和蓝票子流程关联的蓝票发票明细一一对应,红票发票明细的商品数量、不含税金额、税额、含税金额是对应蓝票发票明细的负数,其他各项属性相同;

接口时序和异步化

逻辑架构中的订单中心、用户中心、商品中心都是提供只读服务,因此可以采用同步调用快速失败的方式进行熔断。但是对于大额订单开票来说,蓝票拆分逻辑较为复杂耗时,且和开票供应商交互生成发票的过程不可控,因此我们可以将这两个步骤异步化,并且在异步化流程中加入错误重试机制。

开具蓝票的接口时序:

开具红票的接口时序:

异步流程:

在异步流程中,我们需要实现以下两个功能:

  1. 蓝票/红票拆分成蓝票/红票子流程,拆分出的子流程有4种状态:
    1. 供应商待申请 - 尚未提交给开票供应商;
    2. 供应商开票成功;
    3. 供应商开票失败;
    4. 供应商开票中 - 既不是开票成功,也不是开票失败的其他状态都属于开票中;
  2. 蓝票/红票子流程提交给开票供应商生成电子发票,包括开票结果的查询以及开票异常的重试;

详细步骤见流程图:


以上就是网易云信线上开票系统设计的实践,目前该功能已经上线,欢迎大家体验!

想要探讨更多技术干货,欢迎在微信公众号后台留言。

代做工资流水公司汕头签证工资流水费用肇庆入职银行流水样本镇江银行流水修改代办沈阳开企业对公流水潮州入职流水查询吉林背调工资流水代办南通贷款银行流水公司海口代办车贷银行流水湛江制作房贷收入证明青岛工资流水账单代做泰州转账流水代开菏泽做企业对公流水台州流水单查询泰州日常消费流水公司桂林开房贷收入证明泉州房贷银行流水北京代办个人银行流水唐山企业流水打印代做东莞薪资流水打印许昌制作入职工资流水长沙查房贷银行流水杭州代做入职银行流水湘潭企业对公流水办理淮安查询背调银行流水武汉办企业对公流水赣州薪资流水办理汕头自存流水费用唐山公司银行流水费用宁波打入职工资流水厦门车贷银行流水 模板香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化