电商交易背景知识合集第二季
郑昀编纂 基于网络资料 创建于2015/9/9 最后更新于2015/10/16
关键词:在线支付,异常,重复支付,冲正,out_trade_no
轻点第一季了解更多知识。特别感谢知乎梁川、天顺等知乎网友的精彩答案。
本文档适用人员:交易领域的产品研发人员
提纲:
- 交易中的异常处理
- 何谓冲正
- 重复支付
电商核心交易流程中,由于涉及的对象较多,如自家的订单中心、资金帐户中心、库存中心、支付中心,第三方支付的接口,银行,自家的支付网关等等,每个对象都可能处于不可知状态,网络消息的投递也不能保证先后顺序,还可能丢包,所以有大量的异常分支需要处理。
0x00,交易中的异常处理
1.1.何谓冲正
我们来看看百度百科上关于冲正的定义:
一笔交易在终端已经置为成功标志,但是发送到主机的帐务交易包没有得到响应,即终端交易超时,所以不确定该笔交易是否在主机端也成功完成。为了确保用户的利益,终端重新向主机发送请求,请求取消该笔交易的流水,如果主机端已经交易成功,则回滚交易,否则不处理,然后将处理结果返回给终端。冲正,就为系统认为可能交易失败时采取的补救手法。
学术上这么解释也许够了,但还是不够严谨的,因为冲正交易不光要求对已有交易进行回滚,语义上他还要求应答系统对该交易流水进行幂等控制——将该交易流水插入幂等表,即便后续该交易报文再抵达,也予以拒绝交易。
如果没有上面我补充的这段,冲正交易的实现是有逻辑漏洞的。
虽然概率极低,但由于各链路节点处理信息的效率不一致,所以也有可能出现冲正交易先抵达目标系统,正常交易晚抵达的情况。如果该目标系统的冲正交易并未作以上逻辑判断,那就会引起用户纠纷。
最后,我们来看看冲正交易的使用场景。
通常,目前国内线上支付系统鲜有冲正交易(除非部分快捷支付接口,银行当时是使用信用卡无磁无密网关包装出来的,会保留冲正接口),大多数的场景发生在线下。
例如,你去商场购买了一个包包,价值5万元,刷信用卡消费。
POS机在发送交易报文的时候……不幸掉单了,嗯,就是那么不幸,POS机无论如何收不到来自于收单系统的回执单据。经过漫长的等待,POS机忍不住了,自动给收单系统发了一笔冲正交易……收单行回执,冲正交易处理成功,事件完毕。
这个时候,你会发现服务员又笑眯眯地找你,要你重新刷一下卡……
或许有同学会问,那万一的冲正交易也掉单了呢……
是的,会有这种奇葩情况,通常系统会对冲正交易重发N次,N次后如果还没应答就算了,概率太低了,等用户来投诉吧——很多时候人工保障比你动脑筋想异常中的异常如何系统自动处理来得反而高效和低成本。
或许还有同学会问,那POS机上的撤销交易和冲正是什么关系呢?
其实两个接口的内部实现可以说是类似的,业务场景上,撤销交易更偏向于由人工发起对原单据的撤销,可以理解为业务行为;冲正更类似于系统保障机制,可以不由业务人员感知到,仅此而已。
(出处1)1.2.重复支付
在线支付对重复支付一般解决方案如下:
1)支付接口判重
第三方支付在接收到支付请求后,根据与商家约定的判定重复支付的参数组合对支付请求进行校验及判重,如果为重复订单,则不继续后续流程。
由于涉及每一次支付请求都需要查询交易数据,影响系统性能;且由于不同商家的判重标准不尽相同,一般都需要对接口做定制,因此除非是大商户,一般都不提供此功能。
而且此种方案,并不能杜绝重复支付的问题,例如:用户开了两个窗口,都已经跳转到银行网银页面上,此时侯第三方支付已经无法控制用户支付行为了。
(郑昀注:
1. 从电商平台的角度,我们传给支付宝的商户唯一订单号 out_trade_no,这是第三方支付判重的唯一依据。
2. 用户可能会连续变更 待付款订单 的支付方式,如从支付宝切成微信支付,如从支付宝之网银直连变为支付宝这种第三方支付内部变更,还有可能通过修改购买份数从而变更待付款订单的应付金额(当然有些情况下电商锁定订单,不允许修改),那么,为了保证电商平台能够识别 支付成功通知 对应于用户的同一个订单的哪一次支付行为,我们的 out_trade_no 参数里会包含一个序列号。
我2012年写的《电商课题:支付交易一般性准则》里曾经给出过一个例子:
例一:修改订单,订单应付金额或支付方式发生变化背景:订单在没有支付成功之前,顾客都是可以修改的。做了以下修改后,可能会引起订单应付金额或支付方式发生变化:
- 余额支付的金额变化
- 购买份数的调整
- 优惠券/代金券的使用
而支付宝等第三方支付,对于一个用商户唯一订单号标识的交易,禁止变更 total_fee(交易总金额)字段!所以,我们的同一个订单,发起不同应付金额的支付请求时,必须更换 out_trade_no ,流程如下图4.2所示:图4.2 订单应付金额变化,out_trade_no 必须变化
)
2)重复支付+退款接口
如果重复支付的订单尚未与第三方支付平台结算,则:
在用户支付成功后,商户系统是可以判断是否为重复支付,商户系统可以自动调用退款接口,对判定为重复支付的订单发起退款请求(商户平台订单号+支付平台支付流水号)。
也可以由商户运营人员在运营后台发起退款请求(本质上也是调用退款接口)。
(郑昀注:电商平台的支付中心必须能够判定重复支付,并自动发起原路退返。
举个例子,
10点01分:订单001,应付金额10元,用户选择支付宝发起支付,out_trade_no=XX_001_0001,用户登录支付宝后产生了应付账单,但未付款;
10点02分:订单001,用户修改购买份数,应付金额变更为5元,用户选择支付宝发起支付,out_trade_no=XX_001_0002;
10点03分:用户把XX_001_0001和XX_001_0002都付款成功了;
10点03分10秒:XX_001_0001的支付成功通知到达。电商平台的支付中心标记该交易支付成功,但因该交易关闭而不再路由给订单中心,订单状态不会发生变化。有专门的定时任务处理这种异常交易,T+N 天后如果用户仍没有处理,那么系统会自动发起原路退返,退到用户支付宝账户10元;
10点03分20秒:XX_002_0002的支付成功通知到达。电商平台标记订单为已付款状态,同时标记该订单有重复支付,用户如果登录到商城,会收到站内消息通知,个人中心页面也有提示。
)
3)批量代付退款
如果重复支付的订单已经与第三方支付平台已经结算(第三方支付与银行也完成对账、结算),则:
对在线支付,一般采用批量代付的方案,将重复支付订单退款与提现、转账等业务以批量文件方式提交给代付渠道代付出去。
如果是POS收单,可以采用冲正、消费撤销、退货等命令,对重复支付的订单进行反向交易。在线支付一般较少采用冲正方式。
另外在商户端,为避免重复支付,在业务逻辑上也可以做一些处理,包括:
1、保证交易订单号的唯一性。很多商户系统开发能力有限,经常出现交易订单号不唯一的情况。
2、在发起支付请求后,更改订单状态,避免用户再次发起支付请求。(慎用,只不过在一些业务场合会也会采用此种方案)。
3、对因掉单等原因引起的订单状态未知的情况,先调用第三方支付接口的查询接口确认订单的支付状态。
(出处2)参考资料:
1,2014,知乎天顺的专栏文章,http://zhuanlan.zhihu.com/workandlife/19861292;
2,2015,知乎梁川的回答,http://www.zhihu.com/question/36459849/answer/67597515;
-EOF-
更多知识:
电商交易背景知识合集第一季 (2015-09-08 17:42)
欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注: