create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); $p = Project::factory()->for($tenant)->asSiteSignal('example.com')->create(); expect($p->signal_type)->toBe('site'); expect($p->signal_identifier)->toBe('example.com'); }); test('Project casts sms_senders as array + sms_keyword stored', function () { $tenant = Tenant::factory()->create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); $p = Project::factory() ->for($tenant) ->asSmsSignal(['TINKOFF', 'SBERBANK'], 'ипотека') ->create(); expect($p->fresh()->sms_senders)->toBe(['TINKOFF', 'SBERBANK']); expect($p->fresh()->sms_keyword)->toBe('ипотека'); }); test('Project SMS without keyword stores null keyword', function () { $tenant = Tenant::factory()->create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); $p = Project::factory() ->for($tenant) ->asSmsSignal(['TINKOFF'], null) ->create(); expect($p->fresh()->sms_keyword)->toBeNull(); expect($p->fresh()->sms_senders)->toBe(['TINKOFF']); }); test('Project has supplierB1/B2/B3 relations', function () { $tenant = Tenant::factory()->create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); $sp = SupplierProject::factory()->create(['platform' => 'B1']); $p = Project::factory()->for($tenant)->create(['supplier_b1_project_id' => $sp->id]); expect($p->supplierB1)->toBeInstanceOf(SupplierProject::class); expect($p->supplierB1->id)->toBe($sp->id); expect($p->supplierB2)->toBeNull(); expect($p->supplierB3)->toBeNull(); }); test('Project scopeActiveOnDay returns only projects with today bit set in delivery_days_mask', function () { $tenant = Tenant::factory()->create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); // Все 7 дней (битмаска 0b1111111 = 127) Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 0b1111111, ]); // Только Сб+Вс (биты 5,6 = 0b1100000 = 96) Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 0b1100000, ]); // Неактивный — не попадает независимо от маски Project::factory()->for($tenant)->create([ 'is_active' => false, 'delivery_days_mask' => 0b1111111, ]); $todayDow = (int) now()->dayOfWeekIso; // Проект на все дни должен пройти на любой день $count = Project::activeOnDay($todayDow)->count(); expect($count)->toBeGreaterThanOrEqual(1); // Понедельник (ISO=1, bit 0): проходит только проект на все дни expect(Project::activeOnDay(1)->count())->toBe(1); // Суббота (ISO=6, bit 5): проходят оба активных expect(Project::activeOnDay(6)->count())->toBe(2); }); test('Project scopeForSignal filters by (signal_type, signal_identifier)', function () { $tenant = Tenant::factory()->create(); DB::statement("SET LOCAL app.current_tenant_id = '{$tenant->id}'"); Project::factory()->for($tenant)->asSiteSignal('a.com')->create(); Project::factory()->for($tenant)->asSiteSignal('b.com')->create(); Project::factory()->for($tenant)->asCallSignal('79991234567')->create(); expect(Project::forSignal('site', 'a.com')->count())->toBe(1); expect(Project::forSignal('site', 'b.com')->count())->toBe(1); expect(Project::forSignal('call', '79991234567')->count())->toBe(1); expect(Project::forSignal('site', 'nonexistent.com')->count())->toBe(0); });