208 lines
7.2 KiB
Markdown
208 lines
7.2 KiB
Markdown
|
|
# 云印签支付流程完整性检查
|
|||
|
|
|
|||
|
|
## 一、支付创建流程
|
|||
|
|
|
|||
|
|
### 1. 前端流程 ✅
|
|||
|
|
- **位置**: `jnc-webview/src/components/Payment.vue`
|
|||
|
|
- **步骤**:
|
|||
|
|
1. 用户选择 `yunyinSignPay_wechat` 或 `yunyinSignPay_alipay`
|
|||
|
|
2. 调用 `/pay/payment` 接口
|
|||
|
|
3. 获取 `prepay_id` 或 `prepay_data`(支付链接)
|
|||
|
|
4. 直接跳转到支付链接:`window.location.href = prepayUrl`
|
|||
|
|
|
|||
|
|
### 2. 后端流程 ✅
|
|||
|
|
- **位置**: `jnc-server/app/main/api/internal/logic/pay/paymentlogic.go`
|
|||
|
|
- **步骤**:
|
|||
|
|
1. 接收支付请求
|
|||
|
|
2. 从查询缓存获取用户姓名和手机号
|
|||
|
|
3. **查询是否有未完成的签署**(复用逻辑)
|
|||
|
|
4. 如果有未完成签署:
|
|||
|
|
- 复用 `task_id` 和 `participant_id`
|
|||
|
|
- 获取新的支付链接
|
|||
|
|
5. 如果没有未完成签署:
|
|||
|
|
- 获取 token 和操作ID(带缓存)
|
|||
|
|
- 发起签署流程
|
|||
|
|
- 获取支付链接
|
|||
|
|
6. 创建订单记录(`order` 表)
|
|||
|
|
7. 创建云印签订单记录(`yunyin_sign_pay_order` 表)
|
|||
|
|
8. 返回支付链接(字符串类型,使用 `PrepayId` 字段)
|
|||
|
|
|
|||
|
|
### 3. 数据存储 ✅
|
|||
|
|
- **订单表** (`order`):
|
|||
|
|
- `order_no`: 订单号
|
|||
|
|
- `payment_platform`: `yunyinSignPay_wechat` 或 `yunyinSignPay_alipay`
|
|||
|
|
- `status`: `pending`
|
|||
|
|
- **注意**: 不再在 `remark` 中存储云印签信息
|
|||
|
|
|
|||
|
|
- **云印签订单表** (`yunyin_sign_pay_order`):
|
|||
|
|
- `order_id`: 关联订单ID
|
|||
|
|
- `user_id`: 用户ID(用于查询未完成签署)
|
|||
|
|
- `task_id`: 任务ID/流程ID(唯一索引)
|
|||
|
|
- `participant_id`: 参与者ID
|
|||
|
|
- `source_order_code`: 源订单号(用于查询支付状态)
|
|||
|
|
- `amount`: 支付金额
|
|||
|
|
- `pay_type`: 支付类型(0=微信,1=支付宝)
|
|||
|
|
- `sign_status`: 签署状态(0=待签署)
|
|||
|
|
- `pay_status`: 支付状态(0=待支付)
|
|||
|
|
- `user_mobile`: 用户手机号(冗余字段)
|
|||
|
|
- `user_name`: 用户姓名(冗余字段)
|
|||
|
|
|
|||
|
|
## 二、支付状态查询流程
|
|||
|
|
|
|||
|
|
### 1. 前端轮询 ✅
|
|||
|
|
- **位置**: `jnc-webview/src/views/PaymentResult.vue`
|
|||
|
|
- **步骤**:
|
|||
|
|
1. 用户从支付页面返回后,进入支付结果页面
|
|||
|
|
2. 从 URL 参数获取 `order_no` 或 `out_trade_no`
|
|||
|
|
3. 首次调用 `/pay/check` 接口
|
|||
|
|
4. 如果状态是 `pending`,开始轮询(每3秒一次,最多30次)
|
|||
|
|
5. 如果状态变为 `paid` 或 `refunded`,停止轮询并跳转到结果页面
|
|||
|
|
|
|||
|
|
### 2. 后端主动查询 ✅
|
|||
|
|
- **位置**: `jnc-server/app/main/api/internal/logic/pay/paymentchecklogic.go`
|
|||
|
|
- **步骤**:
|
|||
|
|
1. 查询订单状态
|
|||
|
|
2. 如果订单状态是 `pending` 且支付平台是云印签:
|
|||
|
|
- 调用 `QueryPayeeBill` 查询云印签平台
|
|||
|
|
- 使用 `sourceOrderCode`(订单号)查询
|
|||
|
|
3. 根据云印签返回的 `payStatus` 更新订单状态:
|
|||
|
|
- `2` (支付成功) → `paid`
|
|||
|
|
- `3` (支付失败) → `failed`
|
|||
|
|
- `4` (已退款) → `refunded`
|
|||
|
|
- `0, 1` (订单生成/支付中) → 保持 `pending`
|
|||
|
|
4. 同步更新 `yunyin_sign_pay_order` 表的支付状态
|
|||
|
|
5. 如果支付成功,发送异步任务处理后续流程
|
|||
|
|
|
|||
|
|
### 3. 状态映射 ✅
|
|||
|
|
- **云印签 payStatus**:
|
|||
|
|
- `0`: 订单生成
|
|||
|
|
- `1`: 支付中
|
|||
|
|
- `2`: 支付成功
|
|||
|
|
- `3`: 支付失败
|
|||
|
|
- `4`: 已退款
|
|||
|
|
|
|||
|
|
- **我们的订单状态**:
|
|||
|
|
- `pending`: 待支付
|
|||
|
|
- `paid`: 已支付
|
|||
|
|
- `failed`: 支付失败
|
|||
|
|
- `refunded`: 已退款
|
|||
|
|
|
|||
|
|
- **我们的支付状态** (`yunyin_sign_pay_order.pay_status`):
|
|||
|
|
- `0`: 待支付
|
|||
|
|
- `1`: 已支付
|
|||
|
|
- `2`: 已退款
|
|||
|
|
|
|||
|
|
## 三、前后端数据字段一致性 ✅
|
|||
|
|
|
|||
|
|
### 1. 支付创建接口 (`/pay/payment`)
|
|||
|
|
- **请求字段**: `pay_method` (支持 `yunyinSignPay_wechat`, `yunyinSignPay_alipay`)
|
|||
|
|
- **响应字段**:
|
|||
|
|
- `prepay_id`: 支付链接(字符串类型)
|
|||
|
|
- `prepay_data`: 备用字段(对象类型)
|
|||
|
|
- `order_no`: 订单号
|
|||
|
|
|
|||
|
|
- **前端读取**: `data.value.data.prepay_id || data.value.data.prepay_data` ✅
|
|||
|
|
|
|||
|
|
### 2. 支付状态查询接口 (`/pay/check`)
|
|||
|
|
- **请求字段**: `order_no`
|
|||
|
|
- **响应字段**:
|
|||
|
|
- `type`: `"query"`
|
|||
|
|
- `status`: `"pending"` | `"paid"` | `"failed"` | `"refunded"`
|
|||
|
|
|
|||
|
|
- **前端处理**: 根据 `status` 判断是否继续轮询 ✅
|
|||
|
|
|
|||
|
|
## 四、潜在问题和改进建议
|
|||
|
|
|
|||
|
|
### ⚠️ 问题1: 支付完成后用户可能不会自动跳转
|
|||
|
|
**现状**: 云印签支付完成后,用户可能不会自动跳转回我们的页面
|
|||
|
|
**解决方案**:
|
|||
|
|
- ✅ 已实现:前端通过轮询主动查询支付状态
|
|||
|
|
- ✅ 已实现:用户手动返回后,支付结果页面会自动轮询
|
|||
|
|
|
|||
|
|
### ⚠️ 问题2: 订单状态更新需要检查并发
|
|||
|
|
**现状**: 使用乐观锁更新订单状态,但需要确保不会重复更新
|
|||
|
|
**检查**: ✅ 已实现:使用 `UpdateWithVersion` 和检查 `order.Status == "pending"`
|
|||
|
|
|
|||
|
|
### ⚠️ 问题3: 查询失败时的处理
|
|||
|
|
**现状**: 如果查询云印签平台失败,会记录错误但继续返回当前状态
|
|||
|
|
**检查**: ✅ 已实现:错误处理完善,不影响正常流程
|
|||
|
|
|
|||
|
|
### ⚠️ 问题4: 未找到收款单记录的处理
|
|||
|
|
**现状**: 如果订单刚创建,云印签平台可能还没有记录
|
|||
|
|
**检查**: ✅ 已实现:返回错误但不影响,继续返回 `pending` 状态,前端会继续轮询
|
|||
|
|
|
|||
|
|
## 五、完整流程验证
|
|||
|
|
|
|||
|
|
### 场景1: 首次支付(创建新签署流程)✅
|
|||
|
|
1. 用户选择云印签支付
|
|||
|
|
2. 后端查询无未完成签署
|
|||
|
|
3. 创建新签署流程
|
|||
|
|
4. 创建订单和云印签订单记录
|
|||
|
|
5. 返回支付链接
|
|||
|
|
6. 前端跳转到支付页面
|
|||
|
|
7. 用户完成支付
|
|||
|
|
8. 前端轮询查询状态
|
|||
|
|
9. 后端主动查询云印签平台
|
|||
|
|
10. 更新订单状态为 `paid`
|
|||
|
|
11. 发送异步任务处理后续流程
|
|||
|
|
12. 前端跳转到结果页面
|
|||
|
|
|
|||
|
|
### 场景2: 复用未完成签署 ✅
|
|||
|
|
1. 用户之前创建了签署但未支付
|
|||
|
|
2. 用户再次选择云印签支付
|
|||
|
|
3. 后端查询到未完成签署
|
|||
|
|
4. 复用 `task_id` 和 `participant_id`
|
|||
|
|
5. 获取新的支付链接
|
|||
|
|
6. 创建新订单和云印签订单记录(关联新的订单)
|
|||
|
|
7. 返回支付链接
|
|||
|
|
8. 后续流程同场景1
|
|||
|
|
|
|||
|
|
### 场景3: 支付失败 ✅
|
|||
|
|
1. 用户支付失败
|
|||
|
|
2. 前端轮询查询状态
|
|||
|
|
3. 后端查询到 `payStatus = 3`
|
|||
|
|
4. 更新订单状态为 `failed`
|
|||
|
|
5. 前端显示支付失败提示
|
|||
|
|
|
|||
|
|
### 场景4: 退款 ✅
|
|||
|
|
1. 订单已支付
|
|||
|
|
2. 发生退款
|
|||
|
|
3. 前端轮询查询状态
|
|||
|
|
4. 后端查询到 `payStatus = 4`
|
|||
|
|
5. 更新订单状态为 `refunded`
|
|||
|
|
6. 更新退款时间
|
|||
|
|
7. 前端显示退款状态
|
|||
|
|
|
|||
|
|
## 六、总结
|
|||
|
|
|
|||
|
|
### ✅ 已完成的流程
|
|||
|
|
1. 支付创建流程(包括复用逻辑)
|
|||
|
|
2. 支付状态主动查询
|
|||
|
|
3. 订单状态自动更新
|
|||
|
|
4. 云印签订单表数据同步
|
|||
|
|
5. 前后端数据字段一致性
|
|||
|
|
6. 错误处理和边界情况
|
|||
|
|
|
|||
|
|
### ✅ 代码质量
|
|||
|
|
- 使用了事务保证数据一致性
|
|||
|
|
- 使用了乐观锁避免并发问题
|
|||
|
|
- 错误处理完善
|
|||
|
|
- 日志记录详细
|
|||
|
|
|
|||
|
|
### ✅ 前后端联调
|
|||
|
|
- API 接口定义清晰
|
|||
|
|
- 数据字段命名一致
|
|||
|
|
- 状态映射正确
|
|||
|
|
- 轮询机制完善
|
|||
|
|
|
|||
|
|
## 七、建议测试点
|
|||
|
|
|
|||
|
|
1. **首次支付流程**: 验证创建新签署流程是否正常
|
|||
|
|
2. **复用签署流程**: 验证复用逻辑是否正常工作
|
|||
|
|
3. **支付成功**: 验证状态更新和后续流程是否正常
|
|||
|
|
4. **支付失败**: 验证失败状态是否正确处理
|
|||
|
|
5. **退款**: 验证退款状态是否正确处理
|
|||
|
|
6. **网络异常**: 验证查询失败时的容错处理
|
|||
|
|
7. **并发支付**: 验证同一用户多次支付的场景
|
|||
|
|
8. **订单状态一致性**: 验证订单表和云印签订单表的状态是否同步
|