171 lines
4.5 KiB
Markdown
171 lines
4.5 KiB
Markdown
|
|
# PayPal Webhook处理指南
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
PayPal Webhook是PayPal向你的服务器发送事件通知的机制。当支付状态发生变化时,PayPal会主动推送事件到你的Webhook URL。
|
|||
|
|
|
|||
|
|
## Webhook URL配置
|
|||
|
|
|
|||
|
|
在你的PayPal开发者控制台中配置Webhook URL:
|
|||
|
|
- **开发环境**: `https://你的域名/api/paypal/webhook`
|
|||
|
|
- **生产环境**: `https://你的生产域名/api/paypal/webhook`
|
|||
|
|
|
|||
|
|
## 支持的事件类型
|
|||
|
|
|
|||
|
|
系统已实现以下事件类型的处理:
|
|||
|
|
|
|||
|
|
### 1. PAYMENT.CAPTURE.COMPLETED
|
|||
|
|
**触发时机**: 当PayPal成功捕获资金时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 提取capture信息(金额、货币、状态等)
|
|||
|
|
- 通过`supplementary_data.related_ids.order_id`或`custom_id`获取ERP订单号
|
|||
|
|
- 更新ERP订单状态为"已支付"(PAID)
|
|||
|
|
|
|||
|
|
### 2. PAYMENT.CAPTURE.DENIED
|
|||
|
|
**触发时机**: 当支付捕获被拒绝时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 记录支付失败信息
|
|||
|
|
- 更新ERP订单状态为"支付失败"
|
|||
|
|
|
|||
|
|
### 3. PAYMENT.CAPTURE.REFUNDED
|
|||
|
|
**触发时机**: 当支付被退款时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 记录退款信息
|
|||
|
|
- 更新ERP订单状态为"已退款"
|
|||
|
|
|
|||
|
|
### 4. CHECKOUT.ORDER.APPROVED
|
|||
|
|
**触发时机**: 当订单被顾客批准时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 记录订单批准信息
|
|||
|
|
- 可以触发自动捕获逻辑(如果需要)
|
|||
|
|
|
|||
|
|
### 5. CHECKOUT.ORDER.COMPLETED
|
|||
|
|
**触发时机**: 当订单完成时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 记录订单完成信息
|
|||
|
|
- 根据业务需求处理订单完成逻辑
|
|||
|
|
|
|||
|
|
### 6. CHECKOUT.ORDER.CANCELLED
|
|||
|
|
**触发时机**: 当订单被取消时触发
|
|||
|
|
|
|||
|
|
**处理逻辑**:
|
|||
|
|
- 记录订单取消信息
|
|||
|
|
- 更新ERP订单状态为"已取消"
|
|||
|
|
|
|||
|
|
## 签名验证
|
|||
|
|
|
|||
|
|
### 开发环境(沙箱)
|
|||
|
|
- 签名验证可以暂时跳过(已实现自动跳过)
|
|||
|
|
- 但建议在测试时也启用验证,确保代码正确
|
|||
|
|
|
|||
|
|
### 生产环境
|
|||
|
|
- **必须启用签名验证**
|
|||
|
|
- 需要在配置文件中设置`webhook-id`
|
|||
|
|
- 系统会自动验证每个Webhook请求的签名
|
|||
|
|
|
|||
|
|
## 配置Webhook ID
|
|||
|
|
|
|||
|
|
### 1. 获取Webhook ID
|
|||
|
|
|
|||
|
|
1. 登录PayPal开发者控制台:https://developer.paypal.com/dashboard/
|
|||
|
|
2. 进入你的应用设置
|
|||
|
|
3. 找到Webhook配置部分
|
|||
|
|
4. 创建或查看Webhook,获取Webhook ID
|
|||
|
|
|
|||
|
|
### 2. 配置到系统
|
|||
|
|
|
|||
|
|
在`application-dev.yml`或`application-prod.yml`中添加:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
paypal:
|
|||
|
|
webhook-id: YOUR_WEBHOOK_ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 订单号关联
|
|||
|
|
|
|||
|
|
PayPal Webhook事件中需要关联ERP订单号,系统会按以下顺序尝试获取:
|
|||
|
|
|
|||
|
|
1. **从`supplementary_data.related_ids.order_id`获取**
|
|||
|
|
- 这是PayPal自动填充的,包含原始订单ID
|
|||
|
|
- 然后通过查询PayPal订单详情获取`reference_id`(即ERP订单号)
|
|||
|
|
|
|||
|
|
2. **从`custom_id`获取**
|
|||
|
|
- 如果创建PayPal订单时设置了`custom_id`,可以直接获取
|
|||
|
|
|
|||
|
|
3. **通过`order_id`查询订单详情**
|
|||
|
|
- 如果上述方法都无法获取,会通过PayPal API查询订单详情
|
|||
|
|
- 从订单的`purchase_units[0].reference_id`获取ERP订单号
|
|||
|
|
|
|||
|
|
## 测试Webhook
|
|||
|
|
|
|||
|
|
### 使用PayPal Webhook模拟器
|
|||
|
|
|
|||
|
|
1. 登录PayPal开发者控制台
|
|||
|
|
2. 进入Webhook配置页面
|
|||
|
|
3. 使用"Send test webhook"功能
|
|||
|
|
4. 选择要测试的事件类型
|
|||
|
|
5. 系统会收到测试事件并处理
|
|||
|
|
|
|||
|
|
### 本地测试
|
|||
|
|
|
|||
|
|
如果需要在本地测试,可以使用以下工具:
|
|||
|
|
|
|||
|
|
1. **ngrok**(推荐):
|
|||
|
|
```bash
|
|||
|
|
ngrok http 8082
|
|||
|
|
```
|
|||
|
|
然后将ngrok提供的URL配置到PayPal Webhook URL
|
|||
|
|
|
|||
|
|
2. **PayPal Webhook模拟器**:
|
|||
|
|
使用Postman等工具模拟Webhook请求
|
|||
|
|
|
|||
|
|
## 日志查看
|
|||
|
|
|
|||
|
|
Webhook处理的所有步骤都会记录日志,包括:
|
|||
|
|
- 接收到的Webhook事件
|
|||
|
|
- 签名验证结果
|
|||
|
|
- 事件处理过程
|
|||
|
|
- 订单状态更新结果
|
|||
|
|
|
|||
|
|
查看日志位置:
|
|||
|
|
- 应用日志文件
|
|||
|
|
- 控制台输出
|
|||
|
|
|
|||
|
|
## 常见问题
|
|||
|
|
|
|||
|
|
### 1. Webhook未收到事件
|
|||
|
|
- 检查Webhook URL是否正确配置
|
|||
|
|
- 确认服务器可以访问(防火墙、网络等)
|
|||
|
|
- 检查PayPal控制台中的Webhook状态
|
|||
|
|
|
|||
|
|
### 2. 签名验证失败
|
|||
|
|
- 确认Webhook ID配置正确
|
|||
|
|
- 检查请求头是否完整
|
|||
|
|
- 确认使用的是正确的环境(沙箱/生产)
|
|||
|
|
|
|||
|
|
### 3. 无法关联ERP订单
|
|||
|
|
- 确认创建PayPal订单时设置了`reference_id`
|
|||
|
|
- 检查订单号格式是否正确
|
|||
|
|
- 查看日志中的详细信息
|
|||
|
|
|
|||
|
|
## 安全建议
|
|||
|
|
|
|||
|
|
1. **生产环境必须启用签名验证**
|
|||
|
|
2. **使用HTTPS**(PayPal要求)
|
|||
|
|
3. **记录所有Webhook事件**(用于审计和调试)
|
|||
|
|
4. **实现幂等性处理**(防止重复处理同一事件)
|
|||
|
|
5. **设置超时和重试机制**
|
|||
|
|
|
|||
|
|
## 代码位置
|
|||
|
|
|
|||
|
|
- **Webhook控制器**: `PayPalController.webhook()`
|
|||
|
|
- **Webhook服务**: `PayPalWebhookService` 和 `PayPalWebhookServiceImpl`
|
|||
|
|
- **事件DTO**: `PayPalWebhookEventDTO`
|
|||
|
|
- **配置**: `PayPalProperties.webhookId`
|
|||
|
|
|