AR模块中通用对账的优化尝试

devtools/2024/9/24 16:50:17/
<article class="baidu_pl">
article_content" class="article_content clearfix">
arkdown_views prism-atom-one-light">arker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

背景:
用户在唯品会下单后,是可以自由选择不同支付方式进行支付的,支付后,支付系统会将一笔收款单传送给AR,AR财务可以从此处看到收款情况。但是,真实的资金是按照不同支付方式,由银行或者其他渠道与资金系统交互的。在数据传输中,会有可能出现短款,即支付系统有收款单数据,但是资金系统未收到款。这就需要有一种对账的功能,将我们这边的收款情况和银行的流水做匹配。目前是银行将各自的流水文件每天传送给支付系统,再由支付将银行流水文件传到vos上。AR这边每天去拉取vos上的文件,进行解析后,与AR系统的收退款单数据做比较。最后将比较结果做成报表给到用户分析。

目前的问题点:
早期的时候,因为支付方式不对,对接的渠道少,同时每个银行给到的对账单文件和格式都不一样,由此每一种对账方式都是单独的一套代码,目前仅这种支付方式对账的任务就已经达到了23个,相关数据库表46个。而且后续每新增一个支付方式,按照之前的代码框架,要新增一个任务两个表和一堆配置信息和报表,需要至少3天的开发和测试工作量。这种设计显得非常不合理,为后续运维拓展更加方便,同时减轻数据库压力,需要优化成易拓展运维的通用形式。

前期的业务和代码分析:
通用点:所有的支付方式都需要从vos上拉取文件,解析数据后,存入到接口表中。然后根据支付流水号去抓取AR收款单数据后,将金额进行比较,最后输出结果表。
不同点:银行给的对账单文件格式都不一样:第一是对账单格式和名称不一样,有.csv,.txt,.xlsx,.zip,.xls,.gzip,.bin文件,每种文件的解码方式不一样,而且有的对账单文件前几列是无法解析的。这一部分无法做成完全的通用,但是可以将每种解码方式都写好后,再根据文件的格式去走不通的解码即可。然后文件前面多少列无需解析也可以通过配置文件指定。第二是字段名称含义和顺序不一样,但是银行给的对账文件上大多数字段用户并不关注,同时我们对账用到的字段仅有3个:收退款标识,支付流水号,金额。所以没必要将每种对账方式解析出的数据都落到不同表中,仅需要新增一个attribute字段足够多的通用接口表,用于将vos上拉到的文件字段全部落到通用接口表中即可。同时增加一个配置,指定每种对账方式的三个对账关键字段的位置即可。

