feat: 实名即生效套餐沉默期、延期办理与资产出库时间
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 8m39s

- 迁移 000259~000265:套餐记录沉默期字段与扫描索引、套餐默认沉默期、延期政策/流水/订单/批次/明细 5 张表、默认政策与系统配置(总开关默认关闭)、企微审批白名单、卡与设备出库时间及出库记录
- 沉默期设置(订单发放、自动购包、钱包续费)、后台购买时调整(超默认值按政策免审或企微审批)、统一判定与激活闸门、排队与孤儿扫描跳过过期套餐、过期套餐禁止退款、每 10 分钟扫描
- 总开关专用接口与打开前 4 项检查;延期政策;延期资格与计费;H5 自助与后台二维码在线支付(商户池路由)、支付回调与查单恢复、线下登记、特殊/批量延期、异常重试与原路退款;沉默期审批场景与终态处理
- 换货沉默期流水与出库时间;卡/设备列表、详情、导出与出库记录接口;延期订单与即将过期套餐列表及导出;财务流水纳入延期支付
- 沉默期与出库时间回填工具 cmd/silence-backfill;前端接口变更说明

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
邹进
2026-10-27 16:32:58 +09:00
parent d2b0d2f534
commit 909f4d0ec2
112 changed files with 10473 additions and 82 deletions

View File

