`
zhengyun_ustc
  • 浏览: 82872 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

电商课题VII:支付交易一般性准则

阅读更多

@郑昀汇总 创建于2012/11

发布版本号:v1.3
概念:
退款期限,交易,交易关闭,交易结束,掉单,幂等性,数据一致性
 
关键词:
历史记录不得直接篡改原则,
交易关闭通知处理,退款处理结束通知,
掉单被动处理,掉单主动处理,
多个渠道的重复支付处理,
支付成功时商品不可售卖的处理,
订单金额变化交易流水号变化规则,
推送订单不得包含违禁词,
支付通知并发到达的处理,
支付子系统的独立性和可靠性,
补录数据的时间准则

一. 通用规则
1.1. 历史记录不得直接篡改
电商核心服务基本都是分布式应用,分布式事务如处理不妥善,容易产生数据不一致。一旦出现数据不一致,一定要有旁证来修正。
所以数据库中以下关键资源的记录,郑昀提醒您注意,原则上不允许直接修改历史数据
  • 下单;
  • 支付购买;
  • 生码/验码/物流信息记录;
  • 退款(含部分退款);
  • 结算;
  • 用户注册;
  • 与第三方数据同步;
这里的“直接修改”特指,没有把变更行为记录到日志表里,而是直接在原始记录上 update 甚至 delete ,这种“篡改”和“毁尸灭迹”是明文禁止的,即使留下了文件类型日志也是不允许的。
第一,要修改这些记录的关键字段时,必须在相关日志表里保留变更日志,并记录操作人和发起人,一定要确保历史可回溯
第二,严禁对记录做物理删除,只能是软删除。
 
实例:
对于××团收到第三方支付的通知,我们有第三方交易流水记录表;
对于××团发起的到第三方支付的交易请求。我们有 jxxxe_pay_log 记录;
订单操作变更记录,我们有 jxxxe_order_action日志表记录。
 
Q:什么叫历史可回溯?
A:系统可能对关键记录做了一系列修改,甚至有程序在某个时间段内误写引入了脏数据,但郑昀提示您,我们依然要能从各种操作日志表中随时倒推回历史某一个时刻的快照,一是确保随时能安全地把数据还原回去,二是管理平台可以清晰地展示出由谁引发、怎么变化的历史,三是便于排查问题。
譬如,对于记录了订单信息的 order_info 表,会员如果点击使用账户余额支付了订单的应付金额,那么该订单操作日志表就会做如下记录,原订单记录的重要字段(what)在什么时候(when)从什么变为了什么(how),都会详细记录。
 
1.2. 对关键资源的操作,当接口保证不了幂等性时,必须能防并发
如果你的接口不具备幂等性,那么请保证整个(分布式)系统内对一个重要事物(订单,账户的资金变动等)的有效操作线程同一时间内有且只有一个
比如交易中心有N台服务器负载均衡,订单中心则有M台服务器,如何保证一个订单的同一笔支付处理,一个账户的同一笔资金变动操作是原子性的。
 
原因也很简单:
  • 第三方支付平台可能同一时刻给你的 pay.5xxxxn.com 交易中心集群服务推送过来两个一模一样的支付成功通知。
  • 用户浏览器可能安装了某种插件(如早期的迅雷插件),插件本身为了探测 一个URL 是否是BT资源,会同时模拟发起一个 HTTP GET 请求。
  • 上游服务不可控,不可预知地向发起下游服务发起并发请求。
 
此时可以基于 memcache 实现一个分布式锁,更多详情请阅读郑昀撰写的《电商课题:分布式锁》。
 
1.3. 支付子系统的独立性
电商业务容易出现以下问题:
  • 受到DDoS攻击,带宽被打满;
  • 某一个业务突然响应变慢,如从20ms激增为1s,业务请求被大量阻塞;
所以不同业务之间必须严格隔离,防止一个业务超负荷或宕机连累其他业务。
因此,我们至少要做到:
  • 支付子系统是一个独立工程,独立部署,有单独的二级域名。
最好能做到:
  • 独立带宽,
  • 独立的存储介质。
 
1.4. 支付子系统接收第三方支付通知的可靠性
电商的支付子系统提供一个 Web Service,来接收各家第三方支付的各种异步通知。
接收对方通知之后,你可能会遭遇各种异常,如:
  • 解析时发生异常;
  • 调用支付中心时发生异常,如网络故障,如支付中心宕机,如调用超时;
  • 写日志时发生异常;
即使如此,你也不应该丢弃该通知,并且没有返回“success”字符给第三方支付,
因为这样的话,相当于你的业务完全依赖于第三方支付下一次重试了。
所以,郑昀提醒您,你应该主动地、积极地先把对方的(支付成功、退款处理等)通知存入一个存储介质,如消息队列;
一旦同步处理失败,那么能以某种策略重播这个消息,直到业务系统恢复正常、处理完毕为止。
 
1.5. 补录数据的时间准则
电商结算和对账,由于帐期定义(如日清日结,如T+2结算,如销售佣金计算,如CPS联盟结算),非常依赖于数据记录的时间。
所以,当由于以下原因补录或同步数据时,请慎重考虑数据的时间字段到底如何采信
  • 掉单后主动处理(注:主动查询第三方支付网关,获得订单支付状态);
  • 不同系统之间同步失败后手动触发重新同步;
  • 不同公司的平台之间交换退款等数据。
 
下面举两个小例子:
例一:
××商城对供应商的结算标准是,仅仅以订单进入他们的ERP系统的时间为准,而不是以该订单的下单时间、支付时间等数据自身时间记录为准。
即,一个12月1日23:58支付成功的订单,数据一层一层传递到ERP时,同步时间是12月2日00:01,那么此订单就被判定在12月2日的应结算明细中,而不是12月1日的。
咋听上去好像不合理,仔细想想,供应商有很多,IT系统也就很多,彼此之间的服务器时间肯定不同步,更别提会有很多种类型的脏数据,所以××商城只有选择用ERP系统自身的时间作为唯一结算凭据,而不采信第三方系统的 add_time、update_time、pay_time 五花八门的时间,这样才不会重复结算或漏结算。
 
例二:
支付系统宕机,一段时间后才恢复,此时客服主动处理顾客投诉掉单的订单,从第三方支付查到已支付后,将订单置为已付款。那么,该订单的支付时间怎么记呢?
一是,采信第三方支付系统传递的真实支付时间。二是,记录为手动重置的当前时间。
郑昀的答案是,后者更安全。
因为,有可能补录数据已跨日或跨月,前一日的结算清单可能已计算完毕,如果按前者的逻辑,突然又补录一条记录,结果前一日(上一个月)也不结算它,后一日(下一个月)也不结算,那这个订单就漏结算了。
当然,真实支付时间也还是要记录到日志表的。
 

二. 易被忽略的逻辑处理
2.1. 交易关闭通知的处理
支付宝是这么定义“交易关闭”的:
枚举名称
枚举说明
TRADE_CLOSED
  • 指定时间段内未支付时关闭的交易;
  • 在交易完成全额退款成功时关闭的交易。
交易关闭通知默认是不发送的,如下表格所示:
触发条件名
触发条件描述
触发条件默认值
TRADE_CLOSED
交易关闭
false(不触发通知)
如果商户(也就是你的网站)向支付宝申请打开了该配置,那么请注意接收 TRADE_CLOSED 通知,它会对你的核心购买逻辑产生影响。
 
如何主动指定交易关闭时间呢?
即时到帐交易接口中有这么一个参数:
参数
参数名称
类型
参数说明
是否可为空
样例
it_b_pay
超时时间
String(3)
设置未付款交易的超时时间,一旦超时,该笔交易就会自动被关闭。
取值范围:1m~15d。
m:分钟、h:小时、d:天、1c:当天(无论交易何时创建,都在0点关闭)。
该功能需要联系技术支持来配置关闭时间。
可空
1h
支付宝收到这个参数后,界面会有如下展示:
http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clip_image001%20-%20001%E5%89%AF%E6%9C%AC.jpg
 
此时提示几点:
1)如果交易已经关闭,但商户的网站上仍保留了订单的“付款”按钮,那么点击跳转到支付宝后,会看到如下警告信息:
http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/r_clip_image002%20-%20002%e5%89%af%e6%9c%ac.jpg  
http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/r_clip_image002%20-%20003%e5%89%af%e6%9c%ac.jpg
2)当交易状态为交易关闭时,就算用户能通过第三方网银对支付宝账单进行付款(用户可能已经跳转至银行交易页面,并且未关闭页面),第三方网银能将支付成功信息通知支付宝,支付宝也不会通知商户,而是会自动退还至支付宝余额中。
3)网银直连的订单是关闭不了的,因为它没有跟支付宝账户绑定。
4)商户如发现交易已关闭的订单被用户支付后,那么必须进入异常支付流程(能原路退返就退,如无法退返则返还至账户余额)。
 
2.2. 退款通知的处理
支付宝对此的定义是:
(1) 交易成功之后,商户(高级即时到账或机票平台商)可调用批量退款接口,系统会发送退款通知给商户。
(2) 当商户使用站内退款时,系统会发送包含 refund_status(退款状态)和 gmt_refund(退款时间)字段的通知给商户。
其中退款状态有两种:
枚举名称
枚举说明
REFUND_SUCCESS
退款成功:
  • 全额退款情况:trade_status= TRADE_CLOSED,而refund_status=REFUND_SUCCESS
  • 非全额退款情况:trade_status= TRADE_SUCCESS,而refund_status=REFUND_SUCCESS
REFUND_CLOSED 退款关闭
第三方支付在退款处理完毕后,会发送异步通知给商户,如下表格所示:
触发条件名
触发条件默认值
退款处理结束
true(触发通知)

这个所谓退款处理结束通知,实际上仍是一个“trade_status_sync(交易状态同步)”通知,特殊性在于携带的 refund_stauts =REFUND_SUCCESS 参数,实际例子如下所示:

http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/r_clipboard%20-%20004%e5%89%af%e6%9c%ac.png  
注意几个要点:
  1. 当交易状态为 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. 订单名称中不能包含敏感词
    支付宝对商品标题核查得非常严格,所以郑昀郑重提醒您,为了避免顾客发起支付时看到支付宝如下警告:
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/r_clip_image002%20-%20005%e5%89%af%e6%9c%ac.jpg  
    请提前调用 支付宝交易信息敏感词分析接口(fast_text_trade) ,在录入信息时就阻止保存。
    注意,此敏感词分析接口需要联系支付宝开通权限。
     

     
    四. 正常支付流程的两个要点
    4.1.正常支付的处理流程
    对于一个团购商品来说,顾客的正常支付成功通知到达服务器端时,业务规则简述为:
    1. 商品活动结束后,所有未付款订单,一律不允许支付。
    2. 必须符合库存管理规则。
    3. 本次支付金额应该小于等于该订单的待支付金额。
    4. 订单状态正常(不能处于“已取消”、“已付款”等状态)。

    一旦发现违背业务规则的支付成功通知到达,则:

    1. 并不修改订单状态;
    2. 将此笔支付款项自动返还到该会员的账户余额里
    3. 支付中心记录支付失败日志;并记录资金变动日志;
    4. 会员在前台“个人中心”下的“账户余额”里能看到这个余额变更历史以及对应的说明。

    支付流程图如下图4.1所示:

     

    图4.1 团购支付中心判断的简单流程

     
    4.2. 交易流水号变化规则
    商户发给第三方支付的 out-trade-no 标识了一次交易的商户唯一订单号
    该参数的定义为:
    参数
    参数名称
    类型
    参数说明
    是否可为空
    样例
    out_trade_no
    商户网站唯一订单号
    String(64)
    支付宝合作商户网站唯一订单号,并非支付宝交易流水号
    (确保在合作伙伴系统中唯一)。
    不可空
    58942120-tuan-001
    商户完全可以自定义这个 out_trade_no 的字符串组成规则
    即使对应同一个订单,也可以构造出不同的 out_trade_no 。
    只要当支付宝的交易通知把这个参数原样返回时,你的程序能知道这是哪一个订单的哪一笔交易,它的应付金额是多少,这个应付金额被支付后订单产生什么变化,这样就行。
    下面举几个例子。
     
    例一:修改订单,订单应付金额或支付方式发生变化
    背景:订单在没有支付成功之前,顾客都是可以修改的。做了以下修改后,可能会引起订单应付金额或支付方式发生变化:
    • 余额支付的金额变化
    • 购买份数的调整
    • 优惠券/代金券的使用
    而支付宝等第三方支付,对于一个用商户唯一订单号标识的交易,禁止变更 total_fee(交易总金额)字段!
    所以,我们的同一个订单,发起不同应付金额的支付请求时,必须更换 out_trade_no ,流程如下图4.2所示:
        http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard%20-%20006%E5%89%AF%E6%9C%AC.png
    图4.2 订单应付金额变化,out_trade_no 必须变化
     
    例二:修改订单,订单支付方式发生变化
    背景:订单未成功支付前,用户也是可以调整支付方式的:
    • 支付方式的调整(不仅仅指从支付宝变为快钱这种第三方支付之间的变更,而且包括从支付宝之网银直连变为支付宝这种第三方支付内部变更)
    此时,建议更换 out_trade_no 。
     
    例三:订单已付款,但追加一部分商品,需要补支付
    背景:选择了菜品1、2、3、4的订单已支付成功,顾客追加菜品5,不需要创建新订单,可以在原订单基础上补充支付。
    做法:如下图4.3所示
      http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard%20-007%20%E5%89%AF%E6%9C%AC.png
    图4.3 订单补支付
     
    4.3. 对账拉单
    无论系统是否可靠,商户终归还是要对账的。
    对的就是数据库里记录的当天应收帐款,与第三方支付商户帐号里收到的钱是否吻合。
    如果你数据库记录的顾客用支付宝支付的款项是10001元,而你的支付宝帐号里只收到了10000元,那一定有问题,必须要深究下去。
     
    核对的办法就是,
    每天零点,从数据库里查询出前一日用支付宝支付的所有交易,得到支付宝交易流水号和支付金额的集合;
    遍历这个集合,拿交易流水号去支付宝的单笔交易查询接口(single_trade_query),这样查出交易金额,对比一下,看你数据库里记的支付金额和实际收到的交易金额是否一致。
     
    @郑昀汇总于2012/11
     

    赠图几枚:
    分享到:
    评论

    相关推荐

      ADC架构VII:计数ADC.pdf

      在这些应用场景中,信号变化缓慢,对高速处理要求不高,因此计数ADC可以提供良好的测量精度和稳定性。不过,对于需要处理高速信号的应用,如视频处理和高速数据采集,其他类型的ADC,如Flash型或逐次逼近型ADC,可能...

      The development of intelligent behavior VII: Irving E. Sigel

      The development of intelligent behavior VII: Irving E. Sigel T H E DEVELOPMENT OF INTELLIGENT BEHAVIOR VII : IRVING E. SIGEL’ G . THOMAS ROWLAND New York University and CARSON MCGUIRE The ...

      vii:使用JavaScript创建CSS3动画

      ## vii.js:使用Javascript创建CSS3动画## 请注意,vii.js不是您包含在项目中的库。 是用于生成CSS3动画代码的工具。 因此是这样的: vii.k('n:myTween d:1 e:swing kf:0 x:0%op:1 | kf:100 x:500%op...

      fdps-vii:使用 Spark V2 进行快速数据处理的代码和数据

      【标题】"fdps-vii:使用 Spark V2 进行快速数据处理的代码和数据"涉及的核心技术是Apache Spark V2,这是一个分布式计算框架,专为大规模数据处理设计。Spark V2相较于早期版本,提供了许多性能优化和新特性,如更...

      Labor_VII:简单的图形,3 级战斗,新概念,80 年代 EGA 风格-开源

      "Labor_VII:简单的图形,3 级战斗,新概念,80 年代 EGA 风格-开源"是一个独特的项目,它旨在利用开源精神,重现80年代的电子游戏体验,特别是那些采用EGA(Enhanced Graphics Adapter)图形标准的游戏。 EGA,全称...

      Social Media Analytics Strategy: Using Data to Optimize Business Performance

      Table of Contents Part I: Data Chapter 1: Social Media Data Chapter 2: From Data to Insights ...Part VII: The Future Chapter 18: Prescriptive Analytics Chapter 19: The Future of Social Media Analytics

      CFF Explorer VII

      CFF Explorer VII是一款功能强大的资源查看与编辑工具,主要用于对Windows可执行文件(.exe、.dll等)进行深入分析。这款软件可以帮助IT专业人士、程序员和逆向工程师探索、理解和修改应用程序的内部结构,包括资源...

      'Final Fantasy VII' Remake: Automating Quality Assurance

      为了应对这一挑战,SQUARE-ENIX在开发《最终幻想VII 重制版》时引入了一种创新的自动化QA方法,以降低支持新项目时的成本。这次演讲由Fabien Gravot,AI Lead Engineer,分享了他们在《最终幻想VII 重制版》中的自动...

      Fuji Xerox富士施乐DocuCentre-VII C7788使用说明书.pdf

      富士施乐DocuCentre-VII C7788是一款高度集成的办公设备,结合了先进的技术和广泛的兼容性,旨在提升企业的生产力和效率。通过深入理解并遵循使用说明书中的指导,用户可以充分利用其功能,实现高效的工作流程。

      A Practical Guide to Linux Commands, Editors, and Shell Programming, 4th Edition

      Table of Contents CHAPTER 1: WELCOME TO LINUX AND MACOS ...PART VII: APPENDIXES APPENDIX A: REGULAR EXPRESSIONS APPENDIX B: HELP APPENDIX C: Keeping the System Up-to-Date APPENDIX D: MACOS NOTES

      跨境电商小红书用户网购意愿研究_跨境电商平台消费者购买意愿相关论文毕业设计范文.pdf

      跨境电商小红书用户网购意愿研究 I.绪论 在当今时代,跨境电商的兴起为大众提供了更多的消费渠道和购买途径。然而,跨境网购仍然属于一种较为新颖的消费模式,了解用户网购意愿的影响因素不仅有利于消费者心理理论...

      CCIE.Routing.and.Switching.v5.0.Official.Cert.Guide.Volume.2.5th.Ed

      OCR Table of Contents ...Part VII: Final Preparation Chapter 12. Final Preparation Part VIII: Appendixes Appendix A. Answers to the “Do I Know This Already?” Quizzes Appendix B. CCIE Exam Updates

      时间同步工具

      var vii,vij:Integer; vdt:TDatetime; begin self.IdTCPClient1.Host := '127.0.0.1'; // 局域网内提供授时服务的主机IP地址 self.IdTCPClient1.Port := 1301; // 授时服务器的端口 self.IdTCPClient1.Connect()...

      本地化电子商务平台计划书.docx

      本地化电子商务平台计划书 I. 概述 随着互联网技术的迅速发展和全球化...本地化电子商务平台计划书旨在提供一个综合性的电商解决方案,满足消费者的个性化需求,提高品牌知名度和用户黏性,提高平台的经济可持续性。

      暑期初高中衔接英语语法专项练习:VII名词性从句(含答案精选.doc

      【名词性从句】是英语语法中的一个重要概念,它包括宾语从句、主语从句、表语从句和同位语从句等。在初高中衔接阶段,理解和掌握名词性从句对于提高英语水平至关重要。以下是对给定部分内容的详细解释: 1. 名词性...

      The Feudal Lands-开源

      《创世纪VII:封建领地》是一款基于经典游戏《创世纪VII:黑门和蛇岛》的开源重制项目。这个项目旨在对原作进行改进和扩展,以提供更加丰富和完整的游戏体验。开源软件的概念在此项目中得到了充分体现,意味着游戏的...

      《101 Windows Phone 7 Apps》上册

      本书包含完整的101个Windows Phone 7应用程序的实例,每一个小节都讲述如何利用某个知识...Part VII: Touch & Multi-Touch Part VIII: Accelerometer 感谢作者——微软的Adam Nathan,此书非常适合初学者学习使用。

      加拿大滑铁卢大学时间序列建模课程教材 part1

      PART VII: MULTIPLE INPUT-SINGLE OUTPUT MODELS CHAPTER 16: CAUSALITY CHAPTER 17: CONSTRUCTING TRANSFER FUNCTION-NOISE MODELS CHAPTER 18: FORECASTING WITH TRANSFER FUNCTION-NOISE MODELS PART VIII: ...

    Global site tag (gtag.js) - Google Analytics