|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?


编辑导读:有时会遇到这样的情况:同样一笔订单 , 扣了用户两笔钱 。 这是属于重复扣款的异常 , 对于被扣款的用户来说 , 是极差的用户体验 , 所以我们要避免这样的情况发生 。 本文将对此展开分析 , 希望对你有帮助 。

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
今天的文章我们接着上次的话题 , 继续聊聊支付系统异常解决办法 。
在上篇文章中「支付掉单异常解决方案」 , 我们主要提到的是支付过程中掉单的场景 , 用户明明付款成功 , 银行卡都扣款了 , 但是订单却还显示待付款 。
而在今天的文章中 , 我们将聊到重复付款的异常 , 即同一笔订单 , 扣了用户两笔钱 。
另外我们还将会提到另外一种异常 , 用户扣款成功 , 但是订单却支付失败的场景 。
以上两种异常对于被扣款的用户来讲 , 使用体验极差 , 自己多付了钱 , 订单却还不成功 。 所以如果不及时处理这两类异常 , 那就真的等着被投诉吧 。
一、重复付款异常
1. 异常场景
重复付款异常一般常见于网银支付 , 微信支付 , 支付宝等这类需要跳转到一个支付网关页(网银支付) , 或者跳转到钱包 APP(支付宝、微信) , 从而异步完成扣款的支付场景 。

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
网银支付流程
这种支付场景下 , 只能通过接受异步通知才能知道支付结果 , 我们一般将其称为异步支付 。
【|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?】PS:有了异步支付 , 那么同步支付是什么?
其实同步支付指的就是调用支付接口之后 , 就可以立刻返回支付结果的 , 比如银行卡类快捷/代扣等支付就是同步支付 。
当然也有一些奇葩的银行卡支付渠道 , 同步支付结果为受理成功 , 只能接受异步通知或者查询返回支付结果 。
由于银行卡支付需要返回明确支付结果 , 对于这类渠道只能内部设计将异步转为同步,感兴趣可以看下之前历史文章:
架构设计|异步请求如何同步处理?
后台支付流程如下:

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
网关支付
2. 为什么会发生重复付款?
主要原因其实跟上次内部掉单异常一样 , 跟业务表设计有关 。
上次我们提到 , 支付系统主要表结构如下:

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
在这个表结构下 , 只要支付订单未成功 , 商户就可以重复使用其内部同一订单号调用支付接口 。
假设这样一个场景 , 用户在收银台支付时选择招行进行网银支付 , 当他点击支付之后 , 商户系统将会调用支付公司的网银接口 。
这时支付系统内部将会创建一笔支付单以及关联的渠道订单 , 并且调用招行系统的接口 。
然后用户的浏览器页面将会打开一个新页面 , 然后跳转到招行网站 。
这时如果此时用户再次在收银台点击支付 , 将会再次调用支付系统接口 。 这时候由于支付单已存在 , 所以仅仅会再创建一条渠道订单记录 , 并且调用招行系统的接口 。 这时用户的浏览器将会再次打开一个招行的网站 。
如果用户在两个招行网银页都完成支付 , 这时就发生了重复付款 。
上面这种场景看起来有点傻,但是真实用户操作真的会发生 。 除了这种 , 博客园上的小伙伴还提到这么下面这种情况:

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
3. 解决办法分页标题
重复付款异常的主要的解决办法有两种 , 分为事前与事后 。
事前主要的目是尽可能防止用户重复付款 , 主要解决办法为优化付款页面 , 尽可能做好提示 。
「第一种优化方式 , 付款页面直接跳转到第三方/银行的网银页面 , 不要打开新的页面去跳转 。 」

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
网银同步跳转
这种方式可以防止用户误打开两个网银付款的页面 , 从而导致重复付款 。
但是这里会有一个问题 , 银行网银页面付款成功之后 , 用户如何知道其在商户侧订单状态也成功了?
其实很简单 , 现在网银支付接口 , 一般都会有一个参数 「return_url:同步跳转地址」。
来自支付宝开发文档
只要在接口传入这个地址 , 当支付成功之后 , 页面最终就会跳转到这个传入的地址 , 商户侧就可以在地址显示订单是否支付成功 。

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
支付系统异常处理-同步跳转
上面我们提到 , 用户有可能会使用浏览器回退功能 , 跳转到支付页 , 从而导致重复付款 。
对于这种情况 , 我们可以在其回退支付页时 , 首先向后台查询这笔订单支付结果 , 如果已支付成功 , 那就直接显示成功页面 。
「第二种优化 , 对于这种重新打开一个页面跳转到银行网站 , 我们可以在页面加入弹窗提示 , 询问用户是否已支付完成 。 」

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
比如上面这种处理方式 , 当用户点击确认完成充值 , 可以马上向后台发起查询订单状态 。
下面来聊聊事后的解决办法 , 「其实解决办法很简单 , 发起内部退款 , 将多余支付的一笔反向退款回去」 。
支付系统内部可以有个定时任务 , 定时扫描支付单下有多条成功渠道订单的记录 , 然后选择将重复支付渠道订单发起退款 。
这种方式是支付公司系统内部的操作 , 不需要商户侧发起指令 。
二、订单失效异常
1. 异常场景
这种场景一般常见于电商购物 , 秒杀等购物场景 。 当用户下单之后 , 页面将会开始倒计时 , 用户需要在有效期内支付成功 。

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
假设用户点击跳转到支付宝 , 但是其没有立刻支付 , 而是停留了很久 , 在订单最后一秒时间内完成了支付 , 但是这个时候订单早已因为时间到期而被自动取消 。
这样就发生用户扣款已经成功 , 但是订单却是失败或关闭的场景的 。
另外还有一种情况 , 用户在有效期内支付成功 , 但是因为网络、内部应用等问题 , 支付结果的异步通知过了很久才收到 , 这时内部订单的早因为时间到期而被取消 。
2. 解决办法
「第一种解决办法 , 上送有效期给支付渠道 。 」
一般支付接口都会有一个支付有效期的字段 , 表明这笔支付最晚可以支付的时间 。 如果超时未支付 , 这笔支付将会被关闭 。
来自支付宝开发文档
当然一般情况下 , 如果未上送 , 这个字段内部一般会有个默认的有效期 , 比如 3 天 , 这个时间就比较长了 。
所以当调用支付接口时 , 可以将订单剩余有效期传入支付接口 。 这样用户如果在超时时间内未完成支付 , 支付将会失败 。
「第二种解决办法 , 内部发起退款 。 」
这个解决办法依然事后托底的解决办法 , 对于支付订单已关闭 , 但是支付却成功的情况 , 发起内部退款 , 将钱退给用户 。
内部可以有个定时任务 , 定时扫描支付订单已关闭但是支付却成功的情况 , 然后发起退款指令 。分页标题
三、最后
最后用思维导图方式帮大家总结一下支付系统可能会碰到的异常 。

|一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
本文插图
作者:楼下小黑哥;微信公号@程序通事 , 支付行业 , 后端技术
本文由 @楼下小黑哥 原创发布于人人都是产品经理 。 未经许可 , 禁止转载
题图来自Unsplash , 基于CC0协议