订单状态怎么设计:别用一个字段装所有情况
订单状态越加越多,最后没人说得清某个值代表什么。本文说明状态机该怎么划分、支付与发货为什么要分开记,以及异常状态的处理。
- 一个字段装支付、履约、售后多个维度,会导致状态值组合式增长。
- 拆成独立的支付、履约、售后状态,对外展示时再合成给用户看的说法。
- 必须明确每个状态能转到哪些状态,非法流转直接拒绝而非静默执行。
- 每个可能失败的环节都要有对应的异常状态并进入人工队列,否则订单会静默卡住。
- 状态变更日志单独成表、只追加,它在客诉与对账时比当前状态更有价值。
订单状态字段的典型演化:一开始是待付款、已付款、已发货、已完成四个值。然后加了已取消、退款中、已退款、部分退款、待审核、已关闭 —— 两年后字段里有二十多个值,新人看代码时无法判断某两个状态能不能互相转换。
问题在于一个字段装了多个维度
「已付款」说的是支付状态,「已发货」说的是履约状态,「退款中」说的是售后状态。它们是可以同时存在的 —— 一笔订单可以同时是已付款、已发货、退款中。强行塞进一个字段,就必须为每种组合造一个新值,于是值的数量成组合式增长。
更清晰的做法是拆成几个独立字段:支付状态、履约状态、售后状态,各自有自己的取值和流转规则。对外展示时再按业务规则合成一个给用户看的说法。
流转要有约束
- 明确每个状态能转到哪些状态,非法流转直接拒绝而不是静默执行;
- 状态变更要带操作人与原因,系统自动变更也要记录是哪个任务触发的;
- 并发变更要加锁或用乐观锁,两个客服同时操作同一订单是真实会发生的;
- 终态要明确:已完成、已关闭之后不应再变化,需要变化说明状态划分有问题。
异常状态要显式存在
支付回调处理失败、发货接口超时、退款被拒 —— 这些情况如果没有对应的状态,订单就会停在某个中间值,看起来一切正常,实际上卡住了。应当有明确的异常状态并进入人工处理队列。
判断办法是:列出所有可能失败的环节,每一个都问「失败后订单是什么状态、谁会知道」。答不上来的就是会卡住的地方。
变更日志比当前状态更有价值
当前状态只有一个值,而客诉处理、对账、退款争议需要的是完整过程:什么时候付的款、什么时候发的货、谁在什么时候改成了已完成。这份日志应当单独成表、只追加不修改。
它的另一个作用是排查:订单状态异常时,日志能直接显示是哪一步出的问题,而不需要去翻应用日志。相关设计见电商网站 / 商城定制。状态机定义应当写进接口文档并随项目交付,安排见合作流程。
常见问题
订单状态为什么越加越多?
因为一个字段同时表达了支付、履约、售后多个维度,而这些维度可以并存——一笔订单可以同时是已付款、已发货、退款中。每出现一种组合就要新增一个值,数量于是组合式增长。拆成多个独立字段可以从根本上解决。
订单卡在中间状态怎么办?
根本办法是让每个可能失败的环节都有对应的异常状态,并自动进入人工处理队列。设计时逐一列出可能失败的步骤,对每一步追问失败后订单处于什么状态、谁会知道,答不上来的就是会静默卡住的地方。
需要记录订单状态变更历史吗?
需要,而且应当单独成表、只追加不修改,记录时间、操作人和原因。当前状态只有一个值,而客诉处理、对账和退款争议需要的是完整过程。这份日志同时也是排查状态异常最直接的依据。
参考资料
- 支付宝开放平台文档 · 支付宝开放平台
- WooCommerce Documentation · WooCommerce