103 lines
4.5 KiB
PHP
103 lines
4.5 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
use App\Jobs\Supplier\DeleteSupplierProjectJob;
|
|||
|
|
use App\Models\Project;
|
|||
|
|
use App\Models\SupplierProject;
|
|||
|
|
use App\Models\Tenant;
|
|||
|
|
use App\Services\Supplier\SupplierPortalClient;
|
|||
|
|
use Carbon\Carbon;
|
|||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|||
|
|
use Illuminate\Support\Facades\DB;
|
|||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|||
|
|
|
|||
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Task 2.4 — отложенное удаление донора, пока летит хвост слепка.
|
|||
|
|
*
|
|||
|
|
* Если у supplier_project нет других потребителей, но за активную/завтрашнюю дату
|
|||
|
|
* есть снимок маршрутизации с его источником — хвостовой лид ещё может прийти, и
|
|||
|
|
* LeadRouter ищет snapshot по источнику донора. Удалив донора, мы оборвём матч.
|
|||
|
|
* Поэтому удаление откладывается до следующего CleanupInactiveSupplierProjectsJob.
|
|||
|
|
*/
|
|||
|
|
function insertTailSnapshot(
|
|||
|
|
Tenant $tenant,
|
|||
|
|
string $signalType,
|
|||
|
|
?string $signalIdentifier,
|
|||
|
|
?array $smsSenders = null,
|
|||
|
|
?string $smsKeyword = null,
|
|||
|
|
?string $date = null,
|
|||
|
|
): void {
|
|||
|
|
DB::table('project_routing_snapshots')->insert([
|
|||
|
|
'snapshot_date' => $date ?? Carbon::tomorrow('Europe/Moscow')->toDateString(),
|
|||
|
|
'project_id' => random_int(900000, 999999),
|
|||
|
|
'tenant_id' => $tenant->id,
|
|||
|
|
'daily_limit' => 10,
|
|||
|
|
'delivery_days_mask' => 127,
|
|||
|
|
'regions' => '{}',
|
|||
|
|
'signal_type' => $signalType,
|
|||
|
|
'signal_identifier' => $signalIdentifier,
|
|||
|
|
'sms_senders' => $smsSenders === null ? null : json_encode($smsSenders),
|
|||
|
|
'sms_keyword' => $smsKeyword,
|
|||
|
|
'expected_volume' => 10,
|
|||
|
|
'delivered_count' => 0,
|
|||
|
|
'created_at' => now(),
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
it('не удаляет supplier_project, пока есть снимок с его источником за активную дату', function (): void {
|
|||
|
|
$tenant = Tenant::factory()->create();
|
|||
|
|
$sp = SupplierProject::query()->create([
|
|||
|
|
'platform' => 'B1', 'signal_type' => 'call', 'unique_key' => '79991110000',
|
|||
|
|
'supplier_external_id' => '555', 'current_limit' => 1,
|
|||
|
|
]);
|
|||
|
|
// Снимок-хвост по тому же источнику (call/79991110000), потребителей pivot — нет.
|
|||
|
|
insertTailSnapshot($tenant, 'call', '79991110000');
|
|||
|
|
|
|||
|
|
$mock = Mockery::mock(SupplierPortalClient::class);
|
|||
|
|
$mock->shouldNotReceive('deleteProject');
|
|||
|
|
app()->instance(SupplierPortalClient::class, $mock);
|
|||
|
|
|
|||
|
|
(new DeleteSupplierProjectJob([$sp->id]))->handle(app(SupplierPortalClient::class));
|
|||
|
|
|
|||
|
|
// Донор НЕ удалён — удаление отложено, пока летит хвост.
|
|||
|
|
expect(SupplierProject::find($sp->id))->not->toBeNull();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('откладывает удаление sms-донора, пока снимок несёт его sender в хвосте', function (): void {
|
|||
|
|
$tenant = Tenant::factory()->create();
|
|||
|
|
$sp = SupplierProject::query()->create([
|
|||
|
|
'platform' => 'B3', 'signal_type' => 'sms', 'unique_key' => 'Caranga',
|
|||
|
|
'supplier_external_id' => '777', 'current_limit' => 1,
|
|||
|
|
]);
|
|||
|
|
insertTailSnapshot($tenant, 'sms', null, smsSenders: ['Caranga']);
|
|||
|
|
|
|||
|
|
$mock = Mockery::mock(SupplierPortalClient::class);
|
|||
|
|
$mock->shouldNotReceive('deleteProject');
|
|||
|
|
app()->instance(SupplierPortalClient::class, $mock);
|
|||
|
|
|
|||
|
|
(new DeleteSupplierProjectJob([$sp->id]))->handle(app(SupplierPortalClient::class));
|
|||
|
|
|
|||
|
|
expect(SupplierProject::find($sp->id))->not->toBeNull();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('удаляет донора, когда хвоста слепка нет (регрессия базового удаления)', function (): void {
|
|||
|
|
$tenant = Tenant::factory()->create();
|
|||
|
|
$sp = SupplierProject::query()->create([
|
|||
|
|
'platform' => 'B1', 'signal_type' => 'call', 'unique_key' => '79992220000',
|
|||
|
|
'supplier_external_id' => '600', 'current_limit' => 1,
|
|||
|
|
]);
|
|||
|
|
// Снимок есть, но по ДРУГОМУ источнику — хвоста для этого донора нет.
|
|||
|
|
insertTailSnapshot($tenant, 'call', '70000000000');
|
|||
|
|
|
|||
|
|
$mock = Mockery::mock(SupplierPortalClient::class);
|
|||
|
|
$mock->shouldReceive('deleteProject')->once()->with(600);
|
|||
|
|
app()->instance(SupplierPortalClient::class, $mock);
|
|||
|
|
|
|||
|
|
(new DeleteSupplierProjectJob([$sp->id]))->handle(app(SupplierPortalClient::class));
|
|||
|
|
|
|||
|
|
expect(SupplierProject::find($sp->id))->toBeNull();
|
|||
|
|
});
|