Browse Source

订单推送

master
yangrz 5 months ago
parent
commit
4f34e6baa1
  1. 6
      app/Admin/Controllers/OrderController.php
  2. 42
      app/Admin/Controllers/OrderNotifyController.php
  3. 147
      app/Jobs/OrderChangedNotify.php
  4. 4
      app/Models/Order.php
  5. 5
      app/Models/OrderNotify.php
  6. 2
      app/Services/OutService.php
  7. 1
      composer.json
  8. 2
      database/migrations/2025_08_27_163509_create_orders_table.php
  9. 2
      database/migrations/2025_08_27_170155_create_order_notifies_table.php
  10. 2
      lang/zh_CN/order-notify.php
  11. 2
      lang/zh_CN/order.php

6
app/Admin/Controllers/OrderController.php

@ -49,6 +49,8 @@ class OrderController extends AdminController
]); ]);
$grid->column('transfer_id'); $grid->column('transfer_id');
$grid->column('channel_order_no'); $grid->column('channel_order_no');
$grid->column('errCode');
$grid->column('errMsg');
$grid->column('success_time'); $grid->column('success_time');
$grid->column('created_at'); $grid->column('created_at');
$grid->column('updated_at')->sortable(); $grid->column('updated_at')->sortable();
@ -59,7 +61,7 @@ class OrderController extends AdminController
$grid->disableBatchDelete(); $grid->disableBatchDelete();
$grid->showColumnSelector(); $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) { $grid->filter(function (Grid\Filter $filter) {
$filter->equal('id')->width(3); $filter->equal('id')->width(3);
@ -114,6 +116,8 @@ class OrderController extends AdminController
]); ]);
$show->field('transfer_id'); $show->field('transfer_id');
$show->field('channel_order_no'); $show->field('channel_order_no');
$show->field('errCode');
$show->field('errMsg');
$show->field('success_time'); $show->field('success_time');
$show->field('created_at'); $show->field('created_at');
$show->field('updated_at'); $show->field('updated_at');

42
app/Admin/Controllers/OrderNotifyController.php

@ -5,8 +5,9 @@ namespace App\Admin\Controllers;
use App\Models\OrderNotify; use App\Models\OrderNotify;
use Dcat\Admin\Form; use Dcat\Admin\Form;
use Dcat\Admin\Grid; use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController; use Dcat\Admin\Http\Controllers\AdminController;
use Dcat\Admin\Show;
use Illuminate\Support\Str;
class OrderNotifyController extends AdminController class OrderNotifyController extends AdminController
{ {
@ -31,11 +32,16 @@ class OrderNotifyController extends AdminController
3 => 'danger', 3 => 'danger',
4 => 'gray', 4 => 'gray',
]); ]);
$grid->column('receive_time');
$grid->column('push_time'); $grid->column('push_time');
$grid->column('push_duration');
$grid->column('response_time'); $grid->column('response_time');
$grid->column('response_code'); $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->disableCreateButton();
$grid->disableEditButton(); $grid->disableEditButton();
@ -52,24 +58,32 @@ class OrderNotifyController extends AdminController
/** /**
* Make a show builder. * Make a show builder.
* *
* @param mixed $id
* @param mixed $id
* *
* @return Show * @return Show
*/ */
protected function detail($id) protected function detail($id)
{ {
return Show::make($id, new OrderNotify(), function (Show $show) { return Show::make($id, new OrderNotify(), function (Show $show) {
$show->disableEditButton();
$show->disableDeleteButton();
$show->field('id'); $show->field('id');
$show->field('order_id'); $show->field('order_id');
$show->field('state')->using(admin_trans('order.options.state')); $show->field('state')->using(admin_trans('order.options.state'));
$show->field('receive_time');
$show->field('receive_body')->unescape()->as(fn ($v) => '<pre>' . e($v) . '</pre>');
$show->field('push_time'); $show->field('push_time');
$show->field('push_body')->unescape()->as(fn ($v) => '<pre>' . e($v) . '</pre>');
$show->field('push_duration');
$show->field('push_body')->unescape()->as(function ($v) {
parse_str($v, $r);
return '推送数据:<pre>'.e($v).'</pre><br/>PHP数组:<pre>'.var_export($r, true).'</pre>';
});
$show->field('response_time'); $show->field('response_time');
$show->field('response_code'); $show->field('response_code');
$show->field('response_body')->unescape()->as(fn ($v) => '<pre>' . e($v) . '</pre>');
$show->field('response_body')->unescape()->as(fn($v) => '<pre>'.e($v).'</pre>');
$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) { return Form::make(new OrderNotify(), function (Form $form) {
$form->display('id'); $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');
}); });
} }
} }

