admin-order-status-api.md 9.1 KB

API Contract: 平台订单状态受控调整

Base path: /system/order Authentication: RuoYi 管理后台 Bearer token Permission: system:order:edit Content-Type: application/json

1. Common Conventions

1.1 Response envelope

沿用 AjaxResult

{
  "code": 200,
  "msg": "操作成功",
  "data": {}
}

业务校验、状态冲突或网关失败沿用项目约定返回非 200 的业务 code 与安全错误消息。前端不得只根据 HTTP 状态推断业务成功。

1.2 Snapshot fields

所有写操作必须携带弹窗打开时的四状态快照:

{
  "expectedState": 2,
  "expectedDeliveryStatus": 2,
  "expectedPayStatus": 1,
  "expectedAfterSaleStatus": 0,
  "reason": "骑手端漏操作"
}

reason trim 后 1~200 字。expectedDeliveryStatus 可为 null,其他快照字段必填。

1.3 Conflict behavior

如果订单在上下文读取后被回调、骑手、定时任务或另一管理员更新:

{
  "code": 500,
  "msg": "订单状态已变化,请刷新后重试"
}

冲突请求不得产生订单、账单、积分、日志或推送副作用。

2. Get Status Context

GET /system/order/{id}/status-context

读取修改弹窗所需的最小数据和服务端能力。

Response:

{
  "code": 200,
  "data": {
    "id": 123,
    "ddId": "202608100001",
    "type": 0,
    "payType": "7",
    "state": 2,
    "deliveryStatus": 2,
    "payStatus": 1,
    "afterSaleStatus": 0,
    "sdTime": null,
    "riderAssigned": true,
    "allowedOrderStates": [2],
    "allowedDeliveryStatuses": [2, 3],
    "canConfirmOfflinePayment": false,
    "canConfirmOfflineRefund": false,
    "canReconcileOmg": false,
    "canRefundOmg": true,
    "canConfirmManualOmgRefund": false,
    "omgPaymentStatus": 1,
    "manualRefundPending": false,
    "refundUnknown": false
  }
}

规则:

  • allowed* 至少包含当前值,终态只有当前值;
  • 自取/堂食 allowedDeliveryStatuses=[]
  • OMG 无流水时 omgPaymentStatus=null 且所有 OMG 写能力为 false;
  • 能力字段只控制显示,不能作为后端授权依据。

3. Update Order or Delivery Status

PUT /system/order/{id}/status

Annotations: @PreAuthorize(system:order:edit)@RepeatSubmit

Request:

{
  "expectedState": 2,
  "expectedDeliveryStatus": 2,
  "expectedPayStatus": 1,
  "expectedAfterSaleStatus": 0,
  "targetState": null,
  "targetDeliveryStatus": 3,
  "reason": "骑手已实际送达,客户端漏操作"
}

至少一个目标字段非空且与当前值不同。未提交的目标字段保持不变。

Success response: 返回最新状态上下文。

{
  "code": 200,
  "msg": "修改成功",
  "data": {
    "id": 123,
    "state": 3,
    "deliveryStatus": 3,
    "payStatus": 1,
    "afterSaleStatus": 0,
    "sdTime": "2026-08-10 11:30:00"
  }
}

Validation

  • targetState 只能是 0~4;targetDeliveryStatus 只能是 0~3;
  • 只能执行 data-model.md 中的下一步转换;
  • 非外送不得提交配送目标;
  • 配送到 1/2/3 要求已有骑手;
  • 完成要求已支付且无售后;
  • 已支付取消返回“请使用退款操作”;
  • 送达自动同步完成和送达时间;客户端不能提交 sdTime

4. Confirm Offline Payment

POST /system/order/{id}/offline-payment/confirm

Request: Common snapshot fields only.

{
  "expectedState": 2,
  "expectedDeliveryStatus": null,
  "expectedPayStatus": 0,
  "expectedAfterSaleStatus": 0,
  "reason": "门店确认已收到现金"
}

Allowed:

  • payType="1"
  • payStatus=0
  • state 不是 3/4;
  • afterSaleStatus=0

Result: 只把 payStatus 改为 1,不创建 OMG/历史在线支付流水,不自动完成订单。

5. Confirm Offline Refund

POST /system/order/{id}/offline-refund/confirm

此操作代表管理员已经在线下实际退回款项,前端必须先显示不可逆二次确认。

Request:

{
  "expectedState": 1,
  "expectedDeliveryStatus": null,
  "expectedPayStatus": 1,
  "expectedAfterSaleStatus": 0,
  "reason": "门店无法履约,已现场退还现金"
}

Allowed:

  • payType="1"
  • payStatus=1
  • state!=3
  • afterSaleStatus=0

Atomic result:

{
  "state": 4,
  "payStatus": 2,
  "afterSaleStatus": 3
}

订单使用积分时调用现有幂等积分返还逻辑。已完成订单返回“已完成订单需结算冲正,本期不支持退款”。

6. Reconcile OMG Payment

POST /system/order/{id}/omg-payment/reconcile

