系统怎么处理重复缴费问题?

理由
举报 取消

现在有两个个系统:app,web。这两个个系统都可以生成订单并缴费,且互相之间可以缴费。现在问题就是,我在app上生成一个订单,跳到支付页面(但不做缴费操作,就停在这里),然后我登录web上进行这笔订单的缴费,缴费成功后再继续完成app的缴费,(因为在支付界面不由我系统控制了,还是能继续缴费的)。这样的重复缴费怎么解决?

2017年10月12日 10 条回复 1352 次浏览

发起人:韦昌明 初入职场

任何关于 Live 的问题(功能使用、推荐讲者等等)都可以联系 live@zhihu.com

回复 ( 10 )

  1. 梁川
    理由
    举报 取消

    重复支付的问题,第三方支付公司都有成熟的解决方案。

    在线支付对重复支付一般解决方案如下:

    1、支付接口判重

    第三方支付在接收到支付请求后,根据与商家约定的判定重复支付的参数组合对支付请求进行校验及判重,如果为重复订单,则不继续后续流程。

    由于涉及每一次支付请求都需要查询交易数据,影响系统性能;且由于不同商家的判重标准不尽相同,一般都需要要对接口做定制,因此除非是大商户,一般都不提供此功能。

    而且此种方案,并不能杜绝重复支付的问题,例如:用户开了两个窗口,都已经跳转到银行网银页面上,此时侯第三方支付已经无法控制用户支付行为了。

    2、重复支付+退款接口

    如果重复支付的订单尚未与第三方支付平台结算,则:

    在用户支付成功后,商户系统是可以判断是否为重复支付,商户系统可以自动调用退款接口,对判定为重复支付的订单发起退款请求(商户平台订单号+支付平台支付流水号)。

    也可以由商户运营人员在运营后台发起退款请求(本质上也是调用退款接口)。

    3、批量代付退款

    如果重复支付的订单已经与第三方支付平台已经结算(第三方支付与银行也完成对账、结算),则:

    对在线支付,一般采用批量代付的方案,将重复支付订单退款与提现、转账等业务以批量文件方式提交给代付渠道代付出去。

    如果是POS收单,可以采用冲正、消费撤销、退货等命令,对重复支付的订单进行反向交易。在线支付一般较少采用冲正方式。

    另外在商户端,为避免对于重复支付,在业务逻辑上也可以做一些处理,包括:

    1、保证交易订单号的唯一性。很多商户系统开发能力有限,经常出现交易订单号不唯一的情况。

    2、在发起支付请求后,更改订单状态,避免用户再次发起支付请求。(慎用,只不过在一些业务场合会也会采用此种方案)。

    3、对因掉单等原因引起的订单状态未知的情况,先调用第三方支付接口的查询接口确认订单的支付状态。

  2. socici
    理由
    举报 取消

    1 点支付按钮先先跳到自己服务器的接口,对订单状态校验后重定向到第三方的支付网关。

    2 由支付网关校验是否重复支付

  3. 别业居幽处
    理由
    举报 取消

    我在做基金支付的时候碰到过类似问题。

    结论:单一第三方支付可能没法解决这个问题。需要支付和客户系统配合。因为判断重复支付你首先要明确判断依据,第三方支付可不一定有能力控制他的支付通道以及控制客户后台的账务记录。你不要把所有判重的活都揽在自己或者支付公司身上,这个要双方配合的。

    当时每个人在基金公司后台只有一个TA账户。当时有很多交易账户过来的钱,支付的渠道和方式也不同。比如某人买博时的同一个基金,可能从好买基金网注册基金账户,用网银网关支付;也可能是他在建行开了一个基金交易账户,用建行的快捷支付充值支付。

    基金公司TA系统后台就做的比较好,记录记录份额,收益、余额之类的,重要的是他们记录从哪个渠道过来的钱,分的很清楚。

    1.技术上控制session生命周期,一段时间不操作,支付界面直接踢出去。这个你要和支付公司谈或者你自己的订单做控制。

    2.要求客户后台有账务记录,系统流水ID等。没这些只能对出糊涂账,判断重复支付更是扯淡。判断重复支付不能只依靠第三方支付公司。

    3.实时判断是否重复支付,梁川说的已经比较详细了。我感觉你这块问题的根源不在支付,而是没摸清楚交易渠道和后台账务记录的多对一关系。

  4. 养仓鼠的拔拔
    理由
    举报 取消

    这个问题可以从构造支付请求中的识别号上来解决:

    通常来说,支付请求时必须要提供一些可以唯一识别这一支付请求的数据,比如:批次号,交易号,商家订单号等。

    又,由于无论是通过APP,或WEB,客户实际上是向同一个SERVER下了订单,因此订单号应当是唯一且固定的。

    那么,我们可以根据订单号来构造支付请求中需要的识别信息,其中需要注意的是,最好不要用时间戳作为构造的一部分,因为无法保证在移动端和服务端的系统时间的一致性。

    大概的思路是:order_sn+timestamp(保留到天)+当天支付次数(如同一订单可能分批次付款)。

    PHP:在WEB端,进行支付前,从支付记录数据库(别告诉我没有)中得到当天的该订单的支付次数$count,则 $batch_no=$order_sn.time(date()).($count+1);

    在APP端,以android为例,在调用第三方支付前的页面中,先从服务器中获得count(方法与WEB一致),然则 String batch_no=order_sn+time+String.valueOf(count+1);

    这样通过这个batch_no去提交,就可以避免重复支付,因为:

    假设出现了题主在描述中的情况,假设app端提交的batch_no是0001 1234567890 1(空格为了表示其构造),则当web端去进行请求时,其生成的batch_no必然也是同一个(app端尚未完成支付,并没有Notify,则支付记录数据中得到的count仍然为0),则当web端支付完成后,这个batch_no就已经expire了,app端进行下一步支付时,就会无效。

  5. 味道不错哦
    理由
    举报 取消

    PC端也做 移动端也做,所以不请自来的说两句。你说的这种方式在一个设计完善的程序里是不会出现重复缴费的问题,如果依照你这个讲法,如果支付方式多样化的,如APP WEB 短信 宽带等支付,一旦都开启了支付请求,就全部重复缴费了。

    浅显点比喻:当PC端或WEB端生成订单的时候,数据系统就接收到了请求信息如某人某单号某时间付款状态,无论是在哪一端支付了之后,这个请求随即被注销成已付状态,当你用其他客户端再提请求的时候,就会提示已经缴费, 而不是出现重复缴费。

  6. GavinZhao
    理由
    举报 取消

    这样的情况比较常见,类似的情况是:银行的扣款成功的通知结果延迟了,在同一笔业务订单因为没有收到成功的结果通知,发生第二次支付并正常成功后,才收到第一次支付成功的通知,此时对应的就是「去A平台继续缴费」引起重复缴费,做法比较简单:对A平台的支付做退款即可,引申的问题就是,在异步交易中,如何区分B和A的支付结果通知,这就要对业务订单和支付订单一对多的关系设计一个标识,用来确认对应关系。

  7. 余某
    理由
    举报 取消

    发两个货过去

  8. 春曾
    理由
    举报 取消

    我们哥几个帮人抢火车票,结果同一张票居然都支付成功了。。就是有网页版、有客户端总之各种方式。后来过了一周,应该是系统结账的时候把其它多付的款都退回来了,怎么实现我倒不清楚,不过分布式得收款总得核对订单和账目啊。

  9. 达拉
    理由
    举报 取消

    生成的订单id是唯一的,所以无论在app还是web,后端服务只处理一次该订单id的支付请求,这种只会到支付网关就分辨出来了,都不会进支付渠道

  10. 日野俊基
    理由
    举报 取消

    将待付客户要约在后台生成一份短表,定时清理,保证不会太多,大型支付做好分布储存。

    待付单支付时完成其注销。

我来回答

Captcha 点击图片更换验证码