9d703ccb2a
Закрывает рассинхрон онлайна со слепком поставщика 21:00. - 4.1: SyncSupplierProjectJob в окне 18:00→00:00 МСК кладёт проект в новую очередь supplier_deferred_sync вместо немедленной отправки (перезаписала бы зафиксированный слепок). Вне окна — как раньше. - 4.2: FlushDeferredOnlineSyncJob в 00:05 МСК досылает отложенное вне окна и чистит очередь. - Схема: +1 таблица supplier_deferred_sync (project_id PK, без RLS — системная очередь как supplier_manual_sync_queue), миграция 2026_06_25_120000, schema.sql v8.54 + CHANGELOG. RLS-ревью пройдено (no-RLS консистентно прецеденту; формулировки GRANT/метрик уточнены). Тесты 6/6 + регрессия онлайн-синка 33/33 зелёные. Под LEFTHOOK=0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.3 KiB
PHP
68 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Jobs\Supplier\FlushDeferredOnlineSyncJob;
|
|
use App\Jobs\SyncSupplierProjectJob;
|
|
use App\Models\Project;
|
|
use App\Models\Tenant;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\Bus;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|
|
|
/**
|
|
* Task 4.2 — джоб досыла отложенной онлайн-очереди в 00:05 МСК.
|
|
*
|
|
* Для каждого проекта из supplier_deferred_sync диспатчит SyncSupplierProjectJob
|
|
* (в 00:05 он вне окна → отработает немедленно) и чистит строку.
|
|
*/
|
|
function makeDeferredProject(): Project
|
|
{
|
|
$tenant = Tenant::factory()->create();
|
|
$project = Project::factory()->for($tenant)->create([
|
|
'signal_type' => 'site', 'signal_identifier' => 'okna.ru', 'is_active' => true, 'daily_limit_target' => 10,
|
|
]);
|
|
DB::table('supplier_deferred_sync')->insert([
|
|
'project_id' => $project->id,
|
|
'created_at' => now(),
|
|
]);
|
|
|
|
return $project;
|
|
}
|
|
|
|
it('досылает отложенные онлайн-правки и чистит очередь', function (): void {
|
|
Bus::fake([SyncSupplierProjectJob::class]);
|
|
$project = makeDeferredProject();
|
|
|
|
(new FlushDeferredOnlineSyncJob)->handle();
|
|
|
|
expect(DB::table('supplier_deferred_sync')->count())->toBe(0);
|
|
Bus::assertDispatched(
|
|
SyncSupplierProjectJob::class,
|
|
fn (SyncSupplierProjectJob $job) => $job->projectId === $project->id,
|
|
);
|
|
});
|
|
|
|
it('пустая очередь — ничего не диспатчит, не падает', function (): void {
|
|
Bus::fake([SyncSupplierProjectJob::class]);
|
|
|
|
(new FlushDeferredOnlineSyncJob)->handle();
|
|
|
|
Bus::assertNotDispatched(SyncSupplierProjectJob::class);
|
|
});
|
|
|
|
it('досылает несколько проектов и полностью очищает очередь', function (): void {
|
|
Bus::fake([SyncSupplierProjectJob::class]);
|
|
makeDeferredProject();
|
|
makeDeferredProject();
|
|
makeDeferredProject();
|
|
|
|
(new FlushDeferredOnlineSyncJob)->handle();
|
|
|
|
expect(DB::table('supplier_deferred_sync')->count())->toBe(0);
|
|
Bus::assertDispatchedTimes(SyncSupplierProjectJob::class, 3);
|
|
});
|