224 lines
8.0 KiB
Markdown
224 lines
8.0 KiB
Markdown
# 支付流程(多客户端通用)
|
||
|
||
## 1. 概述
|
||
|
||
本文档描述换皮应用可复用的支付全流程,覆盖:商品获取、支付方式选择、订单创建、平台内购回调、订单核销、补单与账户刷新。
|
||
文档以“能力与流程”表达,不绑定具体客户端项目、目录路径或某一语言实现。
|
||
|
||
---
|
||
|
||
## 2. 支付流程总览
|
||
|
||
```text
|
||
用户点击充值 / Buy
|
||
│
|
||
├─ 已登录 且 开启第三方支付
|
||
│ │
|
||
│ ├─ 拉取支付方式(基于商品/活动)
|
||
│ ├─ 用户选择支付方式
|
||
│ ├─ 创建订单(服务端生成业务订单)
|
||
│ │
|
||
│ ├─ 若为平台内购(如 Google Play)
|
||
│ │ ├─ 调起商店购买
|
||
│ │ ├─ 获取 purchaseData + signature + storeOrderId
|
||
│ │ └─ 回调服务端校验与入账
|
||
│ │
|
||
│ └─ 若为外部支付
|
||
│ └─ 打开 payUrl 在 Web/外部浏览器完成支付
|
||
│
|
||
└─ 未登录 或 未开启第三方支付
|
||
└─ 可走平台内购直购分支(由业务策略决定)
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 支付分支依据(通用)
|
||
|
||
| 条件 | 说明 |
|
||
|------|------|
|
||
| 是否登录 | 通常需要用户身份用于订单归属与回调入账 |
|
||
| 是否开启第三方支付 | 由服务端用户配置或渠道策略控制 |
|
||
| 当前平台能力 | Android / iOS 对内购与外部支付支持差异 |
|
||
| 商品配置 | 某些商品只允许特定支付方式 |
|
||
|
||
建议将分支判断集中在统一策略层,避免同一逻辑散落在多个页面。
|
||
|
||
---
|
||
|
||
## 4. 商品展示与获取
|
||
|
||
### 4.1 获取时机
|
||
|
||
- 进入充值页时拉取一次;
|
||
- 下拉刷新或切换国家/渠道后重新拉取;
|
||
- 支付成功后建议刷新,确保档位与余额展示一致。
|
||
|
||
### 4.2 商品字段(通用语义)
|
||
|
||
| 字段语义 | 说明 |
|
||
|------|------|
|
||
| `productId` | 商店商品 ID(内购必填) |
|
||
| `activityId` | 服务端活动/档位 ID(建单常用) |
|
||
| `actualAmount` | 实付金额 |
|
||
| `originAmount` | 原价(可用于划线价) |
|
||
| `bonus` / `bonusCredits` | 赠送积分 |
|
||
| `credits` | 到账积分(如与赠送分开展示) |
|
||
| `title` | 商品文案(可能由服务端直接下发) |
|
||
|
||
---
|
||
|
||
## 5. 第三方支付流程(通用)
|
||
|
||
### 5.1 拉取支付方式
|
||
|
||
以商品或活动为上下文请求支付方式列表,常见字段包括:
|
||
|
||
- `paymentMethod`:主支付方式(例如平台内购、钱包、卡支付等)
|
||
- `subPaymentMethod`:子方式(可选)
|
||
- `name` / `icon`:展示信息
|
||
- `recommend`:是否推荐
|
||
|
||
### 5.2 创建订单
|
||
|
||
创建订单请求通常包含(**逻辑字段名**):
|
||
|
||
- 应用标识(`app`)
|
||
- 用户标识(`userId`)
|
||
- 商品或活动标识(`activityId` / `productId`)
|
||
- 支付主方式(`paymentMethod`)
|
||
- 支付类型(`paymentType`,按渠道语义填写)
|
||
- 子支付方式(`subPaymentMethod`,如卡种/钱包子通道)
|
||
|
||
> 关键点:`subPaymentMethod` 是独立语义字段。
|
||
> 仅传 `paymentType` 不会自动补出 `subPaymentMethod`。
|
||
|
||
#### 5.2.1 推荐入参组合(避免丢子支付方式)
|
||
|
||
- 卡支付场景(示例):
|
||
- `paymentMethod = MIFAPAY`
|
||
- `paymentType = MIFAPAY`(或按后端约定值)
|
||
- `subPaymentMethod = CreditCard`
|
||
- 若传成 `paymentType = CreditCard` 且未传 `subPaymentMethod`,常见结果是:
|
||
- 有 `paymentMethod`
|
||
- 有 `paymentType`
|
||
- **缺少 `subPaymentMethod`**
|
||
|
||
响应通常返回:
|
||
|
||
- `orderId`(业务订单号)
|
||
- `payUrl`(外部支付链接;仅外部支付场景)
|
||
- `status`(订单状态)
|
||
- 可选 `federation`(用于与商店订单映射)
|
||
|
||
### 5.3 分支执行
|
||
|
||
- **平台内购**:拉起商店购买 -> 取回凭据 -> 回调服务端核验 -> 成功后完成/消费交易。
|
||
- **外部支付**:打开 `payUrl` 完成支付 -> 回前台后查询订单状态或拉取账户余额。
|
||
|
||
---
|
||
|
||
## 6. 平台内购标准链路(Android/iOS 可类比)
|
||
|
||
1. 用 `productId` 调起商店支付;
|
||
2. 拿到商店返回的交易凭据(如 `purchaseData`、`signature`、`storeOrderId`);
|
||
3. 调服务端回调接口完成验签与入账;
|
||
4. 服务端成功后,客户端执行“完成交易/消费交易”(防止重复拥有问题);
|
||
5. 刷新账户余额与订单状态。
|
||
|
||
> 关键原则:**先服务端验单成功,再本地完成/消费交易**,避免凭据丢失导致资产不一致。
|
||
|
||
---
|
||
|
||
## 7. 补单机制(订单恢复)
|
||
|
||
### 7.1 触发时机
|
||
|
||
- 应用启动后;
|
||
- 进入充值页时;
|
||
- 支付异常返回时(例如网络中断、回调超时)。
|
||
|
||
### 7.2 恢复流程
|
||
|
||
1. 拉取未完成/未核销的商店订单(历史订单 + 监听流中的待处理订单);
|
||
2. 对每笔订单尝试找到业务订单映射(如 `federation` / `orderId`);
|
||
3. 若可映射:再次走服务端回调核验,成功后完成/消费交易;
|
||
4. 若不可映射:按产品策略处理(仅完成/消费以解除占用,或进入人工排查队列);
|
||
5. 恢复结束后刷新账户与充值记录。
|
||
|
||
---
|
||
|
||
## 8. API 能力清单(通用命名)
|
||
|
||
| 能力 | 典型方法 | 说明 |
|
||
|------|------|------|
|
||
| 获取商品列表 | `GET` | Android/iOS 可分端点 |
|
||
| 获取支付方式 | `POST`/`GET` | 入参通常含 `activityId` |
|
||
| 创建订单 | `POST` | 返回 `orderId`、`payUrl` 等 |
|
||
| 平台内购回调 | `POST` | 提交 `purchaseData`、`signature` 等 |
|
||
| 订单列表 | `GET` | 历史支付记录 |
|
||
| 订单详情 | `GET` | 查询单笔订单状态 |
|
||
|
||
---
|
||
|
||
## 9. 核心字段对照(通用)
|
||
|
||
| 业务含义 | 常见请求字段 | 常见响应字段 |
|
||
|------|------|------|
|
||
| 应用标识 | `app` | - |
|
||
| 用户标识 | `userId` | - |
|
||
| 活动/档位 | `activityId` | - |
|
||
| 支付方式 | `paymentMethod` | - |
|
||
| 子支付方式 | `paymentType` | - |
|
||
| 订单标识 | `orderId` / `id` | `orderId` |
|
||
| 购买签名 | `signature` | - |
|
||
| 购买数据 | `purchaseData` | - |
|
||
| 商品 ID | - | `productId` |
|
||
| 实付金额 | - | `actualAmount` |
|
||
| 原价 | - | `originAmount` |
|
||
| 赠送积分 | - | `bonus` / `bonusCredits` |
|
||
| 支付链接 | - | `payUrl` |
|
||
| 订单状态 | - | `status` |
|
||
|
||
---
|
||
|
||
## 10. 常见问题
|
||
|
||
### 10.1 商品未找到
|
||
|
||
- **现象**:发起内购时提示商品不存在;
|
||
- **常见原因**:客户端 `productId` 与商店后台配置不一致,或商品未上架到当前测试轨道;
|
||
- **排查建议**:核对包名/应用 ID、商品 ID、地区、测试账号与轨道配置。
|
||
|
||
### 10.2 回调成功但积分未更新
|
||
|
||
- **现象**:支付侧显示成功,账户余额未变;
|
||
- **常见原因**:回调后未刷新账户、订单状态未落库、幂等冲突;
|
||
- **排查建议**:检查回调响应、订单状态接口与账户刷新链路。
|
||
|
||
### 10.3 重复购买被拦截(已拥有此内容)
|
||
|
||
- **现象**:商店提示已拥有,无法再次购买;
|
||
- **常见原因**:上一笔交易未完成/未消费;
|
||
- **排查建议**:执行补单恢复流程并确保完成/消费逻辑成功。
|
||
|
||
### 10.4 创建订单请求缺少子支付方式字段
|
||
|
||
- **现象**:抓包中 `createPayment` 入参有 `paymentMethod`,但缺少 `subPaymentMethod`;
|
||
- **常见原因**:只传了 `paymentType`,没有传 `subPaymentMethod`;
|
||
- **排查建议**:
|
||
- 检查应用侧建单调用是否显式传入 `subPaymentMethod`;
|
||
- 对照请求日志逐项核对三元组:`paymentMethod` / `paymentType` / `subPaymentMethod`;
|
||
- 若项目启用了字段映射,再额外确认映射配置与服务端契约一致。
|
||
|
||
---
|
||
|
||
## 11. 实施建议(多客户端复用)
|
||
|
||
- 以“流程能力层”封装支付,不把分支逻辑写死在页面;
|
||
- 页面只关心:档位展示、用户选择、状态反馈;
|
||
- 建单、回调、补单、轮询统一由支付服务层负责;
|
||
- 统一错误码与文案映射,避免各端提示不一致;
|
||
- 对关键节点埋点:拉起支付、建单成功、回调成功、补单成功、入账成功;
|
||
- 保持接口字段可映射,支持不同换皮应用的字段命名差异。
|
||
|