## 获取收钱吧提供的资料

| 资料              | 来源                         | 开发时的用途                                   |
| ----------------- | ---------------------------- | ---------------------------------------------- |
| `vendor_sn`       | 收钱吧提供                   | 标识接入方开发者，仅在激活终端时作为签名序列号 |
| `vendor_key`      | 收钱吧提供                   | 生成激活请求签名                               |
| `app_id`          | 收钱吧提供                   | 标识本次激活对应的应用                         |
| 测试激活码 `code` | 收钱吧提供                   | 在测试门店下生成测试终端                       |
| 正式激活码 `code` | 上线前由收钱吧或商户后台提供 | 在正式门店下生成正式终端                       |
| API接入域名       | 开放平台                     | 拼接标准接口请求地址                           |

> `vendor_sn`、`vendor_key`和`app_id`不是支付接口的调用凭证。它们用于激活终端；激活成功后，支付、查询和退款使用返回的`terminal_sn`和`terminal_key`。

收到参数后应保存到服务端安全配置或密钥管理系统，不得放进前端代码、二维码、公开代码仓库或普通业务日志。

## 准备商户系统能力

| 能力         | 准备要求                                                     |
| ------------ | ------------------------------------------------------------ |
| 设备标识     | 为每台商户设备生成稳定且全局唯一的`device_id`                |
| 商户订单号   | 每次支付使用能够在商户系统中唯一定位业务订单的编号           |
| 回调地址     | 准备可被收钱吧公网访问的HTTPS地址，支持验签、重复通知和幂等处理 |
| 真实公网IP   | 按支付场景取得顾客手机或收银设备的真实公网IP                 |
| 终端参数存储 | 安全保存`terminal_sn`、`terminal_key`及其所属门店和设备      |
| 订单状态     | 能够保存支付中、成功、失败、结果未知和退款等状态             |
| 主动查询     | 支付请求超时或返回非最终状态时，能够在后台查询原订单         |

`device_id`必须稳定且全局唯一，不得在不同应用、门店或设备之间重复使用。设备更换或终端关系需要重建时，应按照终端恢复流程处理，不要直接复用其他设备的`device_id`或终端参数。

## 建立参数关联关系

系统中至少要保存以下归属关系：

```text
开发者
└── 应用
    └── 商户
        └── 门店
            ├── 商户设备A（全局唯一device_id）
            │   └── 收钱吧终端A（terminal_sn、terminal_key）
            └── 商户设备B（全局唯一device_id）
                └── 收钱吧终端B（terminal_sn、terminal_key）
```

建议为每个终端保存：

- 商户和门店的内部编号。
- `app_id`和`device_id`。
- `terminal_sn`和加密后的`terminal_key`。
- 凭证更新时间和当前状态。

不要把一套终端参数作为所有门店共用的全局配置。否则多门店、多设备运行时无法确定交易归属，签到更新密钥时也可能影响其他设备。

## 激活终端

支付、查询和退款使用收钱吧终端参数。在开发具体支付场景前，先为测试门店的实际设备激活终端。

```text
准备app_id、测试激活码和device_id
→ 使用vendor_sn和vendor_key签名
→ 调用激活接口
→ 读取terminal_sn和terminal_key
→ 与应用、门店和device_id绑定保存
```

### 准备激活参数

| 数据                      | 从哪里取得                 | 用于什么         |
| ------------------------- | -------------------------- | ---------------- |
| `vendor_sn`、`vendor_key` | 收钱吧提供                 | 对激活请求签名   |
| `app_id`                  | 收钱吧提供                 | 指定终端所属应用 |
| `code`                    | 目标测试或正式门店的激活码 | 指定终端所属门店 |
| `device_id`               | 商户系统生成               | 标识实际收款设备 |

同一门店增加设备时，可以在激活码仍有效且有剩余次数的情况下使用同一个激活码，但每台设备必须使用不同且全局唯一的`device_id`。

