layout: post
title: 如何做一个对账系统
category: pay
tags: [pay]
在互联网行业中只要涉及到支付,必然就会有对账的需求,几乎所有互联网公司的业务中多多少少的都会涉及到支付,大一点的公司甚至都标配有了自己的第三方支付公司,因此对账具有普遍性。对账系统是支付体系中最重要的一环,也是保证交易、资金安全的最后一道防线。在大多数的互联网公司中,一般都会有独立的对账系统来处理,比如:电商平台、互联网金融、第三方支付公司等。
{:.center}
对账是支付系统中的一环,因此在对账前我们先了解一下相关的业务知识
业务知识什么是对账
传统的对账就是核对账目,是指在会计核算中,为保证账簿记录正确可靠,对账簿中的有关数据进行检查和核对的工作。在银行或者第三方支付中,对账其实是对一定周期内的交易进行双方确认的过程,一般都是在第二天银行或者第三方支付公司对前一日交易进行清分,生成对账单供平台商户下载,并将应结算款结算给平台商户。在往下一层,在互联网金融行业或者电商行业中,对账其实就是确认在固定周期内和支付提供方(银行和第反方支付)的交易、资金的正确性,保证双方的交易、资金一致正确。
广义的对账,所有跨应用的数据交互,理论上都应该进行对账。所以对账也可以分为信息流对账,资金流对账。信息流对账也一般用在自己内部系统的对账,比如支付系统的支付数据和业务系统的业务数据进行对账,保证资金交易和业务交易的一致性。资金流对账也就是支付系统和银行或者第三方支付系统之间的资金交易对账。
对账方式
- 单向对账:一般拿第三方支付机构或银行流水,与自己系统进行对账,防止出现掉单问题;
- 双向对账:两个应用间的流水进行双向核对,如订单与财务系统,既要保证财务系统支付成功的记录,订单系统也是成功的;也要确保订单系统记录成功的记录,财务系统也成功。
我们一般采用双向对账的方式进行对账
对账相关的问题
不同系统日切点不一致问题:滚动对账
差错处理:补账,补偿(退款)
相关概念
轧帐和平帐
每一笔交易,都要做到各参与者的记录能够吻合,没有偏差。对账系统的工作,是发现有差异的记录,即轧帐;然后通过人工或者自动的方式,解决这些差异,即平帐。
长款和漏单
在以平台交易为基准的情况下和银行对账,发现周期内的交易,平台有此订单而第三方支付中没有订单,成为平台长款。平台长款一般是由于用户在支付的时候跨天的情况,比如用户在23:58分创建了订单,在第二天的凌晨00:03分进行了支付。在以银行交易为基准的情况下对账,银行有此订单而平台无此订单,即为平台漏单。平台漏单很少见,一般直接转人工处理。
账户体系
在一般的支付体系中会分为登录账户和支付账户,支付账户指用户在支付系统中用于交易的资金所有者权益的凭证;登录账号指用户在系统中登录的凭证和个人信息。一个用户可以有多个登录账户,一个登录账户可以有多个支付账户,比如零钱账户、储值卡账户等。一般来说,支付账户不会在多个登录账户之间共用。对账的交易一般都是支付账户参与交易。
交易与账户
账户设置,一般是从交易开始的。 交易的实现必须有账户的支持,账户是交易的基本构成元素。 从支付系统的角度,交易中涉及到的资金流是资金从一个账户流向另一个账户。 发起交易的一方,被称之为交易主体,他可以是一个人,也可以是一个机构。
清算和结算
清算主要是指不同银行间的货币收付,可以认为是结算进行之前,发起行和接收行对支付指令的发送、接收、核对确认,其结果是全面交换结算工具和支付信息,并建立最终结算头寸。
结算是指将清算过程产生的待结算头寸分别在发起行、接收行进行相应的会计处理,完成资金转移,并通知收付双方的过程。当前,大多数银行结算业务的完成主要通过两类账户:一是银行间互相开立的代理账户,二是开立在央行、独立金融机构如银联、或者第三方支付机构的账户。
清算:计算各方应收应付钱款的时间与金额。结算:根据清算的结果在指定的时间对各方进行实际的资金转移操作
资金池
用户备付资金(如充值)统一放在企业的银行账户中,企业可以随意支配这些资金,即为资金池。与之对应的是第三方托管,用户备付资金是放在企业在第三方支付机构为用户开设的虚拟账户中,企业无法随意取出这些资金。现在互联网金融全面要求接入银行存管,就是银行会为每个用户创建一个资金账户来保护用户的资金,互联金融公司不能随意划拨这些资金账户中的金额。
对账系统对账设计
{:.center}
对账系统的设计阶段,将对账系统分为四个模块,每个模块的负责自己的职能。
- 文件获取模块:下载或者读取各渠道对账文件
- 文件解析模块:创建不同的解析模板,根据渠道和文件类型获取对应的解析模板进行解析
- 对账处理模块:对账的业务逻辑处理
- 差错处理模块:处理差错池中的订单
一般会设计一个定时任务,每天固定的时间点触发,定时驱动调度类分别调用四个模块来处理对账。也有的银行会主动的推送对账单,再通过http回调来触发对账流程。
对账算法
一、流程:
1、从上游渠道(银行、银联等金融机构)获取对账文件,程序逐行解析入库;
2、在程序处理中,以上游对账文件的表为基准,程序逐行读取并与我们系统的交易记录对比账务记录(有账务系统情况下,合理方案应该是于账务记录)对比,查找出差异记录;
3、以我们系统的交易记录对比账务记录为基准,程序逐行读取与上游对账文件对比,查找出差异记录。
二、缺陷:
1、对账过程中查询相关数据,如果数据量巨大,对数据库性能影响较大,而且对账逻辑扩展极为麻烦;
2、逐行比对算法效率较低,但算法上并无好的优化余地。如果采用数据库INTERSECT、MINUS对数据库压力也高;
3、在业务量大的情况下(例如有上百家上游渠道需要对,每一家都有几十万条交易记录),对账服务器及数据库服务器负荷较高。即便采用读写分离,对账时候使用读库,压力一样很大;
4、导入批量文件,逐行入库效率较为低下(每一次都需要建立网络连接、关闭连接)。
三、改进:
1、涉及网络传输的,尽量采用批量方式操作,减少网络消耗及时间消耗;
2、使用Redis等NOSQL数据库,降低数据库服务器的压力。同时在扩展上也容易,一台Redis服务器不够,可以无限制增加用于对账用的服务器;
3、使用Redis的set集合的sdiff功能,利用Redis sdiff算法的高性能,比对上游记录和我方记录的差异。
对账流程
{:.center}
1、下载对账单
大多数银行都要求接入方提供ftp服务,银行定时将对账单推送到接入方提供的ftp服务器上面;还有一部分银行会提供对账单的下载服务,通过ftp/http的都有,ftp方式居多;另外网银的对账单比较特殊,一般都需要结算登录网银的后台管理系统中,手动下载,结算下载完对账单后在导入到对账系统。
技术实现上可以做成工厂模式,不同的支付渠道有不同的下载类,如果是http接口将文件写入到对账单,如果是ftp服务器,将服务器中的对账单下载到本地带解析的目录中。主要涉及的代码ftp工具类、http(s)工具类,相关IO读写。
技术选型上,HTTP(S)用apache httpclient即可实现链接池和断点续传, FTP也可以使用Apache Commons Net API。 但不管是哪一个,都需要设置重试次数和链接超时间。重试次数和间隔的设置需要小心,重试太频繁,容易把服务器打死.;时间间隔太大,又会阻塞后续处理步骤。5~10分钟是一个合适的重试间隔区间。
2、创建批次
创建批次一方面是为了防止重复对账,另一方面需要在对账结束的时候将对账的结果信息存储到批次中。
3、解析文件
解析文件主要是将下载的对账文件解析成我们可以对账的数据类型并且入库。解析的文件不同渠道有不同的类型,因此也可以设计成不同的解析模板,使用工厂模式将不同格式的文件解析成可以对账的统一数据类型。解析的文件类型一般包括:json、text、cvs、excle等,另外部分银行会对账单做加密或者提供zip打包的格式,这里就需要额外开发zip工具类和加解密工具类进行处理。
对账文件中包含的主要信息有:商户订单号、交易流水号、交易时间、支付时间、付款方、交易金额、交易类型、交易状态这些字段。
4、对账处理
对账处理也是对账的核心逻辑,具体分为以下的几个步骤来实现:
- 查询平台所有交易成功的订单
- 查询平台所有的交易订单
- 查询平台缓存池中的数据
- 查询银行交易成功的订单
- 开始以平台的数据为准对账,平台长款记入缓冲池
- 开始以银行通道的数据为准对账
以平台订单为基准对账逻辑:以平台所有交易成功的订单为基准,遍历银行订单的所有数据,找出订单号相同的订单,对比订单的金额、手续费是否一致。如果一致跳过;如果不一致,平台订单进入差错池;如果在银行订单中没有找到此笔交易,订单进入缓存池,记录平台长款。同时统计对账相关金额和订单数。
以银行订单为基准对账逻辑:以银行的交易数据为基准,遍历所有平台的交易(包括未成功的订单),找出订单号相同但支付状态不一致的订单,在进行对比金额存入差错池。如果没有在平台的交易中找到此订单,再从缓存池中遍历查找,找到对应的平台订单验证金额是否一致,不一致进入差错池。如果在缓存池汇中依然没有找到对应的订单,直接进入差错池,记录平台漏单。同时统计对账相关金额和订单数。
5、对账统计
根据对账处理中,统计的相关信息包括:对账完成时间、对账是否成功、平账的金额和订单数、差错的金额和订单数、缓存池金额和订单数等。
6、差错处理
在一般系统中,差错处理分为两种,一种人工来处理,一种系统自动来处理。
主要有如下情况:
-
本地未支付,支付渠道已支付。这主要是本地未正确接收到渠道下发的异步通知导致。 一般处理是将本地状态修改为已支付,并做响应的后续处理,比如通知业务方等。
-
本地已支付,支付渠道已支付,但是金额不同,这个需要人工核查。
- 本地已支付,但是支付渠道中无记录;或者本地无记录,支付渠道有记录。在排除跨日因素外,这种情况非常少见,需要了解具体原因后做处理。
示例代码
网上的对账系统的开源代码不是很多,但有一家还不错:龙果支付。龙果支付中有比较完整的对账流程,代码中以微信、支付宝的对账单为例写了对账的流程,大家可以参考。
最后,你们公司的对账系统是怎么实现的,遇到了那些坑?欢迎和我讨论。
参考: