电商课题VII:支付交易一般性准则
@郑昀汇总 创建于2012/11
?此时提示几点:1)如果交易已经关闭,但商户的网站上仍保留了订单的“付款”按钮,那么点击跳转到支付宝后,会看到如下警告信息:
或
2)当交易状态为交易关闭时,就算用户能通过第三方网银对支付宝账单进行付款(用户可能已经跳转至银行交易页面,并且未关闭页面),第三方网银能将支付成功信息通知支付宝,支付宝也不会通知商户,而是会自动退还至支付宝余额中。3)网银直连的订单是关闭不了的,因为它没有跟支付宝账户绑定。4)商户如发现交易已关闭的订单被用户支付后,那么必须进入异常支付流程(能原路退返就退,如无法退返则返还至账户余额)。?2.2. 退款通知的处理支付宝对此的定义是:(1)枚举名称枚举说明REFUND_SUCCESS退款成功:全额退款情况:trade_status=触发条件名触发条件默认值退款处理结束true(触发通知)这个所谓退款处理结束通知,实际上仍是一个“trade_status_sync(交易状态同步)”通知,特殊性在于携带的 refund_stauts =REFUND_SUCCESS 参数,实际例子如下所示:
注意几个要点:
当交易状态为 TRADE_FINISHED(交易完成) ,那么不可退款!
此处有一个“退款期限”概念,交易关闭(TRADE_CLOSED)后3个月(或6个月)内可以退款,超过此期限后,该笔交易成功且结束,从此不可退款!对于业务逻辑,意味着此时只能退还金额到账户余额,无法原路退返。支付宝、快钱、财付通等均有此设定。手机支付退款如返回 D23190 错误码,含义是退款日期超过最大有效期(有效期是半年)。退款处理结束的通知到达时,支付宝会先发送一个支付成功通知,防止你的系统不知道有此交易。请正确处理这个支付成功通知,不要误认为这是“重复支付”(因为对应的订单可能已确认+已支付),以至于误判给原路退返了。??三. 异常处理类3.1. 掉单的被动处理支付宝的文档说的很清楚:服务器异步通知页面(由参数 notify_url 指定页面文件)获取支付宝返回的结果数据,(商户的)程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是 success 这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:2m,10m,10m,1h,2h,6h,15h);所以,如果你用来接收支付宝异步通知的服务阻塞了(hang/stuck)或挂了(shutdown/crash),就无法给支付宝返回 success 响应,所以它会不断地发起重试,直到25小时内你恢复服务返回 success 。所以如果掉单(用户已付款/已扣款,但你的数据库里这个订单还是未付款状态),你还有机会补救。?3.2. 掉单的主动处理掉单后,等待支付宝补发通知给你,商户可能来不及应对汹涌而来的顾客投诉。此时,服务器端应该主动提交此订单对应的(一个或多个)唯一订单号(out_trade_no,支付宝合作商户网站唯一订单号),调用支付宝的单笔交易查询接口?single_trade_query,从而获得交易状态、支付宝交易号、付款时间、交易总金额等明细。(具体细节请看支付宝的《单笔交易查询接口(single_trade_query).pdf》)一旦查询到了支付成功的细节,而且付款金额也等于商户记录的应付金额,那么就可以给操作人员展示一个画面,使得他能手工置这个订单为已确认+已付款。?3.3. 来自于多个支付渠道的重复支付什么情况下会产生重复支付呢?看一个真实的顾客投诉案例:『顾客购买××团的商品后,第一次付款时,由于付款故障(如系统掉单),使得顾客认为付款未成功,所以,顾客换用了其他支付渠道(如选择支付宝的网银直连,或者选择网银在线)进行了第二次付款,于是××团帐号收到两笔付款,且两笔付款均付款成功。』这不是偶然现象。处理办法还是:按时间顺序,稍晚一些的付款被认为是重复支付,进入异常支付流程(能原路退返就退,如无法退返则返还至账户余额)。?3.4. 支付成功时系统发现商品已不可售卖商品不可售卖有两个原因:1)库存不足;2)商品已下线。?如果是库存不足:团购商户为了避免超卖,应该将订单关闭,将交易关闭,将实付金额原路退返(如无法退返,退至账户余额),记录支付失败日志,记录资金变动日志,标记退返原因是“库存不足”,顾客可以在前台账户余额变更历史中看到有过付款以及被退款的明细。如果是实物类电商商户,因为可以事后干预,补足库存,所以可以接受这次付款行为。?如果是商品已下线,处理方式同上,只不过要标记退返原因是“商品已下线”。?3.5. 订单名称中不能包含敏感词支付宝对商品标题核查得非常严格,所以郑昀郑重提醒您,为了避免顾客发起支付时看到支付宝如下警告:请提前调用参数参数名称类型参数说明是否可为空样例out_trade_no商户网站唯一订单号String(64)支付宝合作商户网站唯一订单号,并非支付宝交易流水号(确保在合作伙伴系统中唯一)。不可空58942120-tuan-001商户完全可以自定义这个 out_trade_no 的字符串组成规则。即使对应同一个订单,也可以构造出不同的 out_trade_no 。只要当支付宝的交易通知把这个参数原样返回时,你的程序能知道这是哪一个订单的哪一笔交易,它的应付金额是多少,这个应付金额被支付后订单产生什么变化,这样就行。下面举几个例子。?例一:修改订单,订单应付金额或支付方式发生变化背景:订单在没有支付成功之前,顾客都是可以修改的。做了以下修改后,可能会引起订单应付金额或支付方式发生变化:余额支付的金额变化购买份数的调整优惠券/代金券的使用而支付宝等第三方支付,对于一个用商户唯一订单号标识的交易,禁止变更 total_fee(交易总金额)字段!所以,我们的同一个订单,发起不同应付金额的支付请求时,必须更换 out_trade_no ,流程如下图4.2所示:
图4.2 订单应付金额变化,out_trade_no 必须变化?例二:修改订单,订单支付方式发生变化背景:订单未成功支付前,用户也是可以调整支付方式的:支付方式的调整(不仅仅指从支付宝变为快钱这种第三方支付之间的变更,而且包括从支付宝之网银直连变为支付宝这种第三方支付内部变更)此时,建议更换 out_trade_no 。?例三:订单已付款,但追加一部分商品,需要补支付背景:选择了菜品1、2、3、4的订单已支付成功,顾客追加菜品5,不需要创建新订单,可以在原订单基础上补充支付。做法:如下图4.3所示
图4.3 订单补支付?4.3. 对账拉单无论系统是否可靠,商户终归还是要对账的。对的就是数据库里记录的当天应收帐款,与第三方支付商户帐号里收到的钱是否吻合。如果你数据库记录的顾客用支付宝支付的款项是10001元,而你的支付宝帐号里只收到了10000元,那一定有问题,必须要深究下去。?核对的办法就是,每天零点,从数据库里查询出前一日用支付宝支付的所有交易,得到支付宝交易流水号和支付金额的集合;遍历这个集合,拿交易流水号去支付宝的单笔交易查询接口(single_trade_query),这样查出交易金额,对比一下,看你数据库里记的支付金额和实际收到的交易金额是否一致。?@郑昀汇总于2012/111)电商课题I:Throttle Limits for calls/requests in a clustered environment