This commit is contained in:
Your Name
2026-04-15 16:31:25 +08:00
parent 906684c1ed
commit 3d9c5dd8f5
47 changed files with 7963 additions and 10 deletions
+355
View File
@@ -0,0 +1,355 @@
# 甘草订单状态回调功能配置指南
## 功能说明
实现甘草订单状态回调功能,当甘草订单状态发生变化时(如审核通过、制作中、发货、完成等),甘草系统会主动回调我们的接口,更新订单状态。
## 已创建的文件
### 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