系统里的资金交易如何与银行通道对账?我们这样设计

对账模型

以系统里的出金交易为例, 与银行对账不外乎做两件事:①T+1日拉取T日的银行账单,保存银行账单交易流水;②银行账单交易流水与本系统里的通道交易流水比对,记录并处理差异。

  {对账模型}
  我方通道交易流水    
  ↑↓    
  ↑↓
对账结果
差异账
  ↑↓    
拉取通道对账单
通道对账单    

【FAQ】

【Q】依据支付时间还是支付完成时间对账?

【A】按支付交易完成时间做对账。

【Q】银行单边在怎么产生的?

【A】case1:银行不返回交易完成时间。这种情况下,在日切临界点,我们0:00前查询通道,0:00后收到通道响应,我们按我们服务器时间更新交易完成时间。这就出现我司与通道侧支付完成时间不一致的情况。case2:再一种银行单边由不靠谱程序产生。我司调用通道侧时使用了事务。结果因调用超时通道侧落单,我司没落单,从而出现通道侧单边。

统一数据词典

T日:T日指交易日。银行系统在T+1日生成T日交易的账单,因此,对账发生在T+1日

账单/对账单:bill
银行账单/银行对账单:bank bill batch

对账:bill check
对账批次:bill check batch

明细:detail

差异:diff

定时任务:job。定时任务命名以-Job结尾,如对账Job命名为BankBillCheckJob

所涉及到的系统现有的词汇包括↓

通道/银行:bank

交易:trans

金额:amount,以“分”为单位存储

交易笔数/交易量:qty

数据表设计

 数据表表名comment主要字段
银行账单银行账单批次表bank_bill_batch银行账单表,每银行每天一条记录

batchNo-账单批次号(系统生成,PK)

bankId-系统里记录的银行通道编号

bankBatchNo-varchar-银行侧对账单批次号/对账文件名(没有则为空)

trans_date-int-交易日期/yyyyMMdd

— total_amount-总金额

total_qty-总笔数

createTIme-记录创建时间,即账单的首次拉取时间

updateTime-最后更新时间

 

银行账单交易流水bank_bill_detail银行账单交易明细

id-PK

batchNo-账单批次号

bankId-系统里记录的银行通道编号

transOrderNo-系统请求银行的交易流水号(发生银行单边时,此字段为空)

bankOrderNo-银行侧交易单号

transState-银行侧交易状态(程序里转换为系统里的交易状态)

transAmount-银行侧交易金额,以分为单位存储

payeeAccount-银行侧收款方账号(银行卡号)

transTime-银行侧交易完成时间

createTIme-记录创建时间

银行对账银行对账结果批次表bank_bill_check_batch与bank_bill_batch一对一

batchNo-批次号(PK,来自bank_bill_batch)

bankId-系统里记录的银行通道编号

checkState-对账处理状态 -(I-初始待对账/P-系统对账中/D-差异待处理/S-对账完成)

check_date-对账时间

trans_date-交易日期(针对哪天的交易做的对账)

 

银行对账结果明细表bank_bill_check_detail银行账单与系统交易对账结果

id-PK

transOrderNo-系统请求银行的交易流水号

bankOrderNo-银行侧交易单号

batchNo-批次号(来自bank_bill_batch)

bankId-银行编号

双方记录的交易状态、收款人账号、金额、交易完成时间

checkState-对账处理状态 -(I-初始待对账/D-差异待处理/S-对账完成)

diff_field-存在差异的字段,STATE-状态 / AMOUNT-金额 / BANKONLY-银行单边 / SYSONLY系统单边

check_time – 对账时间

diff_process_time – 差异处理时间

diff_process_remark – 差异处理备注

 

 

银行对账差异处理记录(Optional)bank_bill_check_diff_process记录差异账的处理 (暂略)

 

 

 

 银行对账结果明细表->数据样例

id

系统请求银行

的交易流水号

银行侧

交易单号

账单批次号

/银行编号

系统/银行侧

收款人账号

系统/银行侧

交易金额

系统/银行侧

交易完成时间

系统/银行侧

交易状态

对账状态差异字段对账时间差异处理时间
12023120700901231211110575607

B20231207PAB

/PAB

6217***1069

/6217***1069

10000/10000

