文章目录
- 前言
- 一、交易信息准备
- 1. MessageDescription内容
- 2. 交易信息填充
- 3. 开户机构信息填充
- 4. 省市区域信息填充
- 5. 银行信息填充
- 二、路由处理
- 三、支付渠道数据补全
- 1.服务端支付渠道获取
- 2. 支付渠道通用数据补全
- 2.1 支付渠道账户信息补全
- 2.1 商户信息补全结束
- 3. 支付渠道差异数据补全
- 四、MessageDescription内容
- 总结
前言
在《支付系统设计三:渠道网关设计03-参数验证》之后需要进行交易信息准备、路由处理、支付渠道数据补全操作。
一、交易信息准备
补充在订单持久化、请求外部支付渠道等业务操作时候需要的参数,补充到MessageDescription中的datas属性中。
根据 transCode+PrepareDataServiceImpl 获取到准备数据service bean进行交易信息的补全准备。
1. MessageDescription内容
经过客户端报文解析处理后paycore上送的报文内容经过解析脚本处理被解析填充到MessageDescription中的datas属性中。
2. 交易信息填充
主要补充的内容有:支付网关交易处理状态、支付网关交易对账状态、支付网关交易状态、支付渠道交易日期等参数。
3. 开户机构信息填充
根据上送的账户开户机构编码补充完整账户开户机构名称等信息(部分交易需要这些参数)。
4. 省市区域信息填充
根据上送的省编码补充完整省名称、银行区域码;根据市编码补充完整市名称等信息(部分交易需要这些参数)。
5. 银行信息填充
联行号、清算行号、支行名称等参数补全。
二、路由处理
请求支付路由获取支付渠道信息,如果MessageDescription的datas属性中instTransId(支付渠道交易id)为空则请求支付路由,如果不为空则说明paycore已经请求过支付路由了,在paycore主要是对paygw提供的原子话交易进行产品化封装,在封装产品的时候可能需要确定支付渠道,如在轮询扣款中支付核心系统paycore就会请求支付渠道获取支付渠道信息,paycore在请求支付路由后会将支付路由payrouter返回的命中渠道信息:instCode渠道编码,instTransId支付渠道交易id、对应的账户信息添加到请求支付网关的报文中。
关于路由的处理见《支付路由系统设计》系列文章讲解其设计。
如下是支付路由系统响应报文:
{
"header": {
"success": true,
"errorCode": "",
"errorMsg": "",
"channelCode": "test_postman",
"channelTransNo": "202311100009000001",
"sceneCode": "test_postman",
"transCode": "routerRule",
"transType": "route"
},
"body": {
"instCode": "payCib",
"instTransId": "deduct_2022101023440770",
"otherMap": {
"instAcctNo": "140562008901"
},
"ruleId": "中金-单笔代扣",
"ruleScene": "routerRule",
"transOrgId": ""
}
}
将获取到的instCode、instTransId、otherMap参数填充到MessageDescription中的datas属性中。
根据支付路由系统输出的服务端支付渠道信息(instCode、instTransId),后面就就可以找到后台管理系统配置的支付渠道信息了,同获取客户端支付渠道信息一样,只是此时获取到的支付渠道属于服务端,即paygw要请求的支付渠道,也就是我们对接的外部支付渠道,如下图的2的通讯交互部分。
三、支付渠道数据补全
transCode+CompletionDataServiceImpl从交易数据补全服务工厂中获取到service bean进行支付渠道数据补全。
/**
* @author Kkk
* @Describe: 交易数据补全服务默认实现(单笔交易)
*/
@Service("defaultCompletionDataService")
public class DefaultCompletionDataServiceImpl extends AbstractCompletionDataService {
@Override
public void execute(PayGwContext context) {
String transNo = StringUtils.valueOf(context.getMessageDescription().getData(PayGwConstant.PAYGW_TRANS_NO));
LoggerUtil.info(logger, "交易({})-网关流水号({})-数据补全-开始", context.getClientTransCode(), transNo);
//1、服务端信息
MessageDescription messageDescription = context.getMessageDescription();
String instCode = StringUtils.valueOf(messageDescription.getData(PayGwConstant.INST_CODE));
PayInstitution serverPayInstitution = payInstitutionService.getByInstCode(instCode);
AssertUtils.isNotNull(serverPayInstitution, SystemErrorCode.UNFOUND_CONFIG, new Object[]{"服务端支付渠道"});
context.setServerInstCode(instCode);//支付渠道
messageDescription.setServerPayInstitution(serverPayInstitution);
String instTransId = StringUtils.valueOf(messageDescription.getData(PayGwConstant.INST_TRANS_ID));
InstTransTypeEntity instTransTypeEntity = serverPayInstitution.getInstTransTypeEntityByTransId(instTransId);
AssertUtils.isNotNull(instTransTypeEntity, SystemErrorCode.UNFOUND_CONFIG, new Object[]{"服务端支付渠道交易"});
context.setServerTransId(instTransId);//支付渠道交易id
String instTransCode = instTransTypeEntity.getTransCode();
context.setServerTransCode(instTransCode);//支付渠道交易码
//2、支付渠道通用数据补全
super.complete(context, messageDescription.getDatas());
//3、支付渠道差异数据补全(通过脚本实现)
instDataCompleteService.complete(context, messageDescription.getDatas());
LoggerUtil.info(logger, "交易({})-网关流水号({})-数据补全-结束", context.getClientTransCode(), transNo);
}
}
1.服务端支付渠道获取
根据支付路由返回的instCode、instTransId获取到后端管理系统配置的服务端支付渠道相关信息,填充到MessageDescription:
2. 支付渠道通用数据补全
2.1 支付渠道账户信息补全
对支付路由返回的otherMap中instAcctNo支付渠道账户关联信息的补全,如下后端配置的参数,填充到MessageDescription的datas中:
2.1 商户信息补全结束
根据路由出得账户信息找到对应的商户信息,即如下的配置:
3. 支付渠道差异数据补全
根据支付路由返回的instCode、instTransId获取到后端管理系统配置的服务端支付渠道通讯配置信息,注意此处的通讯可能对应多次,即有的业务需要和渠道通讯多次,如对接的某银行对账文件下载交互过程:
第一次通信:每天9:00调用[KHKF05]接口查询对账文件生成状态、文件名、密码;
第二次通信:拿着[KHKF05]返回的文件名与密码,调用[FILE03]请求下载对账文件;
第三次通信:调用[FILE02]查询对账文件下载状态,若下载完成,处理接下来流程。
针对各个渠道通讯所需的特定参数进行补全,将补的参数添加到MessageDescription的datas中,在组装支付渠道请求报文时获取。
/**
* @author Kkk
* @Describe: 兴业银行代扣补全脚本
*/
class CIBDeductCompleter implements InstDataCompleter{
@Autowired
SequenceService sequenceService
@Override
void complete(PayGwContext context, Map<String, Object> data) {
def remark=data.get(PayGwConstant.PAYGW_REMARK);
remark=StringUtils.isEmpty(remark)?"用户还款支付":remark;
data.put("remark",remark);
def transDate = DateUtil.format(data.get(PayGwConstant.PAYGW_TRANS_DATE),"yyyyMMddHHmmss")
def seq = sequenceService.generate(SeqTypeEnum.SEQ_DEDUCT, 16, DecimalTypeEnum.DECIMAL)
data.put(PayGwConstant.INST_REQ_NO,SeqTypeEnum.SEQ_DEDUCT.getCode().concat(transDate).concat(seq))
}
}
四、MessageDescription内容
经过渠道数据补全后的MessageDescription内容如下:
主要是补全服务侧机构相关信息,和待持久化信息,账户信息,商户信息。
总结
主要介绍了对交易上下文MessageDescription属性的数据补全。