create(); User::factory()->for($tenant)->create(['is_active' => true]); $project = Project::factory()->for($tenant)->create([ 'is_active' => true, 'signal_type' => 'sms', 'signal_identifier' => null, 'sms_senders' => ['Caranga'], 'sms_keyword' => null, ]); $sp = SupplierProject::factory()->create(['platform' => 'B3', 'signal_type' => 'sms', 'unique_key' => 'Caranga']); linkProjectToSupplier($project, $sp); return $project; } beforeEach(function (): void { // Новый матч ВКЛ — смена источника по защищённому проекту проходит (иначе 422-гард). DB::table('system_settings')->updateOrInsert( ['key' => 'routing_match_by_snapshot'], ['value' => 'true', 'type' => 'bool', 'updated_at' => now()], ); }); it('шлёт клиенту in-app уведомление о правиле при смене источника', function (): void { $project = makeSupplierLinkedActiveProject(); app(ProjectService::class)->update($project, ['sms_senders' => ['NewSender']]); expect( InAppNotification::where('tenant_id', $project->tenant_id) ->where('body', 'like', '%по старому источнику%') ->exists() )->toBeTrue(); }); it('шлёт уведомление «вступит в силу» при правке лимита (slepok-поле) без смены источника', function (): void { $project = makeSupplierLinkedActiveProject(); app(ProjectService::class)->update($project, ['daily_limit_target' => 20]); expect( InAppNotification::where('tenant_id', $project->tenant_id) ->where('body', 'like', '%вступят в силу%') ->exists() )->toBeTrue(); }); it('НЕ шлёт уведомление о хвосте если проект без поставщика (нет защиты)', function (): void { $tenant = Tenant::factory()->create(); User::factory()->for($tenant)->create(['is_active' => true]); $project = Project::factory()->for($tenant)->create([ 'is_active' => true, 'signal_type' => 'sms', 'sms_senders' => ['Caranga'], ]); app(ProjectService::class)->update($project, ['sms_senders' => ['NewSender']]); expect( InAppNotification::where('tenant_id', $project->tenant_id) ->where('body', 'like', '%по старому источнику%') ->exists() )->toBeFalse(); });