Files
suixinkan_uikit/docs/门店身份注销旧接口返回数据说明.md
T

478 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 门店身份注销旧接口返回数据说明
整理日期:2026-08-28。依据旧接口文档及当天测试环境的真实响应。
**注销范围:当前 `store_user` 对应的门店用户身份,不是手机号主账号,不影响同手机号的其他身份。**
示例中的 `store_user_id`、`finance_identity_id` 和注销记录 `id` 均脱敏为 `0`,实际为正整数;脱敏值不能用于请求或业务判断。本文不包含 Token、手机号或姓名。
## 1. 请求信息与实测范围
- 测试环境:`https://api-test.zhifly.cn`
- 统一路径前缀:`/api/yf-handset-app/account-deregister`
- 请求头:`token: <当前身份Token>`、`X-APP-VERSION: 1.3.1`、`X-OS-TYPE: iOS`、JSON Accept/Content-Type。
| 方法 | 路径后缀 | 用途 | 真实响应覆盖情况 |
| --- | --- | --- | --- |
| GET | `/eligibility` | 查询注销条件 | 已实测:阻断、两项确认、允许申请、冷静期、撤销后 |
| GET | `/status` | 查询注销记录 | 已实测:无记录、待确认草稿、冷静期、已撤销 |
| POST | `/waivers/wallet` | 确认放弃现金 | 已实测:零余额确认成功 |
| POST | `/waivers/points` | 确认放弃积分 | 已实测:零积分确认成功 |
| POST | `/send-sms` | 发送注销验证码 | 真机发送并收到短信;未保存原始响应体 |
| POST | `/apply` | 提交注销申请 | 真机提交后 GET 确认冷静期;未保存 POST 原始响应体 |
| POST | `/cancel` | 撤销注销申请 | 已实测:撤销成功,并 GET 复核 |
已按用户分次授权执行两项零资产确认,以及一次“短信 → 提交 → 查询 → 立即撤销”。申请时间为 14:23:40,14:24:04 撤销成功,14:24:05 查询确认已撤销;未保留待注销申请,未执行最终注销。正文不记录验证码。
**此前申请状态(15:56复核):15:27:24创建的申请已于15:55:36因重新登录自动撤销(9 / CANCELLED_BY_LOGIN)。没有保留这次待注销申请,旧截止时间不再代表有效冷静期。**
17:01补充实测:当前真机身份查询为未提交草稿0,两项资产已确认,尚未进入冷静期。按用户授权分别尝试`accepted: false`,两条接口均拒绝,确认标记没有重置,见4.4节。
## 2. 公共响应与业务码
| 字段 | 已观测 JSON 类型 | 含义 |
| --- | --- | --- |
| `code` | number(整数) | 业务码,成功为 `100000` |
| `msg` | string | 响应说明,成功可为 `"success"` 或 `"注销申请已撤销"`,不能固定匹配文案 |
| `data` | object;未登录时为 array | 具体业务数据 |
| `time` | string | 成功样例中的服务端时间,格式 `yyyy-MM-dd HH:mm:ss`;时区待确认 |
**HTTP 200 不等于业务成功,必须检查 `code`。**
| 业务码 | 含义 | 验证情况 |
| --- | --- | --- |
| `100000` | 请求成功 | 两个 GET、两个资产确认及撤销响应均观察到 |
| `100090` | 未登录 | 不带 Token 查询两个 GET 时实测 |
| `100099` | 本次表示未明确同意放弃资产 | 两项确认接口传`accepted: false`时实测,见4.4 |
| `150015` | 冷静期身份访问普通业务接口受限 | 15:29使用申请中的身份 GET `/api/yf-handset-app/userinfo` 实测,见5.7 |
两个 GET 的未登录响应均为 HTTP 200,正文如下,没有 `time` 字段:
```json
{"code":100090,"msg":"未登录","data":[]}
```
## 3. 注销条件:GET `/eligibility`
### 3.1 存在阻断时的真实响应
HTTP 200,以下为服务端 `2026-08-28 11:39:51` 的响应:
```json
{
"code": 100000,
"msg": "success",
"data": {
"can_apply": false,
"store_user_id": 0,
"finance_identity_id": 0,
"wallet_balance_fen": 0,
"wallet_balance": "0.00",
"points_balance": 0,
"wallet_waived": false,
"points_waived": false,
"unfulfilled_count": 37,
"fulfillment_in_progress_count": 0,
"risk_end_at": "2026-08-27 15:47:32",
"eligible_at": "2026-09-03 15:47:32",
"risk_window_hours": 168,
"blockers": [
{
"code": "ORDER_UNFULFILLED",
"message": "账户仍有未履约订单或带单",
"action": "complete_orders"
},
{
"code": "RISK_WINDOW_NOT_EXPIRED",
"message": "最后一笔业务的风险结束时间尚未超过7天",
"action": "wait_risk_window"
},
{
"code": "WALLET_WAIVER_MISSING",
"message": "请先确认放弃现金余额",
"action": "confirm_wallet_waiver"
},
{
"code": "POINTS_WAIVER_MISSING",
"message": "请先确认放弃积分",
"action": "confirm_points_waiver"
}
],
"deregister": null
},
"time": "2026-08-28 11:39:51"
}
```
### 3.2 `data` 字段说明
| 字段 | 已观测 JSON 类型 | 数据信息 |
| --- | --- | --- |
| `can_apply` | boolean | 服务端是否允许提交申请 |
| `store_user_id` | number(整数) | 门店用户身份 ID,不是门店实体 ID |
| `finance_identity_id` | number(整数) | 财务身份 ID |
| `wallet_balance_fen` | number(整数) | 现金余额,单位分,适合金额计算 |
| `wallet_balance` | string | 现金金额展示值,如 `"0.00"`,不是 JSON 数字 |
| `points_balance` | number(整数) | 积分余额 |
| `wallet_waived` | boolean | 当前现金余额快照是否已确认放弃 |
| `points_waived` | boolean | 当前积分余额快照是否已确认放弃 |
| `unfulfilled_count` | number(整数) | 未履约记录数量;本次分别观察到 37 和 0 |
| `fulfillment_in_progress_count` | number(整数) | 处理中记录数量,本次为 0;具体统计范围待后端确认 |
| `risk_end_at` | string / null | 最后业务风险结束时间 |
| `eligible_at` | string / null | 业务风险等待截止时间,**不是注销冷静期截止** |
| `risk_window_hours` | number(整数) | 业务风险等待时长,本次为 168 小时 |
| `blockers` | array<object> | 全部阻断项;无阻断时为 `[]` |
| `deregister` | object / null | 注销记录;草稿结构见第 5 节 |
时间字符串本次采用 `yyyy-MM-dd HH:mm:ss`。另一个测试身份的两个风险时间均为 null,不能把 null 转成当前时间或自行追加 168 小时等待。
### 3.3 `blockers[]` 字段与取值
每项包含三个字符串:`code` 为业务标识,`message` 为展示提示,`action` 为建议动作。应展示全部阻断项。
| 已实测 `code` | 含义 | 已实测 `action` |
| --- | --- | --- |
| `ORDER_UNFULFILLED` | 存在未履约订单或带单 | `complete_orders` |
| `RISK_WINDOW_NOT_EXPIRED` | 风险等待期未结束 | `wait_risk_window` |
| `WALLET_WAIVER_MISSING` | 未确认放弃现金 | `confirm_wallet_waiver` |
| `POINTS_WAIVER_MISSING` | 未确认放弃积分 | `confirm_points_waiver` |
旧文档另列出以下代码,但未实测其完整对象和 `action`:
| 仅文档列出的代码 | 文档含义 |
| --- | --- |
| `SHARED_FINANCE_IDENTITY` | 与其他启用身份共用财务账本,需人工处理 |
| `NEGATIVE_ASSET` | 负余额或负积分 |
| `FINANCE_IN_FLIGHT` | 财务流程尚未收口 |
| `FULFILLMENT_IN_PROGRESS` | 退款、分账或交付任务处理中 |
| `WAIVER_STALE` | 确认后余额变化,需重新确认 |
### 3.4 另一个身份的连续数据变化
以下身份现金、积分均为 0,未履约及处理中数量为 0,两个风险时间均为 null。它与 3.1 中有 37 项未履约记录的身份不同。
| 阶段 | `wallet_waived` | `points_waived` | `can_apply` | 阻断 | `deregister` |
| --- | --- | --- | --- | --- | --- |
| 确认前 | false | false | false | 缺两项确认 | null |
| 现金确认后 | true | false | false | 仅缺积分确认 | `status: 0` 草稿 |
| 积分确认后 | true | true | true | `[]` | 仍为 `status: 0` 草稿 |
| 申请后的冷静期 | false | false | false | 缺两项确认 | `status: 1` 冷静期中 |
| 主动撤销后 | false | false | false | 缺两项确认 | `status: 9` 已撤销 |
**第一次资产确认就会产生非空草稿。两项确认后可以申请,但尚未提交申请,也未进入冷静期。**
冷静期中两项确认已变回 false,不应按阻断建议再次确认资产。撤销后重新申请需重新核验条件和确认资产;尚未真实测试再次申请。
## 4. 两项资产确认接口
现金和积分分别请求,均使用以下 JSON 请求体:
```json
{"accepted":true}
```
### 4.1 POST `/waivers/wallet`
HTTP 200,现金确认成功的真实响应:
```json
{
"code": 100000,
"msg": "success",
"data": {
"asset_type": "wallet",
"wallet_balance_fen": 0,
"wallet_balance": "0.00",
"points_balance": 0,
"wallet_waived_at": "2026-08-28 13:45:57",
"points_waived_at": null
},
"time": "2026-08-28 13:45:57"
}
```
### 4.2 POST `/waivers/points`
HTTP 200,积分确认成功的真实响应:
```json
{
"code": 100000,
"msg": "success",
"data": {
"asset_type": "points",
"wallet_balance_fen": 0,
"wallet_balance": "0.00",
"points_balance": 0,
"wallet_waived_at": "2026-08-28 13:45:57",
"points_waived_at": "2026-08-28 13:46:42"
},
"time": "2026-08-28 13:46:42"
}
```
### 4.3 确认响应字段
| 字段 | 已观测 JSON 类型 | 含义 |
| --- | --- | --- |
| `asset_type` | string | 本次确认的资产:`wallet` 或 `points` |
| `wallet_balance_fen` | number(整数) | 当前现金余额,分 |
| `wallet_balance` | string | 当前现金金额展示值 |
| `points_balance` | number(整数) | 当前积分余额 |
| `wallet_waived_at` | string(本次均非空) | 现金确认时间;其他场景是否可为 null 尚未实测 |
| `points_waived_at` | string / null | 积分确认时间;现金确认后仍为 null,积分确认后为时间字符串 |
零余额、零积分也需分别确认。确认成功后重新查询条件和状态,以最新标记为准。旧文档规定确认绑定余额快照;确认本身不等于提交注销或立即清零资产。
### 4.4 `accepted: false` 不支持撤回确认(真实测试)
2026-08-28 17:01,使用iPhone 11当前已登录门店身份,在测试环境分别发送一次:
```json
{"accepted":false}
```
前置状态:`status: 0`未提交草稿,`wallet_waived: true`、`points_waived: true`,现金与积分均为0;`apply_time`、`cooling_until`、`completed_at`均为null。
| 接口 | 服务端响应时间 | HTTP状态 | 业务码 | 结果 |
| --- | --- | --- | --- | --- |
| POST `/waivers/wallet` | 2026-08-28 17:01:14 | 200 | 100099 | 拒绝false,确认标记未变化 |
| POST `/waivers/points` | 2026-08-28 17:01:32 | 200 | 100099 | 拒绝false,确认标记未变化 |
现金接口完整响应如下;积分接口除`time`为`2026-08-28 17:01:32`外,其余字段相同:
```json
{
"code": 100099,
"msg": "请明确确认自愿放弃对应资产",
"data": [],
"time": "2026-08-28 17:01:14"
}
```
每次POST后均再次查询`/status`和`/eligibility`:两项确认仍为true,草稿仍为0,金额未变化,`can_apply`仍为true。**当前接口不能通过传false把已确认状态重置为未确认。** 本轮没有发送true、短信、申请或撤销请求,也没有重新登录。`/cancel`能否取消未提交草稿仍未验证,不能由本次结果推断。
脱敏证据:`/private/tmp/suixinkan-waiver-false-20260828/device-wallet-response.json`、`device-points-response.json`及同目录各自的`before/after-status`、`before/after-eligibility`文件。Token未输出或保存;读取真机会话时的临时副本已删除。
## 5. 注销状态:GET `/status`
### 5.1 无记录
HTTP 200,真实响应:
```json
{
"code": 100000,
"msg": "success",
"data": {
"deregister": null
},
"time": "2026-08-28 11:39:51"
}
```
### 5.2 已确认资产、尚未提交的草稿
HTTP 200,真实响应:
```json
{
"code": 100000,
"msg": "success",
"data": {
"deregister": {
"id": 0,
"status": 0,
"status_label": "待确认",
"reason": "",
"apply_time": null,
"cooling_until": null,
"remaining_seconds": 0,
"cancel_time": null,
"blocked_code": "",
"blocked_reason": "",
"completed_at": null
}
},
"time": "2026-08-28 13:46:42"
}
```
### 5.3 `data.deregister` 字段
| 字段 | 本次实际类型/值 | 含义与待确认事项 |
| --- | --- | --- |
| `id` | number(正整数,示例脱敏为 0) | 注销记录 ID,不是门店用户 ID |
| `status` | number(整数),`0` / `1` / `9` | 分别为待确认、冷静期中、已撤销;其他值未知 |
| `status_label` | string | 服务端状态文案,如 `"冷静期中"`、`"已撤销"` |
| `reason` | string | 草稿为空;提交后保留用户输入的原因 |
| `apply_time` | string / null | 申请时间,本次 `2026-08-28 14:23:40` |
| `cooling_until` | string / null | 冷静期截止,本次 `2026-09-04 14:23:40`;撤销后仍保留 |
| `remaining_seconds` | number(整数) | 查询时剩余秒数;草稿、已撤销都为 0,不能据此认定已完成 |
| `cancel_time` | string / null | 撤销时间,本次 `2026-08-28 14:24:04` |
| `blocked_code` | string | 草稿/冷静期为空;主动撤销为 `CANCELLED_BY_USER` |
| `blocked_reason` | string | 草稿/冷静期为空;主动撤销为 `用户主动撤销注销` |
| `completed_at` | null | 完成时间;非空类型和格式未实测 |
同一草稿结构也出现在 `eligibility` 的 `data.deregister` 内。两个 GET 的 `cooling_until`、`remaining_seconds` 位于该记录对象中;不能据此推断 `/apply` 响应的嵌套结构。
### 5.4 冷静期的真实响应
GET `/status`,HTTP 200。该结果确认申请已受理,但不是 `/apply` 的原始响应体。
```json
{
"code": 100000,
"msg": "success",
"data": {
"deregister": {
"id": 0,
"status": 1,
"status_label": "冷静期中",
"reason": "API test; cancel immediately",
"apply_time": "2026-08-28 14:23:40",
"cooling_until": "2026-09-04 14:23:40",
"remaining_seconds": 604776,
"cancel_time": null,
"blocked_code": "",
"blocked_reason": "",
"completed_at": null
}
},
"time": "2026-08-28 14:24:03"
}
```
### 5.5 主动撤销的真实响应
POST `/cancel`,HTTP 200,无业务请求字段。撤销后再次 GET `/status` 返回相同记录,`msg: "success"`、`time: "2026-08-28 14:24:05"`。
```json
{
"code": 100000,
"msg": "注销申请已撤销",
"data": {
"deregister": {
"id": 0,
"status": 9,
"status_label": "已撤销",
"reason": "API test; cancel immediately",
"apply_time": "2026-08-28 14:23:40",
"cooling_until": "2026-09-04 14:23:40",
"remaining_seconds": 0,
"cancel_time": "2026-08-28 14:24:04",
"blocked_code": "CANCELLED_BY_USER",
"blocked_reason": "用户主动撤销注销",
"completed_at": null
}
},
"time": "2026-08-28 14:24:04"
}
```
`status: 9` 表示已撤销;保留旧 `apply_time`、`cooling_until` 不代表仍在冷静期。这里的 `CANCELLED_BY_USER` 是撤销原因,不是终审阻断状态。两个 GET 均确认两项资产确认标记变为 false;冷静期时已经是 false,不能断言由撤销动作单独导致。
### 5.6 新申请保留在冷静期的真实响应
用户最终确认后,于模拟器点击一次提交;以下为后续 GET `/status` 的真实响应(HTTP 200),不是 POST `/apply` 的响应体:
```json
{
"code": 100000,
"msg": "success",
"data": {
"deregister": {
"id": 0,
"status": 1,
"status_label": "冷静期中",
"reason": "Test account deregistration",
"apply_time": "2026-08-28 15:27:24",
"cooling_until": "2026-09-04 15:27:24",
"remaining_seconds": 604736,
"cancel_time": null,
"blocked_code": "",
"blocked_reason": "",
"completed_at": null
}
},
"time": "2026-08-28 15:28:27"
}
```
同时 GET `/eligibility` 返回现金0、积分0、两项确认 false,以及缺少资产确认的两个阻断;其 `deregister` 仍为上述冷静期记录。不能因此重新确认资产或重复申请。
### 5.7 冷静期普通业务限制的真实响应
15:29以同一身份的现有 Token 只读请求 GET `/api/yf-handset-app/userinfo`,HTTP 200:
```json
{
"code": 150015,
"msg": "账号处于注销冷静期,请先撤销注销后再继续使用",
"data": {
"status": "cooling",
"cooling_until": "2026-09-04 15:27:24",
"remaining_seconds": 604681
}
}
```
该响应没有 `time`,且 `data.status` 是字符串 `"cooling"`;与 `/status` 中 `data.deregister.status` 的数字1不是同一层级或类型,不能共用数字状态 DTO。
请求前后 GET `/status` 均成功且保持同一冷静期申请,`cancel_time`、`completed_at` 均为 null。这证明本次普通信息查询受限,但当前 Token 仍可查询注销状态;不代表正式完成后的鉴权规则已验证,也不能外推为全部普通业务接口已逐一验证。
上述150015和随后status响应已整理为测试夹具(仅记录ID替换为301),并在iPhone 11重放验证业务API、限制通知、状态查询和冷静期页面之间的衔接。此项为Mock集成验证,不是再次请求真实账号或重新申请。
### 5.8 重新登录自动撤销的真实响应
用户重新进入后,15:56只读GET确认之前的申请已撤销,HTTP 200:
```json
{
"code": 100000,
"msg": "success",
"data": {
"deregister": {
"id": 0,
"status": 9,
"status_label": "已撤销",
"reason": "Test account deregistration",
"apply_time": "2026-08-28 15:27:24",
"cooling_until": "2026-09-04 15:27:24",
"remaining_seconds": 0,
"cancel_time": "2026-08-28 15:55:36",
"blocked_code": "CANCELLED_BY_LOGIN",
"blocked_reason": "用户重新登录,自动撤销注销",
"completed_at": null
}
},
"time": "2026-08-28 15:56:34"
}
```
CANCELLED_BY_LOGIN与主动撤销的CANCELLED_BY_USER不同,但同为已撤销9。本次未捕获触发撤销的登录请求,不能确定是哪个登录或身份选择接口触发。并未完成正式注销。
## 6. 尚缺的响应与验证
| 接口 | 旧文档已知信息 | 尚缺信息 |
| --- | --- | --- |
| POST `/send-sms` | 已通过真机发送并收到短信 | 原始成功/失败响应、频率限制及业务码 |
| POST `/apply` | 请求字段 `sms_code`、`reason`;提交后查到冷静期1 | POST 完整响应层级、验证码错误及重复申请响应 |
| POST `/cancel` | 成功体及撤销后9状态已实测 | 失败、重复撤销和终态撤销响应 |
尚未获得阻断、正式完成的 `/status` 响应,不能猜测数字枚举。时间字符串的时区仍待确认,`completed_at` 非空类型和格式仍未实测。
已获得登录自动撤销后的真实状态9和CANCELLED_BY_LOGIN原因,但具体触发接口仍未捕获。到期复核、正式完成后的鉴权响应及全部身份注销后的登录响应仍未验证。此前两次申请现均已撤销。
## 7. 接入注意
1. 按当前门店用户身份隔离状态,不能按手机号共用状态。
2. 展示全部阻断项,不能只使用 `can_apply` 或 HTTP 状态码判断流程。
3. 完整的未提交草稿不应阻止第二项资产确认或手机号验证,非空记录不等于已提交。
4. `eligible_at` 是提交前的业务风险等待截止;`cooling_until` 是提交后的冷静期截止,两者不能混用。
5. `remaining_seconds: 0`、本机时间到期、`can_apply: true` 都不能单独作为注销完成依据。
6. 未知状态、字段缺失或请求失败不能默认解释为“没有申请”。
7. 已撤销9仍含 `cooling_until`,且 `blocked_code` 非空;不能误显示为仍在冷静期或终审阻断。
历史探测过程见 [接口实测记录](门店身份注销接口实测.md),客户端进度见 [接入说明](门店身份注销接入说明.md)。