### 调用激活接口

使用`vendor_sn`作为签名序列号、`vendor_key`作为签名密钥，调用**[激活接口](https://open.shouqianba.com/docs/payment/67?category_id=58)**。

先按[交易结果与异常处理](https://open.shouqianba.com/docs/payment/77)判断通信结果和业务结果。只有确认激活成功后，才读取响应中的`terminal_sn`和`terminal_key`。

### 保存终端参数

激活成功后，将`terminal_sn`和`terminal_key`与当前`app_id`、门店、设备和`device_id`一起保存。终端密钥应加密存储；保存成功前，不允许该设备发起支付。

建议在同一事务内保存终端号、终端密钥和启用状态，避免业务节点读取到不完整的终端配置。

### 处理激活异常

- 明确失败：按错误信息修正参数，不保存终端参数。
- 超时或响应无法解析：先确认原设备是否已生成终端，不要更换`device_id`盲目重试。
- 提示设备已激活：恢复原设备与终端的关系，不生成随机`device_id`绕过。
- 激活码过期或次数不足：取得目标门店的新激活码。
- 终端参数遗失：联系收钱吧确认恢复或解绑方案后再激活。

## 签到并更新终端密钥

签到用于取得最新终端密钥。建议每天首次交易前执行。

```text
读取当前terminal_sn和terminal_key
→ 使用当前终端参数签名
→ 调用签到接口
→ 校验响应
→ 原子保存返回的最新终端参数
→ 所有业务节点切换到新密钥
```

### 调用签到接口

使用当前`terminal_sn`和`terminal_key`签名，提交激活时使用的同一个`device_id`，调用**[签到接口](https://open.shouqianba.com/docs/payment/68?category_id=58)**。

不要提前删除旧密钥。收到并校验签到成功响应后，再替换本地终端参数。

### 原子更新密钥

- 在同一事务中保存响应中的最新`terminal_sn`和`terminal_key`。
- 提交成功后，才允许新交易读取新密钥。
- 集群部署时从共享数据库或密钥服务读取，不由各节点单独维护。
- 确认业务节点已切换后，再结束本次签到任务。

### 处理签到结果未知

签到请求超时后，无法直接判断服务端是否已经更新密钥。此时：

- 暂停该终端的后续签到任务，保留当前本地参数。
- 排除网络问题后，使用本地保存的终端参数再次签到。
- 获得成功响应后，原子保存响应中的最新密钥。
- 持续签名错误或仍无法确认时，停止自动重试并进入人工恢复流程。
- 批量签到发生共性异常时，暂停后续批次，避免扩大密钥不同步范围。

## 确认测试环境

- 中国大陆移动支付API使用`https://vsi-api.shouqianba.com`。
- 测试激活码对应收钱吧提供的测试门店；正式上线时使用正式门店激活码重新生成终端。
- 测试和正式业务通常使用相同API域名，不能通过更换域名区分环境。
- 支付测试会产生真实交易，测试完成后应按原交易发起退款。
- 小程序支付还需完成商户与目标小程序的支付关系配置。
- 公众号与H5支付需要能够在目标钱包环境中打开页面并访问回调服务。

## 开发前检查

- [ ] 已确认支付场景。
- [ ] 已取得`vendor_sn`、`vendor_key`、`app_id`和测试激活码。
- [ ] 已定义全局唯一的`device_id`生成规则。
- [ ] 已建立门店、设备和终端参数的存储关系。
- [ ] 已调用激活接口并安全保存测试终端参数。
- [ ] 已验证签到成功后能够原子更新终端密钥。
- [ ] 所有业务节点能够读取同一份最新终端密钥。
- [ ] 服务端能够访问正确的API域名。
- [ ] 已准备唯一商户订单号。
- [ ] 支付回调地址可以从公网访问。
- [ ] 已确定当前场景的真实公网IP来源。
- [ ] 密钥不会进入前端、二维码、公开仓库或普通日志。
