04 — 进件资料采集
来源:
api/order.ts saveStep/fetchOrder/submitOrder+api/identity.ts
涉及页面:Identity / Personal / Work / Guarantor / Liveness / Review 各 PRD
共 5 个接口(含 BVN/NIN 实时核验)
业务上下文
订单已在 03 步骤创建(status = Drafting),现在进入 6 步资料采集:
| Step | 页面 | 内容 |
|---|---|---|
| identity | Identity | BVN / NIN(二选一)实时核验,回填证件持有人姓名 / DOB / 照片 |
| personal | Personal | 婚姻 / 子女 / 宗教 / 教育 / 行政区划 / 居住情况 / WhatsApp / Facebook / NIN(备) |
| work | Work | 就业类型 / 职业 / 行业 / 发薪周期 / 收入 / 月发薪日 |
| guarantor | Guarantor | Primary + Secondary 紧急联系人(关系 / 姓名 / 电话) |
| liveness | Liveness | 客户活体检测(SDK 返回结果回传后端) |
| review | Review | 客户复核全部信息 + 隐私授权 → 正式提交 |
关键设计:
- 暂存接口是 通用的(按
step字段派发 payload),架构师可后续拆分 - 每步暂存即落库(不依赖最终 review 提交);SA 可中途退出后通过 Applications 列表 Continue
- BVN / NIN 实时核验是独立接口(不走 saveStep),返回的姓名 / DOB 由 SA 现场口述给客户确认 → 准确则进 saveStep(‘identity’)
1. 暂存进件步骤数据(通用)
业务描述:按 step 名称暂存当前步骤的 payload;后端按 step 校验 schema 并落库;不触发状态机推进(仅最后一步 review 提交触发 Drafting → Reviewing)。
触发场景:每个采集页面(Identity / Personal / Work / Guarantor / Liveness)点击 Next 按钮时调用。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_id | string | ✓ | 订单 ID |
| step | enum | ✓ | identity / personal / work / guarantor / liveness |
| data | object | ✓ | 该 step 的 payload(schema 按 step 不同;见下方 §1.x) |
出参
返回更新后的 OrderData(见 §2 进件详情查询出参结构)
关键异常
| 异常码 | 含义 | 前端处理 |
|---|---|---|
| ORDER_NOT_FOUND | order_id 不存在或不属于该 SA | toast + 跳 Applications |
| ORDER_STATUS_INVALID | 当前订单状态不允许采集(如已 Reviewing / Closed) | toast 提示 + 跳详情 |
| STEP_VALIDATION_FAILED | payload 不符合 schema(字段缺失 / 格式错) | 字段级 inline 错误 |
1.1 step = identity payload
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id_type | enum | ✓ | bvn / nin |
| id_number | string | ✓ | 11 位(BVN 11 位数字 / NIN 11 位数字) |
| full_name | string | ✓ | 证件持有人姓名(从 BVN/NIN 核验出参回填,SA 现场口述核对) |
| dob | string(YYYY-MM-DD) | ✓ | 出生日期(同上来源) |
| photo_url | string? | (BVN 路径有) | 证件人脸照(BVN 路径有,NIN 无;前端透传给后端持久化) |
| mismatch_warning_dismissed | boolean | SA 看到”客户口述与 BVN/NIN 不一致”警告时是否仍坚持继续(审计字段) |
1.2 step = personal payload
对应 Personal 页 schema(见 Personal PRD):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| gender | enum | ✓ | male / female |
| marital_status | enum | ✓ | married / single / divorced |
| children | enum | ✓ | 0 / 1-2 / 3-4 / 4+ |
| religion | enum | ✓ | christianity / islam / other |
| education | enum | ✓ | middle_or_below / high_school / diploma / bachelor / master_or_above |
| province | string | ✓ | NG State 代码(如 lagos;字段名沿用技术昵称,UI 显示 State) |
| city | string | ✓ | LGA 代码(如 ikeja;UI 显示 LGA) |
| address | string | ✓ | 街道地址 5-200 字符 |
| residence_type | enum | ✓ | own / rent / family / company / other |
| string | 10 位 NG 号或空 | ||
| string | 用户名 / 链接 ≤ 200 字符或空 | ||
| nin | string | 11 位(与 Identity 的”主 ID”互补 — 主 ID 选 BVN 则此处填 NIN,反之亦然) |
1.3 step = work payload
对应 Work 页 schema(见 Work PRD):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| employment_type | enum | ✓ | salaried / self-employed / business-owner / civil-servant / student / unemployed / others |
| occupation | string | 条件 | 具体职业(自由文本 2-60);student/unemployed 可缺 |
| industry | string | 条件 | 行业代码;student/unemployed 可缺 |
| pay_frequency | enum | ✓ | weekly / monthly |
| income_amount | string(NGN 整数) | ✓ | 按 pay_frequency 口径的收入 |
| salary_payday | int(1-31) | 条件 | 月薪发薪日;仅 pay_frequency=monthly 时必填 |
1.4 step = guarantor payload
对应 Guarantor 页 schema(见 Emergency Contact PRD):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| primary_relationship | string | ✓ | 关系(parent / sibling / spouse / friend / colleague / other) |
| primary_full_name | string | ✓ | 全名 2-60 |
| primary_phone | string | ✓ | 10 位 NG 号;不等于客户本人电话 |
| secondary_relationship | string | ✓ | 同上 |
| secondary_full_name | string | ✓ | 同上 |
| secondary_phone | string | ✓ | 10 位 NG 号;不等于客户本人或 Primary |
1.5 step = liveness payload
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| liveness_passed | boolean | ✓ | SDK 检测结果(true = 通过) |
| liveness_session_id | string | ✓ | SDK 提供的 session ID(用于审计回溯) |
| sdk_provider | string | ✓ | SDK 厂商名(如 smile-id / youverify) |
| sdk_result_raw | object? | SDK 原始结果(用于风控分析;建议透传) |
2. 进件详情查询
业务描述:拉取订单全量数据 — 包括各步骤已填字段、状态、合规标识等。用于:
- Detail 页展示订单全貌
- Continue / Fix Info 路径回填表单数据
- Review 页汇总展示
触发场景:
- Detail 页 mount
- 各 采集页 mount 时 reset(form, order[step])
- Review 页 mount 汇总展示
- Pay / Sign / Deliver 页 mount 拉详情
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_id | string | ✓ | 订单 ID |
出参(OrderData 结构)
| 字段 | 类型 | 说明 |
|---|---|---|
| order_id | string | |
| status | enum | 一级状态;见下方 §状态枚举 |
| fix_reason | enum? | 二级标签 — 仅 status=FixRequired 时有;见下方 §二级状态字段 |
| fix_notes | string? | FixRequired 时的自由文本补充(最多 500 字) |
| offer_type | enum? | 二级标签 — 仅 status ∈ {Approved, Signed, Paid, Completed} 时有;original / revised |
| close_reason | enum? | 二级标签 — 仅 status=Closed 时有;declined / returned / expired |
| merchant_id | string | |
| customer_phone | string | |
| created_at | string(ISO 8601) | |
| updated_at | string(ISO 8601) | |
| calculate | object | Calculate Draft 数据(同 03 分册 calculate 子结构) |
| identity | object? | Identity step 已填数据(结构见 §1.1) |
| personal | object? | 同上 §1.2 |
| work | object? | 同上 §1.3 |
| guarantor | object? | 同上 §1.4 |
| group_photo_url | string? | 审批后 Sign 子阶段 2 拍摄;进件期为空(见 06 分册) |
| liveness_passed | boolean? | 同上 §1.6 |
| sign | object? | 签约数据(06 分册) |
| pay | object? | 付款数据(06 分册) |
| deliver | object? | 交付数据(06 分册) |
| approval_result | object? | 审批结果(status ∈ Reviewing 之后才有;含 approved_amount / interest_rate / first_due_date 等) |
状态机完整定义见 手机分期订单状态机(SoT)。本文仅列与 OrderData 出参直接相关的字段;状态流转图、推进条件、时限规则、异常码命名等以 SoT 为准。
status 一级状态枚举
| 状态 | 含义 | SA 下一动作 |
|---|---|---|
Drafting | 进件中;客户资料未填完 | 继续录单直到 Review 提交 |
FixRequired | 风控要求补正资料(二级 fix_reason 细分) | 跳回对应步补齐后重提 |
Reviewing | 客户已提交,风控审批中 | 等 |
Approved | 审批通过,待签约(二级 offer_type 区分原案/调价) | 跳 Sign 流程 |
Signed | 已签约,待收首付 | 跳 Pay |
Paid | 首付已收,待交付 | 跳 Deliver |
Completed | 已交付 + 锁机激活完成 | 无 |
Closed | 已关闭(二级 close_reason 细分原因) | 无 |
fix_reason 二级枚举(FixRequired 时必填;细分补正方向)
| 取值 | 含义 |
|---|---|
identity_mismatch | BVN/NIN 核验与 SA 录入不符 |
income_insufficient | 收入不足 / 流水异常 |
guarantor_invalid | 担保人信息核验失败 |
address_unverified | 居住地址无法核实 |
other | 其它(须配合 fix_notes 文字说明) |
offer_type 二级枚举(Approved 及后续阶段;区分原案 vs 调价)
| 取值 | 含义 |
|---|---|
original | 按 SA 试算方案审批通过 |
revised | 风控调价通过(如降额 / 改期数;详情见 approval_result) |
close_reason 二级枚举(Closed 时必填)
| 取值 | 含义 |
|---|---|
declined | 风控拒绝放款 |
returned | 用户主动放弃 / 三次联系不上 |
expired | 长时间未推进过期(Approved / Signed / Paid 24h 超时) |
关键异常
| 异常码 | 含义 | 前端处理 |
|---|---|---|
| ORDER_NOT_FOUND | 订单不存在 | toast + 跳 Applications |
| ORDER_NOT_AUTHORIZED | 订单不属于当前 SA(被运营划转) | 同上 |
3. BVN 实时核验
业务描述:用 BVN 号实时调上游 KYC 接口,返回持证人姓名 / DOB / 人脸照。给 SA 现场核对客户身份。
触发场景:Identity 页 SA 录入 11 位 BVN 后点击 Verify BVN 按钮。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_id | string | ✓ | 订单 ID(用于落审计日志) |
| bvn | string | ✓ | 11 位 BVN |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
| bvn | string | 入参回显 |
| full_name | string | 持证人姓名 |
| dob | string(YYYY-MM-DD) | 出生日期 |
| photo_url | string | 持证人人脸照 URL(前端展示给 SA 核对) |
关键异常
| 异常码 | 含义 | 前端处理 |
|---|---|---|
| KYC_BVN_INVALID | BVN 格式错 / 不存在 | inline 错误 BVN not found |
| KYC_UPSTREAM_UNAVAILABLE | KYC 上游不可达 | toast + 允许 SA 重试 |
| KYC_RATE_LIMITED | 该订单短时间核验次数过多 | toast 限频提示 |
注:核验通过后的数据不直接落 order — 由 SA 在 UI 看到 BVN 姓名 + 客户口述姓名后判断是否一致;一致才让 SA 点 Next 触发 saveStep('identity') 落库。
4. NIN 实时核验
业务描述:同 BVN,但 NIN 上游一般不返回人脸照。
触发场景:Identity 页 SA 录入 11 位 NIN 后点击 Verify NIN 按钮。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_id | string | ✓ | 同上 |
| nin | string | ✓ | 11 位 NIN |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
| nin | string | 入参回显 |
| full_name | string | 持证人姓名 |
| dob | string(YYYY-MM-DD) | 出生日期 |
关键异常:同 BVN。
5. 进件正式提交(Review 提交)
业务描述:客户在 Review 页确认所有信息无误 + 勾选授权后,正式提交进件 — 触发订单状态机 Drafting → Reviewing。从此风控开始审批流程。
触发场景:Review 页 SA 帮客户勾选 I authorize... + 点击 Submit 按钮。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_id | string | ✓ | 订单 ID |
| customer_authorized | boolean | ✓ | 客户授权信号(必须 true) |
| privacy_policy_version | string | 客户看到的隐私政策版本号(未来合规要求) | |
| signed_at_client_ts | string(ISO 8601) | 客户授权时间(前端时间戳,与服务端时间对比审计) |
出参 — 返回更新后的 OrderData(status 应该已变为 Reviewing)
关键异常
| 异常码 | 含义 | 前端处理 |
|---|---|---|
| ORDER_INCOMPLETE | 还有 step 未填齐 | toast + 提示去补齐 |
| ORDER_STATUS_INVALID | 当前不是 Drafting 状态 | toast + 跳详情 |
| AUTHORIZATION_MISSING | customer_authorized=false 不允许提交 | 前端阻止(按钮 disabled) |