115 lines
4.4 KiB
PHP
115 lines
4.4 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
use App\Jobs\Supplier\SyncSupplierProjectsJob;
|
|||
|
|
use App\Models\Project;
|
|||
|
|
use App\Models\Tenant;
|
|||
|
|
use Carbon\Carbon;
|
|||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|||
|
|
use Illuminate\Support\Facades\DB;
|
|||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|||
|
|
|
|||
|
|
uses(DatabaseTransactions::class);
|
|||
|
|
uses(SharesSupplierPdo::class);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Task 2.6 — офлайн-батч обязан заказывать у поставщика по источнику ИЗ СЛЕПКА,
|
|||
|
|
* а не по live projects.* . Закрывает рассинхрон окна 18:02 (snapshot) → 18:05 (sync):
|
|||
|
|
* клиент мог сменить источник между двумя cron'ами, но завтрашний заказ уже зафиксирован
|
|||
|
|
* слепком (slepok-инвариант) — иначе поставщик заберёт лиды по НОВОМУ источнику,
|
|||
|
|
* а раздача доводит хвост по СТАРОМУ → рассинхрон денег.
|
|||
|
|
*/
|
|||
|
|
function insertTomorrowSmsSnapshot(
|
|||
|
|
Project $project,
|
|||
|
|
array $smsSenders,
|
|||
|
|
?string $smsKeyword = null,
|
|||
|
|
): void {
|
|||
|
|
$tomorrow = Carbon::tomorrow('Europe/Moscow')->toDateString();
|
|||
|
|
DB::table('project_routing_snapshots')->insert([
|
|||
|
|
'snapshot_date' => $tomorrow,
|
|||
|
|
'project_id' => $project->id,
|
|||
|
|
'tenant_id' => $project->tenant_id,
|
|||
|
|
'daily_limit' => 10,
|
|||
|
|
'delivery_days_mask' => 127,
|
|||
|
|
'regions' => '{}',
|
|||
|
|
'signal_type' => 'sms',
|
|||
|
|
'signal_identifier' => null,
|
|||
|
|
'sms_senders' => json_encode($smsSenders),
|
|||
|
|
'sms_keyword' => $smsKeyword,
|
|||
|
|
'expected_volume' => 10,
|
|||
|
|
'delivered_count' => 0,
|
|||
|
|
'created_at' => now(),
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
it('батч заказывает по источнику из слепка, даже если live-источник сменили после слепка', function (): void {
|
|||
|
|
Carbon::setTestNow(Carbon::parse('2026-05-27 18:04:00', 'Europe/Moscow'));
|
|||
|
|
|
|||
|
|
$tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
|
|||
|
|
$project = Project::factory()->for($tenant)->create([
|
|||
|
|
'is_active' => true,
|
|||
|
|
'signal_type' => 'sms',
|
|||
|
|
'signal_identifier' => null,
|
|||
|
|
'sms_senders' => ['Caranga'],
|
|||
|
|
'sms_keyword' => null,
|
|||
|
|
]);
|
|||
|
|
// Снимок снят с источника Caranga.
|
|||
|
|
insertTomorrowSmsSnapshot($project, smsSenders: ['Caranga']);
|
|||
|
|
|
|||
|
|
// ↓ Клиент сменил live-источник в окне 18:02→18:05 (после слепка).
|
|||
|
|
DB::table('projects')->where('id', $project->id)->update([
|
|||
|
|
'sms_senders' => json_encode(['NewSender']),
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$projects = (new SyncSupplierProjectsJob)->collectEligibleProjects();
|
|||
|
|
|
|||
|
|
$ours = $projects->where('id', $project->id);
|
|||
|
|
expect($ours)->toHaveCount(1);
|
|||
|
|
// Источник ИЗ СЛЕПКА (Caranga), не live (NewSender).
|
|||
|
|
expect((array) $ours->first()->sms_senders)->toBe(['Caranga']);
|
|||
|
|
|
|||
|
|
Carbon::setTestNow();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('батч переопределяет signal_identifier (site) значением слепка', function (): void {
|
|||
|
|
Carbon::setTestNow(Carbon::parse('2026-05-27 18:04:00', 'Europe/Moscow'));
|
|||
|
|
|
|||
|
|
$tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
|
|||
|
|
$project = Project::factory()->for($tenant)->create([
|
|||
|
|
'is_active' => true,
|
|||
|
|
'signal_type' => 'site',
|
|||
|
|
'signal_identifier' => 'old-site.ru',
|
|||
|
|
'sms_senders' => null,
|
|||
|
|
'sms_keyword' => null,
|
|||
|
|
]);
|
|||
|
|
$tomorrow = Carbon::tomorrow('Europe/Moscow')->toDateString();
|
|||
|
|
DB::table('project_routing_snapshots')->insert([
|
|||
|
|
'snapshot_date' => $tomorrow,
|
|||
|
|
'project_id' => $project->id,
|
|||
|
|
'tenant_id' => $project->tenant_id,
|
|||
|
|
'daily_limit' => 10,
|
|||
|
|
'delivery_days_mask' => 127,
|
|||
|
|
'regions' => '{}',
|
|||
|
|
'signal_type' => 'site',
|
|||
|
|
'signal_identifier' => 'old-site.ru',
|
|||
|
|
'sms_senders' => null,
|
|||
|
|
'sms_keyword' => null,
|
|||
|
|
'expected_volume' => 10,
|
|||
|
|
'delivered_count' => 0,
|
|||
|
|
'created_at' => now(),
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
DB::table('projects')->where('id', $project->id)->update([
|
|||
|
|
'signal_identifier' => 'new-site.ru',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$projects = (new SyncSupplierProjectsJob)->collectEligibleProjects();
|
|||
|
|
|
|||
|
|
$ours = $projects->where('id', $project->id);
|
|||
|
|
expect($ours)->toHaveCount(1);
|
|||
|
|
expect($ours->first()->signal_identifier)->toBe('old-site.ru');
|
|||
|
|
|
|||
|
|
Carbon::setTestNow();
|
|||
|
|
});
|