164 行
6.5 KiB
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);
|
|
}
|
|
}
|
|
} |