文件
Henglianshutong/addons/shopro/job/OrderPaid.php

164 行
6.5 KiB
PHP
可执行文件

<?php
namespace addons\shopro\job;
use think\queue\Job;
use think\Db;
use think\exception\HttpResponseException;
use app\admin\model\shopro\order\Order;
use addons\shopro\service\StockSale;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\order\Invoice as OrderInvoice;
use addons\shopro\service\order\OrderOper;
use addons\shopro\facade\Activity as ActivityFacade;
/**
* 订单自动操作
*/
class OrderPaid extends BaseJob
{
/**
* 订单支付完成
*/
public function paid(Job $job, $data)
{
$orderData = $data['order'] ?? null;
$userData = $data['user'] ?? null;
$orderId = is_array($orderData) ? ($orderData['id'] ?? 0) : ($orderData->id ?? 0);
$userId = is_array($userData) ? ($userData['id'] ?? 0) : ($userData->id ?? 0);
try {
if ($orderId) {
Db::transaction(function () use ($orderId, $userId) {
$order = Order::with('items')->where('id', $orderId)->lock(true)->find();
if (!$order) {
return;
}
$user = User::get($userId ?: $order->user_id);
$ext = is_array($order->ext) ? $order->ext : (json_decode($order->ext ?? '', true) ?: []);
// 幂等防重:检查是否已经执行过减库存与活动支付处理
if (empty($ext['paid_forward_processed'])) {
// 订单减库存
$stockSale = new StockSale();
$stockSale->forwardStockSale($order);
// 处理发票审核改为等待开具
if ($order->invoice_status == 1) {
$invoice = OrderInvoice::where('order_id', $order->id)->find();
if ($invoice) {
$invoice->status = 'waiting';
$invoice->save();
}
}
// 处理活动,加入拼团,完成拼团,添加赠品记录等
ActivityFacade::buyOk($order, $user);
// 将订单参与活动信息改为已支付
$orderOper = new OrderOper();
$orderOper->activityOrderPaid($order);
$ext['paid_forward_processed'] = time();
$order->ext = $ext;
$order->save();
}
// 触发订单支付完成事件(下游结算服务内置原生幂等)
$eventData = ['order' => $order, 'user' => $user];
\think\Hook::listen('order_paid_after', $eventData);
});
}
// 删除 job
$job->delete();
} catch (HttpResponseException $e) {
$data = $e->getResponse()->getData();
$message = $data ? ($data['msg'] ?? '') : $e->getMessage();
format_log_error($e, 'OrderPaid.paid.HttpResponseException', $message);
$this->handleFailure($job, $orderId, 'paid', $message);
} catch (\Throwable $e) {
$message = $e->getMessage();
format_log_error($e, 'OrderPaid.paid', $message);
$this->handleFailure($job, $orderId, 'paid', $message);
}
}
/**
* 订单选择线下支付(货到付款)完成
*/
public function offline(Job $job, $data)
{
$orderData = $data['order'] ?? null;
$userData = $data['user'] ?? null;
$orderId = is_array($orderData) ? ($orderData['id'] ?? 0) : ($orderData->id ?? 0);
$userId = is_array($userData) ? ($userData['id'] ?? 0) : ($userData->id ?? 0);
try {
if ($orderId) {
Db::transaction(function () use ($orderId, $userId) {
$order = Order::with('items')->where('id', $orderId)->lock(true)->find();
if (!$order) {
return;
}
$user = User::get($userId ?: $order->user_id);
$ext = is_array($order->ext) ? $order->ext : (json_decode($order->ext ?? '', true) ?: []);
if (empty($ext['offline_forward_processed'])) {
// 订单减库存
$stockSale = new StockSale();
$stockSale->forwardStockSale($order);
// 处理活动,加入拼团,完成拼团,添加赠品记录等
ActivityFacade::buyOk($order, $user);
$ext['offline_forward_processed'] = time();
$order->ext = $ext;
$order->save();
}
// 触发订单选择线下支付(货到付款)完成事件
$eventData = ['order' => $order, 'user' => $user];
\think\Hook::listen('order_offline_after', $eventData);
});
}
// 删除 job
$job->delete();
} catch (HttpResponseException $e) {
$data = $e->getResponse()->getData();
$message = $data ? ($data['msg'] ?? '') : $e->getMessage();
format_log_error($e, 'OrderPaid.offline.HttpResponseException', $message);
$this->handleFailure($job, $orderId, 'offline', $message);
} catch (\Throwable $e) {
$message = $e->getMessage();
format_log_error($e, 'OrderPaid.offline', $message);
$this->handleFailure($job, $orderId, 'offline', $message);
}
}
/**
* 生产级失败与阶梯重试处理
*/
protected function handleFailure(Job $job, $orderId, $action, $errorMessage)
{
$attempts = $job->attempts();
$maxAttempts = 5;
if ($attempts >= $maxAttempts) {
\think\Log::record("[OrderPaid CRITICAL] 订单 ID:{$orderId} ({$action}) 处理连续失败 {$attempts} 次已达上限: {$errorMessage}", 'error');
$this->failed([
'job' => "OrderPaid@{$action}",
'order_id' => $orderId,
'error' => $errorMessage,
'attempts' => $attempts,
'failed_time' => time(),
]);
$job->delete();
} else {
$delay = min(60, $attempts * 5);
$job->release($delay);
}
}
}