支付系统真正难的是订单状态闭环

我做支付相关系统时,最早改变的一个判断是:支付不是一个按钮,也不是一个渠道 SDK。
前端看到的是收银台、二维码、H5 跳转或 JSAPI 调起;业务看到的是订单有没有收款、能不能退款、状态准不准;系统真正要负责的,是把商户、订单、支付渠道、回调、退款和后台管理连成一个状态闭环。
只要这个闭环不清楚,支付页面再顺,后台也会很快陷入解释不清的状态:用户说付了,系统说没付;渠道回调到了,订单没有更新;退款发起了,后台不知道是否成功。
收银台只是入口
支付系统里,收银台是最容易被看见的部分。
它要根据订单展示金额、说明和可用支付方式,再把用户带到微信 H5、微信扫码、微信 JSAPI、支付宝 H5 或支付宝 PC 支付。但收银台本身不应该掌握太多业务判断。它更像一个稳定入口,负责把用户引导到正确渠道。
真正的业务状态要回到订单。订单需要知道属于哪个商户、金额是多少、当前状态是什么、是否发生过退款、渠道返回了什么结果。收银台可以换,渠道可以加,订单状态不能乱。
渠道差异要被包起来
微信支付和支付宝看起来都在解决“收钱”,但接口形态、签名方式、回调处理、H5/扫码/JSAPI 的参数都不一样。
如果每个控制器都直接写渠道细节,系统会很快变得难改。我更倾向于让渠道服务处理自己的复杂度:微信负责商户证书、平台证书、API v3 请求、H5/Native/JSAPI 和退款;支付宝负责 EasySDK、网页支付、手机网站支付、查询和退款。
业务层只关心同一类问题:给这个订单创建支付入口,查询这个订单结果,发起这笔退款。渠道差异留在服务层里,订单逻辑就不会被 SDK 细节绑死。
回调决定状态是否可信
支付系统最不能靠前端跳转判断结果。
用户从支付页面返回,只能说明他回来了,不能证明钱到了。真正可信的状态来自支付渠道回调和主动查询。回调进来以后,系统要确认它来自可信渠道,再找到内部订单,更新状态,并记录必要的结果。
这个过程要考虑很多边界:重复回调怎么处理,订单已经支付后再次收到通知怎么办,金额是否一致,商户是否匹配,回调失败是否能重试,后台什么时候允许人工确认。
支付闭环的质量,往往就体现在这些不顺利的情况里。
退款不是把金额减掉
退款也不是一个简单字段。
后台发起退款时,系统要知道订单原金额、已退金额、本次退款金额、渠道退款结果和当前订单状态。退款可能成功,也可能处理中,还可能失败。只在订单上写一个 refund 数字,会让后续排查很困难。
即使早期系统没有复杂到做完整退款流水,我也会把退款视为状态变化,而不是普通编辑。因为退款一旦发生,业务、财务和用户看到的订单含义都会变。
支付系统要能解释每个状态
支付系统给我留下的经验,是交易类功能不能只追求“能调起支付”。
一个可靠的支付系统,应该能回答这些问题:订单为什么是这个状态,渠道返回过什么,用户走了哪个入口,回调有没有进来,退款是否已经提交,后台看到的结果和渠道结果是否一致。
我现在看支付相关需求,会先画订单状态,再看页面。页面负责让用户完成动作,状态负责让系统能长期解释这笔交易。只要状态闭环清楚,支付系统就算第一版很轻,也有继续扩展的空间。