Request: Common snapshot fields.

Allowed:

  • payType="7"
  • payStatus=0
  • state!=4
  • 存在最新 OMG 支付流水且流水可查询。

Behavior:

  1. 复用 reconcileByQuery(ddId, "admin")
  2. 校验 OMG 返回交易状态、交易号、金额和日期;
  3. 只有真实已支付时通过流水 CAS 和订单 CAS 核销;
  4. 未支付、失败、未知或字段不符时不得写 order.payStatus=1
  5. 回调和补单并发只执行一次支付副作用。

Paid response:

{
  "code": 200,
  "msg": "OMG 支付核验成功",
  "data": {
    "payStatus": 1,
    "reconciled": true
  }
}

Still unpaid response:

{
  "code": 200,
  "msg": "OMG 尚未确认支付",
  "data": {
    "payStatus": 0,
    "reconciled": false
  }
}

金额/订单信息不一致返回错误并写系统核对日志,不向前端返回原始网关报文。

7. Refund OMG Payment

POST /system/order/{id}/omg-refund

前端必须显示不可逆二次确认。

Request: Common snapshot fields.

Allowed:

  • payType="7"
  • payStatus=1
  • state!=3
  • afterSaleStatus=0
  • 最新 OMG 流水为已支付,金额和订单一致。

Outcomes

Automatic refund succeeded

{
  "code": 200,
  "msg": "退款成功",
  "data": {
    "outcome": "REFUNDED",
    "state": 4,
    "payStatus": 2,
    "afterSaleStatus": 3
  }
}

Manual refund required

{
  "code": 200,
  "msg": "该支付方式需在 OMG 后台人工退款,订单暂保持已支付",
  "data": {
    "outcome": "MANUAL_PENDING",
    "payStatus": 1,
    "manualRefundPending": true
  }
}

重复调用不重复新增人工待办。

Result unknown

{
  "code": 500,
  "msg": "OMG 退款结果待确认,请勿重复发起",
  "data": {
    "outcome": "UNKNOWN",
    "payStatus": 1,
    "refundUnknown": true
  }
}

OMG 流水保持退款中,后续请求不得再次调用网关。

Explicit failure

{
  "code": 500,
  "msg": "OMG 退款失败,请核对后重试",
  "data": {
    "outcome": "FAILED",
    "payStatus": 1
  }
}

错误消息不包含 HashKey、HashIV、完整响应或堆栈。

8. Confirm Manual OMG Refund

POST /system/order/{id}/omg-refund/manual-confirm

此接口只用于支付方式不支持 OMG 退款 API、平台管理员已经在 OMG 后台核实退款完成的场景。前端必须进行不可逆二次确认。

Request: Common snapshot fields;reason 必须说明人工退款核实依据。

Allowed:

  • payType="7"、订单 payStatus=1state!=3afterSaleStatus=0
  • 最新 OMG 流水属于不支持自动退款的支付方式;
  • 同一支付流水存在 action=NULL, rtnCode=NULL 的未决人工待办;
  • 不存在 action=NULL, rtnCode=1 的人工完成记录。

Behavior:

  1. 管理员二次确认;
  2. OMG 支付流水复用现有 CAS 执行 1→4→3,不调用网关;
  3. 插入 action=NULL, rtnCode=1 的人工退款完成记录,rtnMsg 标明管理员确认;
  4. 同步 state=4, payStatus=2, afterSaleStatus=3
  5. 写管理员操作日志,包含管理员、前后状态和原因。

Response:

{
  "code": 200,
  "msg": "已确认 OMG 人工退款完成",
  "data": {
    "outcome": "REFUNDED",
    "state": 4,
    "payStatus": 2,
    "afterSaleStatus": 3,
    "manualRefundPending": false
  }
}

无待办、已完成订单、流水状态变化或重复确认均不得产生新的退款记录或业务副作用。

9. Legacy Endpoint Hardening

PUT /system/order

继续保留历史非状态编辑能力,但请求含以下任意字段时拒绝:

  • state
  • deliveryStatus
  • payStatus
  • afterSaleStatus
  • sdTime

Response:

{
  "code": 500,
  "msg": "订单状态请使用状态专用操作"
}

state=7/12kefuState→state=5 等逻辑必须删除。

10. Forbidden Payload Fields

新状态接口 DTO 不声明并不得使用以下字段:

amount, userId, shId, mdId, food, freight, points,
payType, type, qsId, sdTime, payStatus, afterSaleStatus

其中 expectedPayStatusexpectedAfterSaleStatus 仅作为旧快照,不是目标值。服务端必须从数据库读取订单类型、支付类型、金额、骑手和业务标识。

11. Audit Requirements

每次实际改变数据的管理员操作写一条 operatorType=1 的同步订单日志,包含:

  • 管理员 ID/名称;
  • 动作类型;
  • 四状态前后值;
  • 管理员原因;
  • 服务端时间。

相同目标的幂等请求不重复写成功日志。OMG 补单/退款还保留现有 operatorType=0 系统资金日志。