代码关键片段:
拉取文件

	public List<UnionPayObj> downLoadFile(List<ArCfgLookup> lookups){List<UnionPayObj> unionPayObjs = new ArrayList<>();for(ArCfgLookup arCfgLookup:lookups){if(arCfgLookup.getStartDate().equals(arCfgLookup.getEndDate())){continue;}ArVosSFTPSesionObj vosObj = getSftpSessionObj(arCfgLookup.getTagFlag());vosObj.setStartDate(FcsArDateUtil.convertDateToString2(arCfgLookup.getStartDate()));String fileName =vosObj.getStartDate().concat("-").concat(arCfgLookup.getAttrbiute1());vosObj.setFilename(fileName);creatLocalPath(vosObj);VosFileDownHandler vosFileDownHandler = VosFileDownHandlerFactory.INSTANCE.getVosHandler(vosObj.getVosBucket(),vosObj.getHost(), vosObj.getAccessKey(), vosObj.getSecretKey());try{if(!arCfgLookup.getDescription().contains("TEST")){vosFileDownHandler.dowload(vosObj.getFilename(), vosObj.getLocalPath());}if(arCfgLookup.getStartDate().before(arCfgLookup.getEndDate())){arCfgLookup.setStartDate(FcsArDateUtil.addDayByDate(arCfgLookup.getStartDate(), 1));//endDate要另起任务去根据当前时间轮训更新}arCfgLookupService.update(arCfgLookup);unionPayObjs.add(new UnionPayObj(fileName,arCfgLookup,vosObj));} catch (Exception e) {log.info("下载对账文件失败:"+vosObj.getFilename()+"地址:"+vosObj.getLocalPath());}}return unionPayObjs;}```按照类型解析```javapublic void parsingData(List<UnionPayObj> unionPayObjs){log.info("开始解析数据");for(UnionPayObj unionPayObj:unionPayObjs){List<List<String>> results = null;if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".txt")){results = parsingTxt(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".csv")){results = parsingCsv(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".bin")){results = parsingBin(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".xlsx")){results = parsingXlsx(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".xls")){results = parsingXls(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".zip")){results = parsingZip(unionPayObj);}else if(unionPayObj.getFileName().toLowerCase(Locale.ROOT).endsWith(".gzip")){results = parsingGzip(unionPayObj);}arIntCommonImportService.convToArIntCommon(results,unionPayObj.getArCfgLookup());}}
	public List<List<String>> parsingTxt(UnionPayObj unionPayObj) {log.info("开始解析数据txt文件");List<List<String>> txtData = new ArrayList<>();int inputStreamCache = 5 * 1024 * 1024;try (FileInputStream fileInputStream = new FileInputStream(unionPayObj.getArVosSftpSesionObj().getLocalPath() + "/" + unionPayObj.getFileName());InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);BufferedReader reader = new BufferedReader(inputStreamReader, inputStreamCache)) {String line;int index= 0;while ((line = reader.readLine()) != null) {index ++;if(index<= Integer.parseInt(unionPayObj.getArCfgLookup().getAttrbiute5())){continue;}String[] split = line.split("[|\\t]");txtData.add(new ArrayList<>(Arrays.asList(split)));}} catch (IOException e) {log.error(eventName + unionPayObj.getFileName()  + e.getMessage());}return txtData;}

数据落表之前根据配置将对账关键字段捞出放到前3

	public void getMainParam(List<String> sts,ArCfgLookup lookup){String payTypeSign = sts.get(Integer.parseInt(lookup.getAttrbiute2()));String payNumber = sts.get(Integer.parseInt(lookup.getAttrbiute3()));String amount = sts.get(Integer.parseInt(lookup.getAttrbiute4()));//根据金额来判断收退款if(lookup.getAttrbiute2().equals(lookup.getAttrbiute4())){payTypeSign = new BigDecimal(amount).signum() > 0 ? "收款" : "退款";}//此处插入为文件带下来的对账流水号,并不一定是真实流水号,对账时再调用osp查询List<String> newList = new ArrayList<>(sts.size());newList.add(lookup.getLookupCode());newList.add(payTypeSign);newList.add(payNumber);newList.add(amount);sts.addAll(0, newList);}

数据准备好后对账片段

	public void processRecData(ArIntCommonImport arIntCommonImport,List<ArMainReconciliationResult> arMainReconciliationResults){List<ArIntRecIn> recInts = arIntRecInService.listByPayNumber(arIntCommonImport.getAttribute2());BigDecimal recAmount = getRecAmount(arIntCommonImport.getAttribute2());if(CollectionUtils.isEmpty(recInts)){arIntCommonImport.setProcessFlag("E");arIntCommonImport.setErrorMessage("收款单缺失!");return;}if(!FcsArNumberUtil.compareToOnBigDecimal(recAmount,new BigDecimal(arIntCommonImport.getAttribute3()))){arIntCommonImport.setProcessFlag("E");arIntCommonImport.setErrorMessage("收款单金额与对账单金额不等!收款单金额"+recAmount.toString());return;}ArIntRecIn recIn = recInts.get(0);arIntCommonImport.setProcessFlag("S");arIntCommonImport.setErrorMessage("对账成功!");ArMainReconciliationResult arMainReconciliationResult = buildReconsResult(arIntCommonImport,"收款",recIn.getOrderNum(),recIn.getGlobalId());arMainReconciliationResults.add(arMainReconciliationResult);}

优化后的提升:
后续新增对账方式无需新增数据库表和任务和报表。在不新增文件类型的情况下,无需修改代码,仅在配置表上增加配置用于识别新的对账方式即可。用户查看对账结果的报表也无需新增,报表上新增对账方式后,按照筛选对账方式进行查看即可。

最后贴一下GIT地址代码对比
老的对账方式 仅给一个支付宝对账的示例
拉取对账文件 ARTASK下的ArIntfcAliPayMain.java
对账 ARTASK下的ArAliPayAccountExecMain.java

新的对账方式
拉取对账文件 ARTASK下的 ArCommonAccountFromVosMain.java
对账 ARTASK下的 ArExcelCommonImportMain.java


http://www.ppmy.cn/devtools/16525.html

相关文章

离开A页面时,取消A页面的axios接口数据请求

需求&#xff1a;从A页面跳转至B页面时&#xff0c;要取消A页面的axios请求&#xff1b;有时候&#xff0c;我们可能需要在发送请求后取消它&#xff0c;比如用户在请求还未完成时离开了当前页面或者执行了其他操作&#xff0c;本文将介绍如何在使用 Axios 发送请求时取消这些请…

vscode中对 python 快速增加header 描述

在首选项→配置用户代码片段→python 然后再 Code/User/snippets/python.json文件中写入 {// Place your snippets for python here. Each snippet is defined under a snippet name and has a prefix, body and // description. The prefix is what is used to trigger the …

分享:9.3版本无缝导入AVEVA PDMS高版本工程12.0,12.1,E3D

9.3版本可以无缝导入AVEVA PDMS的工程。 UKP3d导入AVEVA PDMS工程的方法 http://47.94.91.234/forum.php?modviewthread&tid163583&fromuid6 (出处: 优易软件-工厂设计软件专家) &#xff08;从AVEVA PDMS导出时元件和等级的功能我们正做收尾工作&#xff0c;到时可以…

MacOS通过命令行开启关闭向日葵远程控制的后台服务

categories: [Tips] tags: MacOS Tips 写在前面 经常有小伙伴问我电脑相关的问题, 而解决问题的一个重要途径就是远程了. 关于免费的远程工具我试过向日葵和 todesk, 并且主要使用向日葵, 虽然 MacOS 下要设置很多权限, 但是也不影响其丝滑的控制. 虽然用着舒服, 但是向日葵…

服务器排障(Linux,Windows)

一&#xff0e;计算机的启动流程 二&#xff0e;系统服务 三&#xff0e;运行级别 四&#xff0e;运行级别被修改 五&#xff0e;Root密码被遗忘 六&#xff0e;设置Grub密码 七&#xff0e;设置bios密码 一、计算机启动流程 1、bios加电自检 对计算机的硬件进行检测&a…

Swift - swiftc

文章目录 Swift - swiftcswiftc存放在Xcode内部一些操作 Swift - swiftc swiftc存放在Xcode内部 Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 一些操作 生成语法树&#xff1a; swiftc -dump-ast main.swift生成最简洁的SIL代码&#xff1a; swiftc…

安全评估报告 项目安全风险评估报告 信息安全评估报告

一、安全评估报告的意义 安全评估报告是对特定环境、设施或系统安全性进行全 面分析、评估和预测的重要工具。它通过对潜在风险的识别、分析和评价&#xff0c;帮助决策者了解当前安全形势&#xff0c;制定科学的安全策略&#xff0c;从而有 效预防和减少安全事故的发生。安全…

【MHA】MySQL高可用MHA介绍4-故障监控与切换具体流程

目录 一 故障监控与切换 1 验证复制设置并识别当前主服务器 2 监控主服务器 3 检测主服务器故障 4 再次验证从服务器配置 5 关闭故障的主服务器&#xff08;可选&#xff09; 6 恢复新主服务器 6.1 保存来自 已崩溃主服务器的二进制日志事件&#xff08;如果可能&#…