From 4f34e6baa1b4984f4273f00dbad44883be13c61d Mon Sep 17 00:00:00 2001 From: yangrz Date: Sat, 30 Aug 2025 11:07:56 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Admin/Controllers/OrderController.php | 6 +- .../Controllers/OrderNotifyController.php | 42 ++--- app/Jobs/OrderChangedNotify.php | 147 ++++++++++++++++++ app/Models/Order.php | 4 + app/Models/OrderNotify.php | 5 + app/Services/OutService.php | 2 +- composer.json | 1 + .../2025_08_27_163509_create_orders_table.php | 2 + ..._27_170155_create_order_notifies_table.php | 2 - lang/zh_CN/order-notify.php | 2 - lang/zh_CN/order.php | 2 + 11 files changed, 190 insertions(+), 25 deletions(-) create mode 100644 app/Jobs/OrderChangedNotify.php diff --git a/app/Admin/Controllers/OrderController.php b/app/Admin/Controllers/OrderController.php index cff14e5..844477b 100644 --- a/app/Admin/Controllers/OrderController.php +++ b/app/Admin/Controllers/OrderController.php @@ -49,6 +49,8 @@ class OrderController extends AdminController ]); $grid->column('transfer_id'); $grid->column('channel_order_no'); + $grid->column('errCode'); + $grid->column('errMsg'); $grid->column('success_time'); $grid->column('created_at'); $grid->column('updated_at')->sortable(); @@ -59,7 +61,7 @@ class OrderController extends AdminController $grid->disableBatchDelete(); $grid->showColumnSelector(); - $grid->hideColumns(['if_code', 'currency', 'bank_name', 'bank_code', 'client_ip', 'transfer_desc', 'notify_url', 'ext_param', 'channel_extra', 'channel_order_no']); + $grid->hideColumns(['if_code', 'currency', 'bank_name', 'bank_code', 'client_ip', 'transfer_desc', 'notify_url', 'ext_param', 'channel_extra', 'channel_order_no', 'errCode', 'errMsg']); $grid->filter(function (Grid\Filter $filter) { $filter->equal('id')->width(3); @@ -114,6 +116,8 @@ class OrderController extends AdminController ]); $show->field('transfer_id'); $show->field('channel_order_no'); + $show->field('errCode'); + $show->field('errMsg'); $show->field('success_time'); $show->field('created_at'); $show->field('updated_at'); diff --git a/app/Admin/Controllers/OrderNotifyController.php b/app/Admin/Controllers/OrderNotifyController.php index 6c5b572..36a26ec 100644 --- a/app/Admin/Controllers/OrderNotifyController.php +++ b/app/Admin/Controllers/OrderNotifyController.php @@ -5,8 +5,9 @@ namespace App\Admin\Controllers; use App\Models\OrderNotify; use Dcat\Admin\Form; use Dcat\Admin\Grid; -use Dcat\Admin\Show; use Dcat\Admin\Http\Controllers\AdminController; +use Dcat\Admin\Show; +use Illuminate\Support\Str; class OrderNotifyController extends AdminController { @@ -31,11 +32,16 @@ class OrderNotifyController extends AdminController 3 => 'danger', 4 => 'gray', ]); - $grid->column('receive_time'); $grid->column('push_time'); - $grid->column('push_duration'); $grid->column('response_time'); $grid->column('response_code'); + $grid->column('response_body')->display(fn($v) => e(Str::limit($v, 15)))->width('15%'); + $grid->column('push_duration')->display(function ($v) { + if ($this->response_code === null) { + return ''; + } + return ($v / 1000).'秒'; + }); $grid->disableCreateButton(); $grid->disableEditButton(); @@ -52,24 +58,32 @@ class OrderNotifyController extends AdminController /** * Make a show builder. * - * @param mixed $id + * @param mixed $id * * @return Show */ protected function detail($id) { return Show::make($id, new OrderNotify(), function (Show $show) { + $show->disableEditButton(); + $show->disableDeleteButton(); $show->field('id'); $show->field('order_id'); $show->field('state')->using(admin_trans('order.options.state')); - $show->field('receive_time'); - $show->field('receive_body')->unescape()->as(fn ($v) => '
' . e($v) . '
'); $show->field('push_time'); - $show->field('push_body')->unescape()->as(fn ($v) => '
' . e($v) . '
'); - $show->field('push_duration'); + $show->field('push_body')->unescape()->as(function ($v) { + parse_str($v, $r); + return '推送数据:
'.e($v).'

PHP数组:
'.var_export($r, true).'
'; + }); $show->field('response_time'); $show->field('response_code'); - $show->field('response_body')->unescape()->as(fn ($v) => '
' . e($v) . '
'); + $show->field('response_body')->unescape()->as(fn($v) => '
'.e($v).'
'); + $show->field('push_duration')->as(function ($v) { + if ($this->response_code === null) { + return ''; + } + return ($v / 1000).'秒'; + }); }); } @@ -82,16 +96,6 @@ class OrderNotifyController extends AdminController { return Form::make(new OrderNotify(), function (Form $form) { $form->display('id'); - $form->text('order_id'); - $form->text('state'); - $form->text('receive_time'); - $form->text('receive_body'); - $form->text('push_time'); - $form->text('push_body'); - $form->text('push_duration'); - $form->text('response_time'); - $form->text('response_code'); - $form->text('response_body'); }); } } diff --git a/app/Jobs/OrderChangedNotify.php b/app/Jobs/OrderChangedNotify.php new file mode 100644 index 0000000..07bd2e2 --- /dev/null +++ b/app/Jobs/OrderChangedNotify.php @@ -0,0 +1,147 @@ +orderId = $orderId; + $this->state = $state; + } + + /** + * Execute the job. + */ + public function handle(OutService $outService): void + { + $order = Order::find($this->orderId); + + if (!$order) { + return; + } + + if (!$order->notify_url) { + return; + } + + $mchApp = MchApp::query() + ->where('mch_no', $order->mch_no) + ->where('app_id', $order->app_id) + ->first(); + + if (!$mchApp) { + return; + } + + $params = [ + 'mchNo' => $order->mch_no, + 'appId' => $order->app_id, + 'mchOrderNo' => $order->mch_order_no, + 'transferId' => $order->transfer_id, + 'amount' => (string) $order->amount, + 'currency' => $order->currency, + 'ifCode' => $order->if_code, + 'entryType' => $order->entry_type, + 'state' => (string) $this->state, + 'accountNo' => $order->account_no, + 'accountName' => $order->account_name, + 'bankName' => $order->bank_name, + 'transferDesc' => $order->transfer_desc, + 'channelOrderNo' => $order->channel_order_no, + 'errCode' => $order->errCode, + 'errMsg' => $order->errMsg, + 'extraParam' => $order->ext_param, + 'createdAt' => $order->created_at->format('Uv'), + ]; + + if ($this->state == 2) { + $params['success_time'] = $order->success_time->format('Uv'); + } + + $params['sign'] = $outService->makeSign($params, $mchApp->secret_key); + + $notify = new OrderNotify(); + $notify->order_id = $this->orderId; + $notify->state = $this->state; + $notify->push_time = now(); + $notify->push_body = http_build_query($params); + $notify->save(); + + try { + $options = [ + 'allow_redirects' => false, + 'timeout' => 10, + ]; + + $response = Http::withOptions($options) + ->withBody($notify->push_body, 'application/x-www-form-urlencoded') + ->post($order->notify_url); + + $notify->response_code = $response->status(); + $notify->response_body = Str::limit($response->body(), 2000); + } catch (Throwable) { + $notify->response_code = 0; + $notify->response_body = ''; + } + + $notify->response_time = now(); + $notify->push_duration = round($notify->push_time->diffInSeconds($notify->response_time) * 1000); + $notify->save(); + + if ($notify->response_body !== 'success') { + $this->customRelease(); + } + } + + private function customRelease(): void + { + // 下一次尝试的时间间隔 + $delayList = [ + 1 => 60 * 2, + 2 => 60 * 10, + 3 => 60 * 10, + 4 => 3600, + 5 => 3600 * 2, + 6 => 3600 * 6, + 7 => 3600 * 15, + ]; + + $currentAttempt = $this->attempts(); + + $this->release($delayList[$currentAttempt]); + } +} diff --git a/app/Models/Order.php b/app/Models/Order.php index e22f2f9..d8be0e7 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -8,4 +8,8 @@ use Illuminate\Database\Eloquent\Model; class Order extends Model { use HasDateTimeFormatter; + + protected $casts = [ + 'success_time' => 'datetime', + ]; } diff --git a/app/Models/OrderNotify.php b/app/Models/OrderNotify.php index acd3483..713f5f1 100644 --- a/app/Models/OrderNotify.php +++ b/app/Models/OrderNotify.php @@ -9,5 +9,10 @@ class OrderNotify extends Model { use HasDateTimeFormatter; + protected $casts = [ + 'push_time' => 'datetime', + 'response_time' => 'datetime', + ]; + public $timestamps = false; } diff --git a/app/Services/OutService.php b/app/Services/OutService.php index d48eb48..aafcb0d 100644 --- a/app/Services/OutService.php +++ b/app/Services/OutService.php @@ -14,7 +14,7 @@ class OutService * @param string $secretKey * @return string */ - private function makeSign(array $params, string $secretKey): string + public function makeSign(array $params, string $secretKey): string { ksort($params); diff --git a/composer.json b/composer.json index db6ff26..991304a 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.2", + "ext-bcmath": "*", "dcat/laravel-admin": "2.*", "laravel-lang/common": "^6.7", "laravel/framework": "^12.0", diff --git a/database/migrations/2025_08_27_163509_create_orders_table.php b/database/migrations/2025_08_27_163509_create_orders_table.php index a5de963..81fafc2 100644 --- a/database/migrations/2025_08_27_163509_create_orders_table.php +++ b/database/migrations/2025_08_27_163509_create_orders_table.php @@ -32,6 +32,8 @@ return new class extends Migration $table->tinyInteger('state')->default(0)->comment('转账状态'); $table->string('transfer_id')->nullable()->unique()->comment('转账订单号'); $table->string('channel_order_no')->nullable()->comment('渠道转账单号'); + $table->string('errCode')->nullable()->comment('渠道错误码'); + $table->string('errMsg')->nullable()->comment('渠道错误描述'); $table->timestamp('success_time')->nullable()->comment('成功时间'); $table->timestamps(); $table->unique(['mch_no', 'mch_order_no']); diff --git a/database/migrations/2025_08_27_170155_create_order_notifies_table.php b/database/migrations/2025_08_27_170155_create_order_notifies_table.php index e58ca98..36682f5 100644 --- a/database/migrations/2025_08_27_170155_create_order_notifies_table.php +++ b/database/migrations/2025_08_27_170155_create_order_notifies_table.php @@ -15,8 +15,6 @@ return new class extends Migration $table->id(); $table->unsignedBigInteger('order_id')->index()->comment('订单ID'); $table->tinyInteger('state')->comment('订单状态'); - $table->timestamp('receive_time')->nullable()->comment('接收通知的时间'); - $table->text('receive_body')->comment('接收通知的内容'); $table->timestamp('push_time')->nullable()->comment('推给客户的时间'); $table->text('push_body')->nullable()->comment('推给客户的内容'); $table->integer('push_duration')->nullable()->comment('推送用时'); diff --git a/lang/zh_CN/order-notify.php b/lang/zh_CN/order-notify.php index 9e38a54..94c1e34 100644 --- a/lang/zh_CN/order-notify.php +++ b/lang/zh_CN/order-notify.php @@ -7,8 +7,6 @@ return [ 'fields' => [ 'order_id' => '订单ID', 'state' => '订单状态', - 'receive_time' => '接收通知的时间', - 'receive_body' => '接收通知的内容', 'push_time' => '推给客户的时间', 'push_body' => '推给客户的内容', 'push_duration' => '推送用时', diff --git a/lang/zh_CN/order.php b/lang/zh_CN/order.php index 25cfc8f..ad379db 100644 --- a/lang/zh_CN/order.php +++ b/lang/zh_CN/order.php @@ -24,6 +24,8 @@ return [ 'state' => '转账状态', 'transfer_id' => '转账订单号', 'channel_order_no' => '渠道转账单号', + 'errCode' => '渠道错误码', + 'errMsg' => '渠道错误描述', 'success_time' => '成功时间', ], 'options' => [