81 lines
3.3 KiB
PHP
81 lines
3.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use App\Jobs\Supplier\SyncSupplierProjectsJob;
|
||
|
|
use App\Models\Project;
|
||
|
|
use App\Models\SupplierProject;
|
||
|
|
use App\Models\Tenant;
|
||
|
|
use App\Services\Supplier\Channel\AjaxProjectChannel;
|
||
|
|
use Carbon\Carbon;
|
||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Http;
|
||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
||
|
|
|
||
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Эпик 5 Task 5.1 — по завершении вечерней заливки джоб пишет строку-сводку
|
||
|
|
* в supplier_sync_runs (для экрана SaaS-admin «Интеграция с поставщиком»).
|
||
|
|
*/
|
||
|
|
beforeEach(function (): void {
|
||
|
|
Carbon::setTestNow(Carbon::parse('2026-05-27 18:06:00', 'Europe/Moscow'));
|
||
|
|
DB::table('supplier_sync_runs')->delete();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(fn () => Carbon::setTestNow());
|
||
|
|
|
||
|
|
it('пишет run-сводку даже когда нет eligible-проектов (groups_total=0, status=ok)', function (): void {
|
||
|
|
(new SyncSupplierProjectsJob)->handle(app(AjaxProjectChannel::class));
|
||
|
|
|
||
|
|
$run = DB::table('supplier_sync_runs')->latest('id')->first();
|
||
|
|
expect($run)->not->toBeNull();
|
||
|
|
expect((int) $run->groups_total)->toBe(0);
|
||
|
|
expect((int) $run->synced_ok)->toBe(0);
|
||
|
|
expect($run->status)->toBe('ok');
|
||
|
|
expect($run->started_at)->not->toBeNull();
|
||
|
|
expect($run->finished_at)->not->toBeNull();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('считает синхронизированную группу в синку run-сводки (groups_total=1, synced_ok=1)', function (): void {
|
||
|
|
$tenant = Tenant::factory()->create();
|
||
|
|
$project = Project::factory()->create([
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'is_active' => true,
|
||
|
|
'signal_type' => 'site',
|
||
|
|
'signal_identifier' => 'okna-run.example.com',
|
||
|
|
'daily_limit_target' => 9,
|
||
|
|
'delivery_days_mask' => 127,
|
||
|
|
'regions' => [82, 83],
|
||
|
|
]);
|
||
|
|
insertSnapshotForTomorrow($project, regions: '{82,83}');
|
||
|
|
|
||
|
|
Http::fake([
|
||
|
|
'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(
|
||
|
|
['status' => 'OK', 'message' => '', 'result' => null, 'id' => '2001'],
|
||
|
|
200,
|
||
|
|
),
|
||
|
|
'crm.bp-gr.ru/admin/visit/rt-projects-load*' => Http::response(
|
||
|
|
['projects' => [
|
||
|
|
['id' => '2001', 'src' => 'rt', 'name' => 'okna-run.example.com', 'tag' => 'РФ', 'type' => 'hosts', 'content' => 'okna-run.example.com'],
|
||
|
|
['id' => '2002', 'src' => 'bl', 'name' => 'okna-run.example.com', 'tag' => 'РФ', 'type' => 'hosts', 'content' => 'okna-run.example.com'],
|
||
|
|
['id' => '2003', 'src' => 'mt', 'name' => 'okna-run.example.com', 'tag' => 'РФ', 'type' => 'hosts', 'content' => 'okna-run.example.com'],
|
||
|
|
]],
|
||
|
|
200,
|
||
|
|
),
|
||
|
|
]);
|
||
|
|
|
||
|
|
(new SyncSupplierProjectsJob)->handle(app(AjaxProjectChannel::class));
|
||
|
|
|
||
|
|
// Группа реально создалась у поставщика.
|
||
|
|
expect(SupplierProject::on('pgsql_supplier')->where('unique_key', 'okna-run.example.com')->count())->toBe(3);
|
||
|
|
|
||
|
|
$run = DB::table('supplier_sync_runs')->latest('id')->first();
|
||
|
|
expect($run)->not->toBeNull();
|
||
|
|
expect((int) $run->groups_total)->toBe(1);
|
||
|
|
expect((int) $run->synced_ok)->toBe(1);
|
||
|
|
expect((int) $run->failed)->toBe(0);
|
||
|
|
expect($run->status)->toBe('ok');
|
||
|
|
});
|