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(); });