356 lines
8.2 KiB
Markdown
356 lines
8.2 KiB
Markdown
# 甘草订单状态回调功能配置指南
|
||
|
||
## 功能说明
|
||
|
||
实现甘草订单状态回调功能,当甘草订单状态发生变化时(如审核通过、制作中、发货、完成等),甘草系统会主动回调我们的接口,更新订单状态。
|
||
|
||
## 已创建的文件
|
||
|
||
### 1. 回调控制器
|
||
**文件:** `server/app/api/controller/GancaoCallbackController.php`
|
||
|
||
**功能:**
|
||
- 接收甘草订单状态回调
|
||
- 验证回调签名(防止伪造)
|
||
- 更新订单状态
|
||
- 记录回调日志
|
||
|
||
**支持的订单状态:**
|
||
- `10` - 系统审核中
|
||
- `11` - 系统审核通过
|
||
- `110` - 订单药房流转制作中(包含:派单、审方、调配、复核、浸泡、煎药、包装、发货等流程)
|
||
- `20` - 物流中
|
||
- `30` - 完成(终态)
|
||
- `90` - 拦截(终止流转:可恢复)
|
||
- `91` - 主动撤单(退费:终态)
|
||
- `92` - 驳回(无法制作并退费:终态)
|
||
|
||
### 2. 数据库迁移文件
|
||
**文件:** `add_gancao_callback_fields.sql`
|
||
|
||
**新增字段:**
|
||
- `gancao_order_state` - 甘草订单状态
|
||
- `gancao_flow_name` - 订单流程名称
|
||
- `gancao_supplier` - 供应商/药房名称
|
||
- `gancao_remark` - 订单备注
|
||
|
||
## 配置步骤
|
||
|
||
### 步骤 1: 执行数据库迁移
|
||
|
||
```bash
|
||
# 连接到数据库
|
||
mysql -u root -p your_database
|
||
|
||
# 执行 SQL 文件
|
||
source /path/to/add_gancao_callback_fields.sql;
|
||
|
||
# 或者直接执行
|
||
mysql -u root -p your_database < add_gancao_callback_fields.sql
|
||
```
|
||
|
||
### 步骤 2: 添加路由
|
||
|
||
在 `server/route/api.php` 文件中添加回调路由:
|
||
|
||
```php
|
||
<?php
|
||
use think\facade\Route;
|
||
|
||
// 甘草订单状态回调(不需要登录验证)
|
||
Route::post('gancao/callback/order-status', 'GancaoCallbackController@orderStatus');
|
||
```
|
||
|
||
**注意:** 这个路由不需要登录验证,因为是甘草系统主动回调。
|
||
|
||
### 步骤 3: 配置回调 URL
|
||
|
||
在 `.env` 文件中配置回调地址:
|
||
|
||
```env
|
||
# 甘草回调配置
|
||
GANCAO_SCM_CALLBACK_URL=https://your-domain.com/api/gancao/callback/order-status
|
||
|
||
# 回调签名验证(可选,如果甘草提供了独立的回调密钥)
|
||
# GANCAO_SCM_CALLBACK_APPKEY=your_callback_appkey
|
||
# GANCAO_SCM_CALLBACK_SECRET_KEY=your_callback_secret_key
|
||
```
|
||
|
||
**重要:**
|
||
1. 回调地址必须是 **HTTPS**
|
||
2. 回调地址必须能从公网访问
|
||
3. 如果是开发环境,可以使用内网穿透工具(如 ngrok)
|
||
|
||
### 步骤 4: 更新配置文件
|
||
|
||
在 `server/config/gancao_scm.php` 中添加回调配置:
|
||
|
||
```php
|
||
return [
|
||
// ... 其他配置
|
||
|
||
'callback_url' => (string) zyt_gancao_scm_env('CALLBACK_URL', ''),
|
||
|
||
// 回调签名验证(如果甘草提供了独立的密钥)
|
||
'callback_appkey' => (string) zyt_gancao_scm_env('CALLBACK_APPKEY', ''),
|
||
'callback_secret_key' => (string) zyt_gancao_scm_env('CALLBACK_SECRET_KEY', ''),
|
||
];
|
||
```
|
||
|
||
### 步骤 5: 测试回调接口
|
||
|
||
#### 方法 A:使用 curl 测试
|
||
|
||
```bash
|
||
# 模拟甘草回调请求
|
||
curl -X POST https://your-domain.com/api/gancao/callback/order-status \
|
||
-H "Content-Type: application/json" \
|
||
-H "access-appkey: your_appkey" \
|
||
-H "access-nonce: test1234" \
|
||
-H "access-timestamp: $(date +%s)" \
|
||
-H "access-sign: calculated_sign" \
|
||
-d '{
|
||
"recipel_order_no": "GC202604...",
|
||
"state": 11,
|
||
"ext": {
|
||
"flow_name": "审核通过"
|
||
}
|
||
}'
|
||
```
|
||
|
||
#### 方法 B:查看日志
|
||
|
||
```bash
|
||
# 查看回调日志
|
||
tail -f server/runtime/log/$(date +%Y%m%d).log | grep -i "gancao callback"
|
||
```
|
||
|
||
### 步骤 6: 向甘草提供回调地址
|
||
|
||
联系甘草技术支持,提供以下信息:
|
||
1. 回调地址:`https://your-domain.com/api/gancao/callback/order-status`
|
||
2. 确认回调签名验证方式
|
||
3. 测试回调是否正常
|
||
|
||
## 回调数据格式
|
||
|
||
### 请求头
|
||
|
||
```
|
||
access-appkey: ak-xxxxx
|
||
access-nonce: random_string
|
||
access-timestamp: 1234567890
|
||
access-sign: md5_hash
|
||
```
|
||
|
||
### 请求体
|
||
|
||
```json
|
||
{
|
||
"recipel_order_no": "GC202604...",
|
||
"state": 110,
|
||
"ext": {
|
||
"flow_name": "煎药开始",
|
||
"supplier": "XX药房"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 状态 110(制作中)的扩展信息
|
||
|
||
```json
|
||
{
|
||
"recipel_order_no": "GC202604...",
|
||
"state": 110,
|
||
"ext": {
|
||
"flow_name": "派单|审方|调配|复核|浸泡|煎药开始|包装|发货|寄出",
|
||
"supplier": "XX药房"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 状态 20(物流中)的扩展信息
|
||
|
||
```json
|
||
{
|
||
"recipel_order_no": "GC202604...",
|
||
"state": 20,
|
||
"ext": {
|
||
"shipping_name": "顺丰速运",
|
||
"nu": "SF1234567890",
|
||
"supplier": "XX药房"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 签名验证
|
||
|
||
### 签名算法
|
||
|
||
```
|
||
access_sign = md5(access-appkey + secret-key + access-nonce + access-timestamp + request_body)
|
||
```
|
||
|
||
### 示例
|
||
|
||
```
|
||
access-appkey: ak-36b05d5034f13a86b102c97e72f14
|
||
secret-key: f8c1f3c58b55a61a4d41242016d314ea
|
||
access-nonce: 1jd4u8ii
|
||
access-timestamp: 1723014934
|
||
Body: {"recipel_order_no":"1234","state":10,"ext":{"flow_name":"浸泡开始"}}
|
||
|
||
计算:
|
||
md5("ak-36b05d5034f13a86b102c97e72f14" + "f8c1f3c58b55a61a4d41242016d314ea" + "1jd4u8ii" + "1723014934" + '{"recipel_order_no":"1234","state":10,"ext":{"flow_name":"浸泡开始"}}')
|
||
= 03b46e3b385d1dceb183cad08e44f31f
|
||
```
|
||
|
||
## 订单状态映射
|
||
|
||
### 甘草状态 → 系统履约状态
|
||
|
||
| 甘草状态 | 状态名称 | 系统履约状态 | 说明 |
|
||
|---------|---------|-------------|------|
|
||
| 10 | 系统审核中 | 保持不变 | 甘草内部审核 |
|
||
| 11 | 系统审核通过 | 保持不变 | 审核通过,准备制作 |
|
||
| 110 | 订单药房流转制作中 | 2(履约中) | 药房制作流程 |
|
||
| 110(发货) | 发货/寄出 | 5(已发货) | 药房已发货 |
|
||
| 20 | 物流中 | 5(已发货) | 快递运输中 |
|
||
| 30 | 完成 | 3(已完成) | 订单完成 |
|
||
| 90 | 拦截 | 保持不变 | 订单被拦截 |
|
||
| 91 | 主动撤单 | 4(已取消) | 撤单并退费 |
|
||
| 92 | 驳回 | 4(已取消) | 无法制作并退费 |
|
||
|
||
## 日志记录
|
||
|
||
### 回调接收日志
|
||
|
||
```
|
||
[info] Gancao callback received: {
|
||
"headers": {...},
|
||
"body": {...}
|
||
}
|
||
```
|
||
|
||
### 回调处理日志
|
||
|
||
```
|
||
[info] Gancao callback processed: {
|
||
"order_id": 123,
|
||
"recipel_order_no": "GC202604...",
|
||
"state": 110,
|
||
"ext": {...}
|
||
}
|
||
```
|
||
|
||
### 订单日志
|
||
|
||
在 `zyt_prescription_order_log` 表中记录:
|
||
- `admin_name`: "甘草系统"
|
||
- `action`: "gancao_callback"
|
||
- `summary`: "甘草订单状态更新:系统审核通过"
|
||
|
||
## 错误处理
|
||
|
||
### 签名验证失败
|
||
|
||
```
|
||
[warning] Gancao callback sign verification failed
|
||
```
|
||
|
||
**处理:** 返回 "ok",避免甘草重试
|
||
|
||
### 订单不存在
|
||
|
||
```
|
||
[warning] Gancao callback order not found
|
||
```
|
||
|
||
**处理:** 返回 "ok",记录日志
|
||
|
||
### 更新失败
|
||
|
||
```
|
||
[error] Gancao callback update order failed
|
||
```
|
||
|
||
**处理:** 返回 "ok",记录错误日志
|
||
|
||
## 重试机制
|
||
|
||
甘草的重试策略:
|
||
- 如果回调失败(未返回 "ok" 或超时),会进行重试
|
||
- 最多重试 10 次
|
||
- 重试间隔:失败次数 × 5 分钟
|
||
|
||
**建议:**
|
||
1. 接口必须在 5 秒内返回 "ok"
|
||
2. 使用异步处理复杂逻辑
|
||
3. 即使处理失败也返回 "ok",避免重复回调
|
||
|
||
## 安全建议
|
||
|
||
1. **启用签名验证**:防止伪造回调
|
||
2. **记录所有回调**:便于排查问题
|
||
3. **限制访问频率**:防止恶意请求
|
||
4. **使用 HTTPS**:保护数据传输安全
|
||
5. **IP 白名单**:只允许甘草服务器 IP 访问(可选)
|
||
|
||
## 监控和告警
|
||
|
||
### 监控指标
|
||
|
||
1. 回调接收数量
|
||
2. 签名验证失败次数
|
||
3. 订单更新失败次数
|
||
4. 回调处理耗时
|
||
|
||
### 告警规则
|
||
|
||
1. 签名验证失败率 > 10%
|
||
2. 订单更新失败率 > 5%
|
||
3. 回调处理耗时 > 3 秒
|
||
|
||
## 测试清单
|
||
|
||
- [ ] 数据库字段已添加
|
||
- [ ] 路由已配置
|
||
- [ ] 回调 URL 已配置
|
||
- [ ] 签名验证正常
|
||
- [ ] 订单状态更新正常
|
||
- [ ] 日志记录正常
|
||
- [ ] 错误处理正常
|
||
- [ ] 已向甘草提供回调地址
|
||
- [ ] 已测试真实回调
|
||
|
||
## 故障排查
|
||
|
||
### 问题 1:收不到回调
|
||
|
||
**检查:**
|
||
1. 回调 URL 是否正确
|
||
2. 服务器是否能从公网访问
|
||
3. 防火墙是否开放端口
|
||
4. 路由是否配置正确
|
||
|
||
### 问题 2:签名验证失败
|
||
|
||
**检查:**
|
||
1. appkey 是否正确
|
||
2. secret-key 是否正确
|
||
3. 签名算法是否正确
|
||
4. 请求体是否被修改
|
||
|
||
### 问题 3:订单状态未更新
|
||
|
||
**检查:**
|
||
1. 订单是否存在
|
||
2. 数据库字段是否添加
|
||
3. 更新逻辑是否正确
|
||
4. 查看错误日志
|
||
|
||
## 相关文档
|
||
|
||
- 甘草 API 文档:https://apidoc.igancao.com/service-doc/scm-outer-recipel.html#订单状态回调
|
||
- ThinkPHP 路由文档:https://www.kancloud.cn/manual/thinkphp6_0/1037493
|