147
app/Jobs/OrderChangedNotify.php

@ -0,0 +1,147 @@
<?php
namespace App\Jobs;
use App\Models\MchApp;
use App\Models\Order;
use App\Models\OrderNotify;
use App\Services\OutService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Throwable;
class OrderChangedNotify implements ShouldQueue
{
use Queueable;
/**
* 可以尝试任务的次数
* @var int
*/
public int $tries = 8;
/**
* 订单ID
* @var int
*/
private int $orderId;
/**
* 推送状态
* @var int
*/
private int $state;
/**
* Create a new job instance.
*/
public function __construct(int $orderId, int $state)
{
$this->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]);
}
}

4
app/Models/Order.php

@ -8,4 +8,8 @@ use Illuminate\Database\Eloquent\Model;
class Order extends Model class Order extends Model
{ {
use HasDateTimeFormatter; use HasDateTimeFormatter;
protected $casts = [
'success_time' => 'datetime',
];
} }

5
app/Models/OrderNotify.php

@ -9,5 +9,10 @@ class OrderNotify extends Model
{ {
use HasDateTimeFormatter; use HasDateTimeFormatter;
protected $casts = [
'push_time' => 'datetime',
'response_time' => 'datetime',
];
public $timestamps = false; public $timestamps = false;
} }

2
app/Services/OutService.php

@ -14,7 +14,7 @@ class OutService
* @param string $secretKey * @param string $secretKey
* @return string * @return string
*/ */
private function makeSign(array $params, string $secretKey): string
public function makeSign(array $params, string $secretKey): string
{ {
ksort($params); ksort($params);

1
composer.json

@ -10,6 +10,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.2", "php": "^8.2",
"ext-bcmath": "*",
"dcat/laravel-admin": "2.*", "dcat/laravel-admin": "2.*",
"laravel-lang/common": "^6.7", "laravel-lang/common": "^6.7",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",

2
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->tinyInteger('state')->default(0)->comment('转账状态');
$table->string('transfer_id')->nullable()->unique()->comment('转账订单号'); $table->string('transfer_id')->nullable()->unique()->comment('转账订单号');
$table->string('channel_order_no')->nullable()->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->timestamp('success_time')->nullable()->comment('成功时间');
$table->timestamps(); $table->timestamps();
$table->unique(['mch_no', 'mch_order_no']); $table->unique(['mch_no', 'mch_order_no']);

2
database/migrations/2025_08_27_170155_create_order_notifies_table.php

@ -15,8 +15,6 @@ return new class extends Migration
$table->id(); $table->id();
$table->unsignedBigInteger('order_id')->index()->comment('订单ID'); $table->unsignedBigInteger('order_id')->index()->comment('订单ID');
$table->tinyInteger('state')->comment('订单状态'); $table->tinyInteger('state')->comment('订单状态');
$table->timestamp('receive_time')->nullable()->comment('接收通知的时间');
$table->text('receive_body')->comment('接收通知的内容');
$table->timestamp('push_time')->nullable()->comment('推给客户的时间'); $table->timestamp('push_time')->nullable()->comment('推给客户的时间');
$table->text('push_body')->nullable()->comment('推给客户的内容'); $table->text('push_body')->nullable()->comment('推给客户的内容');
$table->integer('push_duration')->nullable()->comment('推送用时'); $table->integer('push_duration')->nullable()->comment('推送用时');

2
lang/zh_CN/order-notify.php

@ -7,8 +7,6 @@ return [
'fields' => [ 'fields' => [
'order_id' => '订单ID', 'order_id' => '订单ID',
'state' => '订单状态', 'state' => '订单状态',
'receive_time' => '接收通知的时间',
'receive_body' => '接收通知的内容',
'push_time' => '推给客户的时间', 'push_time' => '推给客户的时间',
'push_body' => '推给客户的内容', 'push_body' => '推给客户的内容',
'push_duration' => '推送用时', 'push_duration' => '推送用时',

2
lang/zh_CN/order.php

@ -24,6 +24,8 @@ return [
'state' => '转账状态', 'state' => '转账状态',
'transfer_id' => '转账订单号', 'transfer_id' => '转账订单号',
'channel_order_no' => '渠道转账单号', 'channel_order_no' => '渠道转账单号',
'errCode' => '渠道错误码',
'errMsg' => '渠道错误描述',
'success_time' => '成功时间', 'success_time' => '成功时间',
], ],
'options' => [ 'options' => [

Loading…
Cancel
Save