@@ -0,0 +1,116 @@
# 实名即生效套餐沉默期 — 前端接口变更说明
> 对应 OpenSpec Change `add-package-silence-period`;规则以 `docs/沉默期技术方案/实名即生效套餐沉默期技术方案_v3.md` 为准。接口字段以 `docs/admin-openapi.yaml` 为准,本文只说明页面要做什么。
## 1. 总开关对页面的影响
沉默期总开关 `package.silence.enabled` **默认关闭**。
| 页面 / 功能 | 关闭时 | 打开时 |
|---|---|---|
| 资产套餐列表、H5 套餐历史里的 `silence` 对象 | **不返回**(字段为空),页面不显示沉默期 | 返回,显示状态、截止日 |
| "延期"入口 | 不显示 | `silence.extendable = true` 时显示 |
| 延期资格、试算、下单、线下登记、特殊延期 | 返回错误码 **1274** | 可用 |
| 套餐默认沉默期、延期政策、企微审批场景配置 | 可用 | 可用 |
| 购买时调整沉默期 | 可用 | 可用 |
| 卡 / 设备出库时间 | 不受开关影响 | 不受开关影响 |
后台"系统配置"通用接口不能修改总开关(只读),请用专用接口:
- `GET /api/admin/package-silence/switch`:当前值 + 打开前 4 项检查(`precheck[]`:code、name、passed、count)。
- `PUT /api/admin/package-silence/switch` `{ "enabled": true|false }`:仅超级管理员。打开前检查不通过返回 **1275**,`data.failed_items` 为未满足项,直接展示即可;关闭不检查。
## 2. 套餐配置
- 新增 / 编辑套餐增加 `silence_period_days`(1~90)、`silence_extension_enabled`(默认 true)。
- **实名即生效的正式套餐必填**默认沉默期,新建时前端预填 30;不填或越界返回 **1260**。
- 购买即生效套餐、加油包不显示、不提交这两个字段。
- 套餐响应增加 `silence_period_days`、`silence_extension_enabled`、`silence_config_required`(是否必须配置)。
- 实名即生效套餐改为购买即生效、店铺分配(单个、批量、系列授权)里覆盖为与套餐不同的生效条件,返回 **1262**。购买即生效改为实名即生效时,同一请求必须带 `silence_period_days`。
- "未配置沉默期的实名即生效套餐"清单:套餐列表加 `silence_unconfigured=true`;导出用套餐导出场景,筛选同样传 `silence_unconfigured`。套餐导出新增"默认沉默期(天)""是否支持付费延期"两列。
## 3. 后台购买时调整沉默期
`POST /api/admin/orders`(后台给资产购买套餐)新增可选字段:
- `silence_period_days`(≥ 1,不设上限)、`silence_reason`(设置时必填)。
- 需要 `package_silence:override` 权限,无权限传值返回 **1261**。
- 不超过默认值:直接生效;超过默认值:按延期政策直接生效,或**先按默认值购买并提交企微审批**(审批中套餐不会过期)。发起人未绑定企微成员时购买被拒。
- 只对"资产未实名时购买的实名即生效主套餐"生效,其他情况忽略。
## 4. 资产套餐展示
后台资产套餐历史 / 当前套餐、H5 套餐历史(`/api/c/v1/asset/package-history`)每笔套餐增加 `silence` 对象(总开关打开且适用沉默期时返回):
| 字段 | 说明 |
|---|---|
| `silence_status` / `silence_status_name` | `waiting` 待实名(延期后显示"延期待实名")/ `expired` 沉默期已过期 / `ended` 沉默期已结束;待实名但已过截止的直接按 `expired` 返回 |
| `silence_deadline_at`、`silence_start_at`、`silence_period_days` | 截止时间(截止日 23:59:59)、起算时间、天数 |
| `silence_extended_days`、`silence_paid_extended_days`、`silence_extension_count`、`silence_free_extension_used` | 延期累计 |
| `silence_expired_at`、`silence_adjust_pending` | 过期时间、调整审批中 |
| `extendable` | 是否显示"延期"入口 |
套餐沉默期流水:后台 `GET /api/admin/package-silence/records?package_usage_id=`,H5 `GET /api/c/v1/package-silence/records?package_usage_id=`。
## 5. 延期(后台)
均在 `/api/admin/package-silence` 下:
| 接口 | 权限 | 说明 |
|---|---|---|
| `GET /eligibility?package_usage_id=` | — | 资格:`can_extend`、`special_extension_available`、`reason`、`min_days`/`max_days`、`min_months`/`max_months`、`unit_price`、`options[]`(每档计费天数、金额、新截止日)。**金额全部由后端算,前端只传天数** |
| `GET /quote?package_usage_id=&days=` | — | 输入天数试算(按 30 天向上取整:1→30、31→60) |
| `POST /orders/qrcode` | `package_silence:extend` | 运营生成支付二维码:入参 `package_usage_id`、`days`、`payment_method`(wechat/alipay)、`request_id`、`evidence_refs`;返回 `qr_content` 渲染为二维码。已有客户 H5 待支付订单时后端先查单,未付自动关闭旧单 |
| `POST /orders/offline` | `package_silence:offline` | 登记线下付款:`offline_payment_method_id`(线下收款方式字典)、`offline_trade_no`、`paid_amount`(必须等于计算金额,否则 **1273**)、`paid_at`、`payment_voucher_keys`(1~5)、`evidence_refs`、`request_id`。交易单号重复 **1272**。默认进企微审批 |
| `GET /orders`、`GET /orders/:id` | — | 延期订单列表 / 详情,含 `payment_method`、`payment_merchant_name`、`third_party_trade_no`;导出场景 `package_silence_order` |
| `POST /special` | `package_silence:extend`(批量另需 `package_silence:extend_batch`) | 特殊延期:`extension_type`(free/discount/complaint_compensation/system_compensation/special_customer)、`items[]`(package_usage_id + days)、`reason`、`basis`、`evidence_refs`、`amount`(免费为 0)、优惠价有收款时填收款方式 / 交易单号 / 凭证。批量明细逐行校验,不通过返回 `data.rows[]`(行号与原因)。免费次数用完 **1267** |
| `GET /batches`、`GET /batches/:id` | — | 批次与明细(`has_exception=true` 只看含异常的) |
| `POST /extensions/:id/handle` | `package_silence:exception` | 异常明细 `action=retry|close` + `reason`;在线订单关闭时原路退款 |
| `GET /usages?view=expiring|expired|all` | — | 即将过期(默认 7 天内)/ 已过期套餐;导出场景 `package_silence_usage` |
延期政策(`package_silence:policy`):`GET/POST /policies`、`GET/PUT /policies/:id`、`PUT /policies/:id/status`、`GET /policies/match?package_id=`。同级重叠返回 **1269**。
## 6. 延期(H5)
均在 `/api/c/v1/package-silence` 下,资产须属于当前客户:
- `GET /eligibility`、`GET /quote`:同后台。
- `POST /orders`:自助下单(`package_usage_id`、`days`、`payment_method`、`request_id`),返回 `qr_content`(支付链接或二维码内容);支付成功自动延期。
- `GET /orders`、`GET /orders/:id`:我的延期订单。
- `GET /records`:沉默期流水。
## 7. 退款
沉默期已过期的套餐申请退款返回 **1268**(总开关打开时)。
## 8. 卡 / 设备出库时间
- 卡列表、设备列表返回 `outbound_at`,支持 `outbound_start`、`outbound_end`(RFC3339)筛选;卡详情、设备详情、资产解析返回 `outbound_at`。
- 卡、设备导出末尾新增"出库时间"列。
- 出库记录:`GET /api/admin/assets/:asset_type/:id/outbound-records`(asset_type 为 card / device),按世代倒序,含来源(首次购买套餐 / 换货新资产 / 历史回填)、订单号或换货单号、结束时间与原因。
- 绑定在设备上的卡不记录出库时间;只读,不提供修改。
## 9. 错误码
| 码 | 名称 | 说明 |
|---|---|---|
| 1260 | silence_period_out_of_range | 沉默期天数不在允许范围 |
| 1261 | silence_override_forbidden | 无权限调整沉默期 |
| 1262 | package_expiry_base_change_forbidden | 不允许变更该套餐的生效条件 |
| 1263 | silence_extension_not_expired | 套餐未过期 / 无沉默期 / 已激活 / 已退款(`data.reason` 细分) |
| 1264 | silence_extension_disabled | 该套餐不支持付费延期(可申请特殊延期) |
| 1265 | silence_extension_exceeds_limit | 超过可延期期限(`data.min_months`、`data.max_months`) |
| 1266 | silence_extension_months_invalid | 延期天数不在允许范围(`data.min_days`、`data.max_days`) |
| 1267 | silence_free_extension_used_up | 免费延期次数已用完 |
| 1268 | silence_expired_not_refundable | 沉默期已过期的套餐不能退款 |
| 1269 | silence_policy_overlap | 延期政策重叠 |
| 1270 | silence_extension_no_policy | 未匹配到延期政策 |
| 1271 | silence_extension_order_pending | 已有未结束的延期订单或申请 |
| 1272 | silence_offline_trade_no_duplicate | 线下交易单号已登记 |
| 1273 | silence_offline_amount_mismatch | 实收金额与计算金额不一致(`data.expected_amount`) |
| 1274 | silence_feature_disabled | 沉默期功能未开启 |
| 1275 | silence_switch_precheck_failed | 总开关打开前检查未通过(`data.failed_items`) |
## 10. 企微审批模板
超级管理员在"企微审批场景"配置业务类型 **沉默期审批(package_silence_approval)**,模板需有"申请类型"单选控件,选项映射:`购买时调整沉默期`、`特殊延期`、`线下付费延期`。可映射字段见场景配置页的业务字段列表(申请单号、资产、套餐、原截止日期、延期天数、计费天数、费用、原因、附件、收款方式、交易单号、凭证等)。