2023-12-07

11:11:11

/

2023-12-07

11:11:11

S/FDSTATE

2023-12-08

01:06:00

 
2 231211110575608

B20231207PAB

/PAB

 –

/6217***5638

 -/1

 

/-

-/F SBANKONLY

2023-12-08

01:06:00

2023-12-08

09:30:00

32023120700902 

B20231207PAB

/PAB

6217***1069

/-

1/-

/-

F/-DSYSONLY

2023-12-08

01:06:00

 
42023120701094231211110575613

B20231207PAB

/PAB

9558****0631

/9558****0631

500/500

/-

F/FS

2023-12-08

01:06:00

52023120701950SCLY0906231725

B20231207ALI

/PAB

6228***7074

/6228***7074

12380/12380

2023-12-07

02:52:01

/

2023-12-07

02:52:01

S/SS

2023-12-08

01:06:00

 

 

如何触发对账?

毋庸置疑,实现方案是使用定时任务(JOB)。每家银行出账单的时间是不一样的,例如有的是凌晨3:00生成,有的是上午8:00生成。因此,可以每隔20分钟触发JOB,调用各银行的API获取账单,直到拉取到,然后再进行对账。

拉取银行账单JOB银行对账JOB

获取需要拉取账单的银行通道列表-bankList

依次遍历 bankList

查询bank_bill_batch及bank_bill_check_batch,获取待对账的账单批次-batchList

依次遍历 batchList

 ↓

拉取银行账单方法 (bank) {

  if(已经拉取到) return;

  加锁,防重复执行控制

  组装银行请求参数,拉取银行账单

  解析数据,持久化入库,包括银行账单批次表和账单明细表(事务)

}

银行对账方法(){

  加锁,防重复执行控制

  更新batch的checkState=P

  对该批次里的交易与系统里的T日交易进行check

  对账完成后,标记batch的checkState,存在差异交易则为D,否则为S

 

实现要点

业务防重复执行锁

key:日期+银行编号

TTL:拉取银行账单 与 银行对账,保证这两者在T+1日均执行一次即可。 因此可设置TTL=24h

 

对账及时性保证

银行账单是在T+1日生成T日账单。不同银行的对账单的具体生成时间点有所不同,有的是01:00,有的可能是09:00,甚至有的是中午11:00。因此,定时JOB的开始时间可以从00:30开始,每隔半小时触发。银行账单一旦拉取完成,后续JOB触发时不再重复拉取。

上面表格里的方案是两个JOB,即将拉取银行账单JOB与银行对账JOB分开了。 这是有缺点的。——可能出现对账不及时的情况(银行账单都拉取到了,系统却迟迟没有对账)(见后文【花絮】)。

那么,如何优化呢? 保留一个JOB即可。 拉取银行账单的业务完成后,则异步触发银行对账,保证银行对账及时性。

 

哪些通道需要对账?

最“朴实”的实现方式,不外乎是读取通道表得到bankList,针对这个集合里的每个通道做对账。

注意上面的朴实是加了双引号的。

比较好的姿势,是根据T日的通道交易流水,筛选出来真正需要对账的bankList。

 

【花絮】

我组的对账起初也是2个JOB(开发人员错误的以为分开为2个JOB才叫解耦),其中,拉取银行账单JOB是整点每隔1小时执行(cron=0 0 1-12/1 * * ?),银行对账JOB是整半点每隔1小时执行(cron=0 30 1-12/1 * * ?)。后来,产品经理和结算人员反馈银行账单拉取不及时,对账也不及时。怎么办?开发人员就反复调整这2个cron表达式,让其触发时间间隔更接近。 例如,变更银行对账JOB的cron=cron=0 15 1-12/1 * * ?。 但这样依然无法根本解决对账不及时的问题。 因此,更合适的实现方案是,拉取到对账单后就异步触发对账,并且缩短JOB执行间隔为半小时。

 

【EOF】知识就是力量,但更重要的是…。欢迎关注我的微信公众号「靠谱的程序员」,解密靠谱程序员的日常,让我们一起做靠谱的程序员。

温馨提示:本文发布时间2023-12-09 21:42:00 更新于2023-12-09 21:42:00,某些文章具有时效性,若有错误或已失效,请在下方留言或联系站长
© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发