mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-17 21:03:17 +08:00
架构修复
This commit is contained in:
parent
4b729e6e21
commit
639732e6d1
@ -27,7 +27,7 @@ class Ccbpayment extends Common
|
||||
* 不需要登录的方法 (支付回调不需要登录)
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedLogin = ['callback', 'notify'];
|
||||
protected $noNeedLogin = ['notify'];
|
||||
|
||||
/**
|
||||
* 不需要权限的方法
|
||||
@ -98,7 +98,23 @@ class Ccbpayment extends Common
|
||||
$this->error('支付串生成失败: ' . $result['message']);
|
||||
}
|
||||
|
||||
// 5. 直接返回支付串(不再重复保存数据库!)
|
||||
// 5. ✅ 推送订单到建行(步骤2:调用订单推送接口将已提交订单)
|
||||
// ⚠️ 注意:此时推送的是未支付状态的订单
|
||||
try {
|
||||
$pushResult = $this->orderService->pushOrder($orderId);
|
||||
|
||||
if ($pushResult['status']) {
|
||||
Log::info('[建行支付] 订单推送成功 order_id:' . $orderId);
|
||||
} else {
|
||||
// ⚠️ 推送失败不阻塞支付流程,只记录日志
|
||||
Log::warning('[建行支付] 订单推送失败(不阻塞支付) order_id:' . $orderId . ' error:' . $pushResult['message']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// ⚠️ 推送异常不阻塞支付流程
|
||||
Log::error('[建行支付] 订单推送异常(不阻塞支付) order_id:' . $orderId . ' error:' . $e->getMessage());
|
||||
}
|
||||
|
||||
// 6. 返回支付串
|
||||
$this->success('支付串生成成功', $result['data']);
|
||||
|
||||
} catch (Exception $e) {
|
||||
@ -163,22 +179,6 @@ class Ccbpayment extends Common
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ⚠️ 已废弃: 支付回调 (前端调用)
|
||||
*
|
||||
* @deprecated 2025-01-20 该方法存在严重安全漏洞,已被queryPaymentStatus()替代
|
||||
* @see queryPaymentStatus()
|
||||
*/
|
||||
public function callback()
|
||||
{
|
||||
// 向后兼容:直接调用查询接口
|
||||
Log::warning('[建行支付] callback()已废弃,请前端改用queryPaymentStatus()接口');
|
||||
|
||||
// 将POST的order_id转为GET参数
|
||||
$_GET['order_id'] = $this->request->post('order_id', 0);
|
||||
|
||||
return $this->queryPaymentStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* 建行支付通知 (建行服务器回调)
|
||||
@ -224,19 +224,26 @@ class Ccbpayment extends Common
|
||||
// 6. 调用支付服务处理通知(返回订单ID)
|
||||
$result = $this->paymentService->handleNotify($params);
|
||||
|
||||
// 7. 处理成功后推送订单到建行外联系统
|
||||
// 7. ✅ 处理成功后更新订单状态到建行(步骤13:调用订单更新接口更新订单状态)
|
||||
if ($result['status'] === 'success' && !empty($result['order_id'])) {
|
||||
// ⚠️ 只有新支付才推送,已支付的订单跳过推送
|
||||
// ⚠️ 只有新支付才更新,已支付的订单跳过更新
|
||||
if ($result['already_paid'] === false) {
|
||||
try {
|
||||
$this->pushOrderToCcb($result['order_id']);
|
||||
Log::info('[建行通知] 订单推送成功 order_id:' . $result['order_id']);
|
||||
// 调用订单更新接口,将订单状态从未支付更新为已支付
|
||||
$updateResult = $this->orderService->updateOrderStatus($result['order_id']);
|
||||
|
||||
if ($updateResult['status']) {
|
||||
Log::info('[建行通知] 订单状态更新成功 order_id:' . $result['order_id']);
|
||||
} else {
|
||||
// ⚠️ 更新失败不影响本地支付状态,记录日志后续补推
|
||||
Log::warning('[建行通知] 订单状态更新失败(本地已支付) order_id:' . $result['order_id'] . ' error:' . $updateResult['message']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// ⚠️ 推送失败不影响支付成功,记录日志后续补推
|
||||
Log::error('[建行通知] 订单推送失败 order_id:' . $result['order_id'] . ' error:' . $e->getMessage());
|
||||
// ⚠️ 更新异常不影响支付成功,记录日志后续补推
|
||||
Log::error('[建行通知] 订单状态更新异常(本地已支付) order_id:' . $result['order_id'] . ' error:' . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
Log::info('[建行通知] 订单已支付且已推送,跳过推送 order_id:' . $result['order_id']);
|
||||
Log::info('[建行通知] 订单已支付且已更新,跳过更新 order_id:' . $result['order_id']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,104 +265,15 @@ class Ccbpayment extends Common
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送订单到建行外联系统
|
||||
* ⚠️ 已废弃: 推送订单到建行外联系统
|
||||
*
|
||||
* ⚠️ 重要: 只在notify()支付成功后调用!
|
||||
* ✅ 幂等性: 支持重复调用,已推送的订单会跳过
|
||||
*
|
||||
* @param int $orderId 订单ID
|
||||
* @return void
|
||||
* @throws Exception 推送失败时抛出异常
|
||||
* @deprecated 2025-01-20 根据建行流程图,订单推送应在createPayment()时完成,此方法已废弃
|
||||
* @see createPayment() 步骤5: 推送未支付订单
|
||||
* @see notify() 步骤7: 更新订单为已支付
|
||||
*/
|
||||
private function pushOrderToCcb($orderId)
|
||||
{
|
||||
try {
|
||||
// ✅ 重新查询订单,确保状态已更新
|
||||
$order = OrderModel::find($orderId);
|
||||
if (!$order) {
|
||||
throw new Exception('订单不存在');
|
||||
}
|
||||
|
||||
// ✅ 验证订单状态
|
||||
if ($order->status !== 'paid') {
|
||||
throw new Exception('订单状态不正确(status=' . $order->status . '),无法推送');
|
||||
}
|
||||
|
||||
// ✅ 幂等性检查: 如果已推送成功,跳过
|
||||
if ($order->ccb_sync_status == 1) {
|
||||
Log::info('[建行推送] 订单已推送,跳过 order_id:' . $orderId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取订单商品列表
|
||||
$orderItems = Db::name('shopro_order_item')
|
||||
->where('order_id', $order->id)
|
||||
->field('goods_id, goods_sku_text, goods_title, goods_price, goods_num, discount_fee')
|
||||
->select();
|
||||
|
||||
$goodsList = [];
|
||||
foreach ($orderItems as $item) {
|
||||
$goodsList[] = [
|
||||
'goods_id' => $item['goods_id'],
|
||||
'goods_name' => $item['goods_title'],
|
||||
'goods_sku' => $item['goods_sku_text'],
|
||||
'goods_price' => $item['goods_price'],
|
||||
'goods_num' => $item['goods_num'],
|
||||
'discount_amount' => $item['discount_fee'] ?? 0
|
||||
];
|
||||
}
|
||||
|
||||
// 获取用户的建行用户ID
|
||||
$user = Db::name('user')->where('id', $order->user_id)->field('ccb_user_id')->find();
|
||||
|
||||
// 构造订单数据 (使用Shopro实际字段名)
|
||||
$orderData = [
|
||||
'id' => $order->id,
|
||||
'order_sn' => $order->order_sn,
|
||||
'ccb_user_id' => $user['ccb_user_id'] ?? '',
|
||||
'total_amount' => $order->total_amount, // 订单总金额
|
||||
'pay_amount' => $order->total_fee, // 实际支付金额
|
||||
'discount_amount' => $order->discount_fee, // 优惠金额
|
||||
'status' => $order->status, // Shopro使用status枚举
|
||||
'refund_status' => $order->aftersale_status ?? 0, // 售后状态
|
||||
'create_time' => $order->createtime, // Shopro使用秒级时间戳
|
||||
'paid_time' => $order->paid_time, // 支付时间
|
||||
'ccb_pay_flow_id' => $order->ccb_pay_flow_id,
|
||||
'goods_list' => $goodsList,
|
||||
];
|
||||
|
||||
// 推送到建行
|
||||
$result = $this->orderService->pushOrder($order->id);
|
||||
|
||||
if (!$result['status']) {
|
||||
// ✅ 推送失败: 更新状态为失败,记录错误原因
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 2, // 2=失败
|
||||
'ccb_sync_error' => $result['message'] ?? '未知错误',
|
||||
'ccb_sync_time' => time(),
|
||||
]);
|
||||
|
||||
throw new Exception($result['message'] ?? '推送失败');
|
||||
}
|
||||
|
||||
// ✅ 推送成功: 更新同步状态
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 1, // 1=成功
|
||||
'ccb_sync_time' => time(),
|
||||
'ccb_sync_error' => '', // 清空错误信息
|
||||
]);
|
||||
|
||||
Log::info('[建行推送] 订单推送成功 order_id:' . $order->id . ' order_sn:' . $order->order_sn);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// ✅ 记录失败原因,供后续补推
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 2, // 失败状态
|
||||
'ccb_sync_error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
throw $e; // 向上抛出异常
|
||||
}
|
||||
Log::warning('[建行支付] pushOrderToCcb()已废弃,请使用orderService->pushOrder()或updateOrderStatus()');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2,9 +2,10 @@
|
||||
|
||||
**项目**: Shopro商城建行支付集成
|
||||
**修复时间**: 2025-01-20
|
||||
**文档版本**: v1.0
|
||||
**修复类型**: 🔴 严重安全漏洞 + 架构偏离
|
||||
**文档版本**: v2.0 (根据官方流程图修正)
|
||||
**修复类型**: 🔴 严重安全漏洞 + 架构偏离 + 订单同步时机错误
|
||||
**建行接口版本**: v2.20 (2025-07-25)
|
||||
**参考文档**: 建行生活服务方接入流程图
|
||||
|
||||
---
|
||||
|
||||
@ -17,14 +18,15 @@
|
||||
1. **前端callback机制违反建行标准流程** 🔴 致命
|
||||
2. **前端可伪造支付成功请求** 🔴 安全漏洞
|
||||
3. **双通道更新订单状态导致竞态条件** 🔴 致命
|
||||
4. **订单推送时机错误** 🟡 严重
|
||||
5. **缺少轮询查询机制** 🟡 严重
|
||||
4. **订单推送时机错误** 🔴 致命 - 应该在创建订单时推送,而不是支付成功后
|
||||
5. **订单更新时机错误** 🔴 致命 - 支付成功后应调用更新接口,而不是推送接口
|
||||
6. **缺少轮询查询机制** 🟡 严重
|
||||
|
||||
---
|
||||
|
||||
## 🔴 建行标准支付流程 vs 错误实现
|
||||
|
||||
### 建行标准流程(官方文档)
|
||||
### 建行标准流程(官方文档 - 根据流程图修正)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
@ -32,25 +34,39 @@ sequenceDiagram
|
||||
participant Backend as 服务方后台
|
||||
participant CCBApp as 建行APP
|
||||
participant CCBBackend as 建行后端
|
||||
participant Merchant as 商户管理(外联)
|
||||
|
||||
Note over H5,Backend: 步骤1: 生成支付串
|
||||
H5->>Backend: POST /createPayment
|
||||
Note over H5,Backend: 步骤1: 请求下单
|
||||
H5->>Backend: POST /createPayment(生成支付串)
|
||||
Backend->>Backend: 保存订单(未支付状态)
|
||||
|
||||
Note over Backend,CCBBackend: 步骤2: 推送订单 ✅ 推送未支付订单!
|
||||
Backend->>Merchant: 调用订单推送接口(A3341TP01)
|
||||
Merchant-->>Backend: 返回推送结果
|
||||
Backend-->>H5: {payment_string}
|
||||
|
||||
Note over H5,CCBApp: 步骤2: 调起建行收银台
|
||||
Note over H5,CCBApp: 步骤3: 调起建行收银台
|
||||
H5->>CCBApp: JSBridge.ccbpay(支付串)
|
||||
activate CCBBackend
|
||||
CCBApp->>CCBBackend: 校验登录
|
||||
CCBApp->>CCBApp: 调用支付组件
|
||||
H5->>CCBApp: 确认支付、输入密码
|
||||
CCBApp->>CCBBackend: 发送支付请求
|
||||
Note right of CCBBackend: 用户在建行APP中完成支付
|
||||
|
||||
Note over CCBBackend,Backend: 步骤3: 建行异步通知 ✅ 唯一可信的支付确认!
|
||||
CCBBackend->>Backend: POST notify(ORDERID, SIGN等)
|
||||
Note over CCBBackend,Backend: 步骤10-12: 建行异步通知
|
||||
CCBBackend->>Merchant: 返回支付成功通知
|
||||
Merchant->>Backend: 推送服务器通知(notify)
|
||||
Backend->>Backend: 验证SIGN签名
|
||||
Backend->>Backend: 原子更新订单状态为paid
|
||||
Backend->>Backend: 推送订单到外联系统
|
||||
Backend-->>CCBBackend: 返回SUCCESS
|
||||
Backend->>Backend: 原子更新本地订单状态为paid
|
||||
deactivate CCBBackend
|
||||
|
||||
Note over H5,Backend: 步骤4: 前端轮询查询状态 ✅ 只查询,不更新!
|
||||
Note over Backend,Merchant: 步骤13: 更新订单状态 ✅ 更新为已支付!
|
||||
Backend->>Merchant: 调用订单更新接口(A3341TP02)
|
||||
Merchant-->>Backend: 返回更新结果
|
||||
Backend-->>Merchant: 返回SUCCESS
|
||||
|
||||
Note over H5,Backend: 步骤15-16: 前端轮询查询状态 (未收到通知时)
|
||||
loop 每2秒轮询(最多60秒)
|
||||
H5->>Backend: GET /queryPaymentStatus
|
||||
Backend-->>H5: {status: 'paid'或'unpaid'}
|
||||
@ -60,6 +76,11 @@ sequenceDiagram
|
||||
end
|
||||
```
|
||||
|
||||
**关键流程说明**:
|
||||
1. **步骤2**: 生成支付串后**立即推送未支付订单**到建行外联系统(A3341TP01)
|
||||
2. **步骤13**: 收到支付成功通知后**更新订单状态为已支付**(A3341TP02)
|
||||
3. **步骤15**: 前端轮询查询订单状态(用于未收到通知的降级方案)
|
||||
|
||||
### 修复前的错误实现
|
||||
|
||||
```mermaid
|
||||
@ -327,7 +348,76 @@ public function notify()
|
||||
|
||||
---
|
||||
|
||||
### 修复3: handleNotify()返回订单ID
|
||||
### 修复3: createPayment()推送未支付订单
|
||||
|
||||
**修复后** (`addons/shopro/controller/Ccbpayment.php:101-118`):
|
||||
|
||||
```php
|
||||
// 5. ✅ 推送订单到建行(步骤2:调用订单推送接口将已提交订单)
|
||||
// ⚠️ 注意:此时推送的是未支付状态的订单
|
||||
try {
|
||||
$pushResult = $this->orderService->pushOrder($orderId);
|
||||
|
||||
if ($pushResult['status']) {
|
||||
Log::info('[建行支付] 订单推送成功 order_id:' . $orderId);
|
||||
} else {
|
||||
// ⚠️ 推送失败不阻塞支付流程,只记录日志
|
||||
Log::warning('[建行支付] 订单推送失败(不阻塞支付) order_id:' . $orderId . ' error:' . $pushResult['message']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// ⚠️ 推送异常不阻塞支付流程
|
||||
Log::error('[建行支付] 订单推送异常(不阻塞支付) order_id:' . $orderId . ' error:' . $e->getMessage());
|
||||
}
|
||||
|
||||
// 6. 返回支付串
|
||||
$this->success('支付串生成成功', $result['data']);
|
||||
```
|
||||
|
||||
**修复要点**:
|
||||
- ✅ 生成支付串后立即调用`pushOrder()`推送未支付订单(A3341TP01)
|
||||
- ✅ 推送失败不阻塞支付流程,用户仍可继续支付
|
||||
- ✅ 记录推送结果日志,失败的可后续补推
|
||||
|
||||
---
|
||||
|
||||
### 修复4: notify()更新订单状态为已支付
|
||||
|
||||
**修复后** (`addons/shopro/controller/Ccbpayment.php:227-248`):
|
||||
|
||||
```php
|
||||
// 7. ✅ 处理成功后更新订单状态到建行(步骤13:调用订单更新接口更新订单状态)
|
||||
if ($result['status'] === 'success' && !empty($result['order_id'])) {
|
||||
// ⚠️ 只有新支付才更新,已支付的订单跳过更新
|
||||
if ($result['already_paid'] === false) {
|
||||
try {
|
||||
// 调用订单更新接口,将订单状态从未支付更新为已支付
|
||||
$updateResult = $this->orderService->updateOrderStatus($result['order_id']);
|
||||
|
||||
if ($updateResult['status']) {
|
||||
Log::info('[建行通知] 订单状态更新成功 order_id:' . $result['order_id']);
|
||||
} else {
|
||||
// ⚠️ 更新失败不影响本地支付状态,记录日志后续补推
|
||||
Log::warning('[建行通知] 订单状态更新失败(本地已支付) order_id:' . $result['order_id'] . ' error:' . $updateResult['message']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// ⚠️ 更新异常不影响支付成功,记录日志后续补推
|
||||
Log::error('[建行通知] 订单状态更新异常(本地已支付) order_id:' . $result['order_id'] . ' error:' . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
Log::info('[建行通知] 订单已支付且已更新,跳过更新 order_id:' . $result['order_id']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修复要点**:
|
||||
- ✅ 收到支付成功通知后调用`updateOrderStatus()`(A3341TP02)
|
||||
- ✅ 将订单状态从"未支付"更新为"已支付"
|
||||
- ✅ 更新失败不影响本地支付状态(本地订单已标记为paid)
|
||||
- ✅ 幂等性保护(已支付的订单跳过更新)
|
||||
|
||||
---
|
||||
|
||||
### 修复5: handleNotify()返回订单ID
|
||||
|
||||
**修复后** (`addons/shopro/library/ccblife/CcbPaymentService.php:349-403`):
|
||||
|
||||
@ -404,84 +494,21 @@ public function handleNotify($params)
|
||||
|
||||
---
|
||||
|
||||
### 修复4: pushOrderToCcb()增加幂等性检查
|
||||
### ~~修复6: pushOrderToCcb()增加幂等性检查~~
|
||||
|
||||
**修复后** (`addons/shopro/controller/Ccbpayment.php:270-359`):
|
||||
**⚠️ 已废弃**: 根据建行流程图,`pushOrderToCcb()`方法已废弃。
|
||||
|
||||
```php
|
||||
/**
|
||||
* 推送订单到建行外联系统
|
||||
*
|
||||
* ⚠️ 重要: 只在notify()支付成功后调用!
|
||||
* ✅ 幂等性: 支持重复调用,已推送的订单会跳过
|
||||
*
|
||||
* @param int $orderId 订单ID
|
||||
* @throws Exception 推送失败时抛出异常
|
||||
*/
|
||||
private function pushOrderToCcb($orderId)
|
||||
{
|
||||
try {
|
||||
// ✅ 重新查询订单,确保状态已更新
|
||||
$order = OrderModel::find($orderId);
|
||||
if (!$order) {
|
||||
throw new Exception('订单不存在');
|
||||
}
|
||||
|
||||
// ✅ 验证订单状态
|
||||
if ($order->status !== 'paid') {
|
||||
throw new Exception('订单状态不正确,无法推送');
|
||||
}
|
||||
|
||||
// ✅ 幂等性检查: 如果已推送成功,跳过
|
||||
if ($order->ccb_sync_status == 1) {
|
||||
Log::info('[建行推送] 订单已推送,跳过 order_id:' . $orderId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 推送到建行
|
||||
$result = $this->orderService->pushOrder($order->id);
|
||||
|
||||
if (!$result['status']) {
|
||||
// ✅ 推送失败: 更新状态为失败,记录错误原因
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 2, // 2=失败
|
||||
'ccb_sync_error' => $result['message'] ?? '未知错误',
|
||||
'ccb_sync_time' => time(),
|
||||
]);
|
||||
|
||||
throw new Exception($result['message'] ?? '推送失败');
|
||||
}
|
||||
|
||||
// ✅ 推送成功: 更新同步状态
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 1, // 1=成功
|
||||
'ccb_sync_time' => time(),
|
||||
'ccb_sync_error' => '',
|
||||
]);
|
||||
|
||||
Log::info('[建行推送] 订单推送成功 order_id:' . $orderId);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// ✅ 记录失败原因,供后续补推
|
||||
OrderModel::where('id', $orderId)->update([
|
||||
'ccb_sync_status' => 2,
|
||||
'ccb_sync_error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修复要点**:
|
||||
- ✅ 幂等性检查(ccb_sync_status == 1时跳过)
|
||||
- ✅ 状态验证(只推送已支付的订单)
|
||||
- ✅ 失败原因记录(ccb_sync_error字段)
|
||||
- ✅ 异常向上抛出(但不影响notify返回SUCCESS)
|
||||
**正确流程**:
|
||||
1. `createPayment()` → 调用`orderService->pushOrder()` → 推送未支付订单(A3341TP01)
|
||||
2. `notify()` → 调用`orderService->updateOrderStatus()` → 更新为已支付(A3341TP02)
|
||||
|
||||
---
|
||||
|
||||
### 修复5: 前端改为轮询查询
|
||||
**⚠️ 已废弃**: 根据建行流程图,订单推送和更新的幂等性由`CcbOrderService`内部保证。
|
||||
|
||||
---
|
||||
|
||||
### 修复6: 前端改为轮询查询
|
||||
|
||||
**修复后** (`frontend/sheep/platform/pay.js:325-386`):
|
||||
|
||||
@ -576,11 +603,13 @@ async ccbPay() {
|
||||
| **支付确认来源** | 前端callback + 建行notify (双通道) ❌ | 只依赖建行notify (单通道) ✅ |
|
||||
| **前端职责** | 调用callback通知后端支付成功 ❌ | 轮询查询订单状态 ✅ |
|
||||
| **安全性** | 可伪造前端请求触发支付成功 🔴 | 只信任建行签名验证 ✅ |
|
||||
| **订单推送时机** | callback()中推送 ❌ | notify()成功后推送 ✅ |
|
||||
| **订单推送时机** | 支付成功后推送 ❌ | **创建订单时推送未支付状态** ✅ |
|
||||
| **订单更新时机** | 未更新到建行 ❌ | **支付成功后更新为已支付** ✅ |
|
||||
| **竞态风险** | callback和notify可能同时执行 🔴 | 只有notify会更新订单 ✅ |
|
||||
| **幂等性** | 无幂等保护 ❌ | 支持重复调用,已推送的跳过 ✅ |
|
||||
| **符合建行规范** | 否 ❌ | 是 ✅ |
|
||||
| **幂等性** | 无幂等保护 ❌ | 支持重复调用,已推送/已更新的跳过 ✅ |
|
||||
| **符合建行规范** | 否 ❌ | **完全符合流程图** ✅ |
|
||||
| **订单状态一致性** | 可能重复更新或状态异常 🔴 | 原子更新,状态一致 ✅ |
|
||||
| **建行订单同步** | 不同步或错误时机同步 ❌ | **按流程图正确同步** ✅ |
|
||||
|
||||
---
|
||||
|
||||
@ -652,25 +681,24 @@ curl -X POST "http://your-domain/addons/shopro/ccbpayment/notify" \
|
||||
### 4. 日志验证
|
||||
|
||||
```bash
|
||||
# 查看创建支付串日志
|
||||
tail -f runtime/log/$(date +%Y%m)/*.log | grep '建行支付'
|
||||
|
||||
# ✅ 正常流程应该看到:
|
||||
# [建行支付] 订单推送成功 order_id:123 ← 步骤2: 推送未支付订单
|
||||
|
||||
# 查看notify日志
|
||||
tail -f runtime/log/$(date +%Y%m)/*.log | grep '建行通知'
|
||||
|
||||
# ✅ 正常流程应该看到:
|
||||
# [建行通知] 收到异步通知: ORDERID=...
|
||||
# [建行通知] 解析参数: {...}
|
||||
# [建行通知] 订单状态更新成功 order_id:123
|
||||
# [建行通知] 订单推送成功 order_id:123
|
||||
# [建行通知] 订单状态更新成功 order_id:123 ← 步骤13: 更新为已支付
|
||||
# [建行通知] 处理完成,返回: SUCCESS
|
||||
|
||||
# 查看推送日志
|
||||
tail -f runtime/log/$(date +%Y%m)/*.log | grep '建行推送'
|
||||
|
||||
# ✅ 正常流程应该看到:
|
||||
# [建行推送] 订单推送成功 order_id:123 order_sn:202501200001
|
||||
|
||||
# 查看幂等性日志(重复通知时)
|
||||
# [建行通知] 订单已支付,跳过处理 order_id:123
|
||||
# [建行推送] 订单已推送,跳过 order_id:123
|
||||
# [建行通知] 订单已支付且已更新,跳过更新 order_id:123
|
||||
```
|
||||
|
||||
---
|
||||
@ -790,6 +818,7 @@ php think clear
|
||||
| 版本 | 日期 | 修改内容 |
|
||||
|-----|------|---------|
|
||||
| v1.0 | 2025-01-20 | 初始版本,完成严重安全漏洞和架构偏离修复 |
|
||||
| v2.0 | 2025-01-20 | **重大修正**: 根据建行流程图修正订单同步时机 - 推送未支付订单在createPayment,更新已支付订单在notify |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user