2025-10-17 16:32:16 +08:00

306 lines
9.1 KiB
PHP

<?php
namespace addons\shopro\controller;
use addons\shopro\controller\Common;
use addons\shopro\library\ccblife\CcbPaymentService;
use addons\shopro\library\ccblife\CcbOrderService;
use app\admin\model\shopro\order\Order as OrderModel;
use think\Db;
use think\Exception;
use think\Log;
/**
* 建行支付控制器
*
* 功能:
* - 生成支付串
* - 处理支付回调
* - 验证支付结果
*
* @author Billy
* @date 2025-01-16
*/
class Ccbpayment extends Common
{
/**
* 不需要登录的方法 (支付回调不需要登录)
* @var array
*/
protected $noNeedLogin = ['callback', 'notify'];
/**
* 不需要权限的方法
* @var array
*/
protected $noNeedRight = ['*'];
/**
* 支付服务
* @var CcbPaymentService
*/
private $paymentService;
/**
* 订单服务
* @var CcbOrderService
*/
private $orderService;
/**
* 初始化
*/
public function _initialize()
{
parent::_initialize();
$this->paymentService = new CcbPaymentService();
$this->orderService = new CcbOrderService();
}
/**
* 生成支付串
*
* @return void
*/
public function createPayment()
{
try {
// 1. 获取订单ID
$orderId = $this->request->post('order_id', 0);
if (empty($orderId)) {
$this->error('订单ID不能为空');
}
// 2. 查询订单
$order = OrderModel::where('id', $orderId)
->where('user_id', $this->auth->id)
->find();
if (!$order) {
$this->error('订单不存在');
}
// 3. 检查订单状态
if ($order['status'] != 'unpaid') {
$this->error('订单已支付或已关闭');
}
// 4. 生成支付串
$result = $this->paymentService->generatePaymentString($order->toArray());
if (!$result['success']) {
$this->error('支付串生成失败: ' . $result['error']);
}
// 5. 保存支付流水号到订单
$order->ccb_pay_flow_id = $result['pay_flow_id'];
$order->save();
// 6. 记录支付日志
$this->savePaymentLog($order, $result['payment_string'], $result['pay_flow_id']);
// 7. 返回支付串
$this->success('支付串生成成功', [
'payment_string' => $result['payment_string'],
'order_id' => $order->id,
'order_sn' => $order->order_sn,
'pay_flow_id' => $result['pay_flow_id'],
'amount' => $order->pay_amount,
]);
} catch (Exception $e) {
Log::error('[建行支付] 生成支付串失败 order_id:' . ($orderId ?? 0) . ' error:' . $e->getMessage());
$this->error('生成支付串失败: ' . $e->getMessage());
}
}
/**
* 支付回调 (前端调用)
*
* 说明:
* 前端调起支付后,建行App会跳转回H5页面
* H5页面需要调用此接口通知后端支付成功
*
* @return void
*/
public function callback()
{
try {
// 1. 获取参数
$orderId = $this->request->post('order_id', 0);
$transId = $this->request->post('trans_id', '');
$payTime = $this->request->post('pay_time', '');
if (empty($orderId)) {
$this->error('订单ID不能为空');
}
// 2. 查询订单
$order = OrderModel::where('id', $orderId)->find();
if (!$order) {
$this->error('订单不存在');
}
// 3. 检查订单状态
if ($order['status'] == 'paid' || $order['status'] == 'completed') {
$this->success('订单已支付', [
'order_id' => $order->id,
'order_sn' => $order->order_sn,
'status' => $order['status'],
]);
return;
}
// 4. 验证支付结果 (调用建行查询接口)
$verifyResult = $this->paymentService->verifyPayment($order->order_sn);
if (!$verifyResult) {
$this->error('支付验证失败,请稍后再试');
}
// 5. 更新订单状态
Db::startTrans();
try {
$order->status = 'paid';
$order->paid_time = time() * 1000; // Shopro使用毫秒时间戳
$order->save();
// 6. 推送订单状态到建行
$this->pushOrderToCcb($order);
// 7. 更新支付日志
$this->updatePaymentLog($order->ccb_pay_flow_id, [
'status' => 1,
'pay_time' => time(),
'trans_id' => $transId,
]);
Db::commit();
Log::info('[建行支付] 支付成功 order_id:' . $order->id . ' order_sn:' . $order->order_sn . ' trans_id:' . $transId);
$this->success('支付成功', [
'order_id' => $order->id,
'order_sn' => $order->order_sn,
'status' => 'paid',
]);
} catch (Exception $e) {
Db::rollback();
throw $e;
}
} catch (Exception $e) {
Log::error('[建行支付] 支付回调失败 order_id:' . ($orderId ?? 0) . ' error:' . $e->getMessage());
$this->error('支付处理失败: ' . $e->getMessage());
}
}
/**
* 建行支付通知 (建行服务器回调)
*
* 说明:
* 建行支付成功后,会向notify_url发送支付通知
* 这是服务器到服务器的回调,需要验签
*
* @return void
*/
public function notify()
{
try {
// TODO: 实现建行支付通知处理逻辑
// 1. 接收建行推送的支付结果
// 2. 验签
// 3. 更新订单状态
// 4. 返回success给建行
$this->success('SUCCESS');
} catch (Exception $e) {
Log::error('[建行通知] 处理失败 error:' . $e->getMessage());
$this->error('FAIL');
}
}
/**
* 推送订单到建行
*
* @param object $order 订单对象
* @return void
*/
private function pushOrderToCcb($order)
{
// 构造订单数据 (使用Shopro实际字段名)
$orderData = [
'id' => $order->id,
'order_sn' => $order->order_sn,
'ccb_user_id' => $order->ccb_user_id,
'total_amount' => $order->order_amount, // Shopro字段名
'pay_amount' => $order->pay_fee, // Shopro字段名
'discount_amount' => $order->total_discount_fee, // Shopro字段名
'status' => $order->status, // Shopro使用status枚举
'refund_status' => 0,
'create_time' => intval($order->createtime / 1000), // Shopro使用毫秒,转秒
'ccb_pay_flow_id' => $order->ccb_pay_flow_id,
'goods_list' => [], // TODO: 从订单详情中获取商品列表
];
// 推送到建行
$result = $this->orderService->pushOrder($orderData);
if (!$result['success']) {
Log::warning('[建行推送] 订单推送失败 order_id:' . $order->id . ' error:' . ($result['error'] ?? ''));
} else {
// 更新同步状态
$order->ccb_sync_status = 1;
$order->ccb_sync_time = time();
$order->save();
Log::info('[建行推送] 订单推送成功 order_id:' . $order->id . ' order_sn:' . $order->order_sn);
}
}
/**
* 保存支付日志
*
* @param object $order 订单对象
* @param string $paymentString 支付串
* @param string $payFlowId 支付流水号
* @return void
*/
private function savePaymentLog($order, $paymentString, $payFlowId)
{
Db::name('ccb_payment_log')->insert([
'order_id' => $order->id,
'order_sn' => $order->order_sn,
'pay_flow_id' => $payFlowId,
'payment_string' => $paymentString,
'user_id' => $order->user_id,
'ccb_user_id' => $order->ccb_user_id,
'amount' => $order->pay_amount,
'status' => 0, // 待支付
'create_time' => time(),
]);
}
/**
* 更新支付日志
*
* @param string $payFlowId 支付流水号
* @param array $data 更新数据
* @return void
*/
private function updatePaymentLog($payFlowId, $data)
{
Db::name('ccb_payment_log')
->where('pay_flow_id', $payFlowId)
->update($data);
}
}