3. 支付订单核心状态定义

支付订单状态机是整个聚合支付系统的核心骨架。状态定义是否清晰,直接决定了后续交易处理、对账、退款、风控等模块的复杂度和可靠性。本节将定义六个核心状态:待支付、支付中、支付成功、支付失败、已退款、已关闭,并给出每个状态的准入条件、业务含义和典型停留时长。

3.1 六状态总览

状态名称 状态码 业务含义 典型停留时长 是否终态
待支付 PENDING 订单已创建,等待用户发起支付 15分钟~24小时(超时关闭) 否
支付中 PROCESSING 用户已提交支付,等待渠道异步结果 几秒~几分钟(渠道超时) 否
支付成功 SUCCESS 渠道确认资金已划转完成 长期(可发起退款) 是(可退款)
支付失败 FAILED 渠道明确返回支付未成功 长期 是
已退款 REFUNDED 原支付订单已全额或部分退款 长期 是
已关闭 CLOSED 订单超时未支付或用户主动取消 长期 是
设计要点:“支付成功”虽然是终态,但允许通过退款操作转移到“已退款”状态。在状态机建模中,这种“终态但可转移”的设计需要特殊处理,通常通过子状态机或补偿事件来实现。

3.2 状态转换关系

六个状态之间的合法转换路径如下:

  • 待支付 → 支付中:用户点击支付按钮,系统向渠道发起支付请求。
  • 待支付 → 已关闭:用户主动取消,或订单超过支付有效期。
  • 支付中 → 支付成功:渠道异步通知或轮询确认支付成功。
  • 支付中 → 支付失败:渠道明确返回失败,或超时未收到确认。
  • 支付中 → 待支付:渠道返回需要用户重新操作(如密码错误、卡信息错误)。
  • 支付成功 → 已退款:用户发起退款,系统完成退款流程。
  • 支付成功 → 支付失败:极少见,如渠道后续对账发现该笔交易实际失败,需人工介入。
关键约束:“支付中”状态不允许直接跳转到“已关闭”。如果用户在支付中阶段取消订单,系统必须先等待渠道结果,再根据结果决定进入“支付成功”或“支付失败”,最后再执行关闭逻辑。这是防止资金丢失的重要设计。

3.3 状态机 SVG 图

下图展示了六个核心状态及其合法转换关系。图中使用不同颜色区分初始态、中间态和终态,箭头上的标签表示触发事件。

支付订单核心状态机 支付订单核心状态机 待支付 PENDING 支付中 PROCESSING 支付成功 SUCCESS 支付失败 FAILED 已退款 REFUNDED 已关闭 CLOSED 发起支付 超时/取消 异步通知成功 渠道返回失败 需重新操作 发起退款 对账异常(极少) 初始态 中间态 终态 失败终态 非常规路径

3.4 状态定义详细说明

3.4.1 待支付 (PENDING)

  • 创建时机:用户提交订单后,系统生成支付记录。
  • 数据要求:订单号、金额、支付方式、渠道ID、商户ID、商品描述。
  • 超时策略:通常设置15~30分钟超时,超时后自动进入“已关闭”。
  • 幂等性:同一订单不可重复发起支付,需做防重校验。

3.4.2 支付中 (PROCESSING)

  • 进入条件:系统已向渠道发送支付请求,等待异步回调。
  • 风险点:渠道超时、网络闪断、回调丢失。
  • 补偿机制:系统需启动定时轮询或重试任务,防止订单卡在“支付中”。
  • 用户感知:前端应展示“支付处理中,请稍候…”并禁用重复提交。

3.4.3 支付成功 (SUCCESS)

  • 确认方式:渠道异步通知优先,轮询结果作为兜底。
  • 后续动作:触发商户通知、发货、积分赠送、对账记录生成。
  • 退款能力:支持全额或部分退款,退款后进入“已退款”。

3.4.4 支付失败 (FAILED)

  • 失败原因:余额不足、风控拦截、渠道系统异常、卡信息错误。
  • 用户提示:需明确展示失败原因,引导用户重新支付。
  • 重试策略:允许用户从“支付失败”重新发起,此时新建一笔支付订单。

3.4.5 已退款 (REFUNDED)

  • 触发条件:用户申请退款或商户主动退款。
  • 退款类型:全额退款、部分退款(需记录退款金额和剩余金额)。
  • 对账要求:退款记录必须与渠道退款流水一一对应。

3.4.6 已关闭 (CLOSED)

  • 触发条件:用户主动取消、超时未支付、风控拒绝。
  • 不可逆:关闭后不可再发起支付,需重新下单。
  • 资源释放:释放预占的库存、优惠券、积分等资源。

3.5 状态定义常见误区

避坑指南:
  • 误区一:将“支付中”视为临时状态,不记录日志。→ 正确做法:支付中状态必须记录完整的请求和响应日志,用于对账和问题排查。
  • 误区二:允许“支付中”直接跳转到“已关闭”。→ 正确做法:必须先等待渠道结果,再决定最终状态。
  • 误区三:“支付成功”后不允许任何状态变更。→ 正确做法:保留“支付成功→已退款”的合法路径。
  • 误区四:状态码使用数字而非枚举。→ 正确做法:使用有语义的字符串枚举,便于扩展和排查。

3.6 状态定义检查清单

在实际项目中,建议使用以下清单验证状态定义是否完整:

  1. 每个状态是否有明确的进入条件和退出条件?
  2. 是否存在无法到达的“孤儿状态”?
  3. 所有终态是否都有对应的业务处理逻辑?
  4. 状态转换是否覆盖了所有异常场景(超时、重试、取消)?
  5. 状态变更是否都有审计日志记录?
  6. 状态机是否支持未来扩展(如部分退款、部分关闭)?
最佳实践:在项目初期,将状态定义以状态机图的形式固化到技术文档中,并作为代码评审的必查项。每次新增状态或转换路径,都需要更新状态机图并通知相关团队。