feat: add commerce adjustment operations

This commit is contained in:
Codex
2026-06-29 22:28:19 +08:00
parent f3577e257c
commit 9b17f25dd9
12 changed files with 1444 additions and 12 deletions

View File

@@ -1853,7 +1853,7 @@ approved/processing -> failed
- 退款通知地址由支付账户或 `submit_provider_refund.providerNotifyUrl` 配置,后端公开接收路径为 `POST /api/commerce/refunds/notify/wechat_pay?tenantId=<tenantId>``POST /api/commerce/refunds/notify/alipay?tenantId=<tenantId>`。这是支付平台回调地址Taro 前端不要主动调用。
- 退款通知只会推进已经审核/处理中的退款申请;未审核的 `requested` 退款不能被外部通知直接落账。
- 已经 `succeeded` 的退款不能再次查询或再次标记成功,避免订单退款金额重复累加。前端应按接口返回状态展示,不要假设点击后立即到账。
- 自动补偿 worker 已接入:支付漏通知和处理中退款会由后端定时查询供应商并幂等落账。资金对账已支持租户后台手工/API 导入供应商账单、微信/支付宝官方账单下载任务、查询差异差错工单处理异常订单运营台人工调整凭证复核后续继续补。生产联调时仍需保留人工确认/失败登记入口。
- 自动补偿 worker 已接入:支付漏通知和处理中退款会由后端定时查询供应商并幂等落账。资金对账已支持租户后台手工/API 导入供应商账单、微信/支付宝官方账单下载任务、查询差异差错工单处理异常订单运营台人工调整凭证复核报表。生产联调时仍需保留人工确认/失败登记入口。
### 租户后台资金对账
@@ -2057,6 +2057,112 @@ ignored 无效行或不符合本次 billType
- 对账差异和差错工单只是运营判断依据,`resolve/ignore` 不会落账。最终订单修正必须走退款、补偿、人工确认或后续专门的人工调整接口。
- 当前后端支持 JSON 行手工导入;官方账单下载 worker 支持微信/支付宝账单 JSON/CSV/ZIP 解析,并复用同一套对账导入逻辑。真实生产接入时仍要用真实账单文件抽样验收字段映射。
### 异常订单运营台和调整凭证
租户后台财务/售后页可以用异常运营台作为入口。该页只展示待处理风险和凭证复核状态,不允许前端直接修改订单、支付、退款或权益。
异常运营台:
```text
GET /api/commerce/operations/anomalies?provider=wechat_pay&limit=50
权限tenant:reconciliation:read
```
返回中 `items[].type` 可能是:
```text
reconciliation_issue 未关闭对账差错工单
provider_bill_job 官方账单下载失败或运行超时
payment_event_error 支付/退款通知处理异常
stuck_pending_payment 长时间 pending 支付
stuck_refund 长时间待处理/处理中退款
```
创建人工调整凭证:
```text
POST /api/commerce/adjustment-vouchers
权限tenant:reconciliation:write
body: {
"voucherNo": "ADJ-20260629-001",
"reconciliationIssueId": "<issueId>",
"adjustmentType": "write_off",
"direction": "decrease",
"amountCents": 990,
"title": "供应商缺失账单人工核销凭证",
"description": "仅作为财务复核证据",
"assetId": "<contentAssetId可选>",
"externalUrl": "https://finance.example.com/proofs/ADJ-20260629-001",
"metadata": {
"operatorRemark": "后台上传凭证"
}
}
```
可关联的来源字段:
```text
reconciliationIssueId 对账差错工单
reconciliationItemId 对账明细
orderId / orderNo 订单
paymentId 支付记录
refundRequestId/refundNo 退款申请
sourceType=manual 纯人工凭证
```
凭证字段:
```text
adjustmentType:
manual_payment_confirm | refund_correction | provider_confirmed |
local_corrected | write_off | duplicate | other
direction:
increase | decrease | none
status:
draft | submitted | approved | rejected | voided
```
查询凭证:
```text
GET /api/commerce/adjustment-vouchers?status=submitted&orderNo=<orderNo>
权限tenant:reconciliation:read
```
复核凭证:
```text
POST /api/commerce/adjustment-vouchers/status
权限tenant:reconciliation:review
body: {
"voucherId": "<voucherId>",
"status": "approved | rejected | voided",
"reviewNote": "财务复核意见",
"metadata": {
"reviewChannel": "tenant-admin"
}
}
```
查看凭证轨迹和报表:
```text
GET /api/commerce/adjustment-vouchers/events?voucherId=<voucherId>
GET /api/commerce/adjustment-vouchers/report?startDate=2026-06-01&endDate=2026-06-29
权限tenant:reconciliation:read
```
前端处理规则:
- 学生端不要接这些接口。
- `tenant:reconciliation:write` 可创建凭证,`tenant:reconciliation:review` 才能审批、驳回或作废凭证。
- 后端会校验凭证来源和附件 `content_assets` 必须属于当前租户。
-`approved/rejected/voided` 的凭证不能翻转到其它关闭状态。
- 凭证审批不会自动改订单、支付、退款和权益;真正落账仍要走退款状态机、支付补偿、手工支付确认或后续专门落账命令。
- 前端可在差错工单 `resolve` 时把 `metadata.voucherNo` 一并传入,用于人读检索,但不要把它当成落账动作。
### 激活码预检查与兑换
兑换前建议先调用: