create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Авто', 'mode' => AdCampaign::MODE_AUTO, 'audience_days' => 10, 'use_uploaded_list' => true, 'weekly_budget_rub' => '2500.00', ]); Deal::factory()->create(['tenant_id' => $tenant->id, 'phone' => '79990001001', 'received_at' => now()->subDays(3)]); DB::table('ad_campaign_phones')->insert([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'phone' => '79990001099', 'expires_at' => null, 'created_at' => now(), 'updated_at' => now(), ]); $phones = app(CampaignAudienceBuilder::class)->build($campaign); expect($phones)->toContain('79990001001') ->and($phones)->not->toContain('79990001099'); }); it('manual: сделка внутри диапазона снимка попадает, вне — нет', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Ручной', 'mode' => AdCampaign::MODE_MANUAL, 'audience_days' => 10, 'snapshot_from' => now()->subDays(5)->format('Y-m-d'), 'snapshot_to' => now()->subDays(1)->format('Y-m-d'), 'weekly_budget_rub' => '2500.00', ]); Deal::factory()->create(['tenant_id' => $tenant->id, 'phone' => '79990002001', 'received_at' => now()->subDays(3)]); Deal::factory()->create(['tenant_id' => $tenant->id, 'phone' => '79990002002', 'received_at' => now()->subDays(20)]); $phones = app(CampaignAudienceBuilder::class)->build($campaign); expect($phones)->toContain('79990002001') ->and($phones)->not->toContain('79990002002'); }); it('manual: свой список подмешивается всегда (не по use_uploaded_list)', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Ручной без флага', 'mode' => AdCampaign::MODE_MANUAL, 'audience_days' => 10, 'snapshot_from' => now()->subDays(5)->format('Y-m-d'), 'snapshot_to' => now()->subDays(1)->format('Y-m-d'), 'use_uploaded_list' => false, 'weekly_budget_rub' => '2500.00', ]); DB::table('ad_campaign_phones')->insert([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'phone' => '79990003001', 'expires_at' => null, 'created_at' => now(), 'updated_at' => now(), ]); $phones = app(CampaignAudienceBuilder::class)->build($campaign); expect($phones)->toContain('79990003001'); }); it('manual: без заданных дат снимка сделки пустые, но список остаётся', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Ручной без дат', 'mode' => AdCampaign::MODE_MANUAL, 'audience_days' => 10, 'weekly_budget_rub' => '2500.00', ]); Deal::factory()->create(['tenant_id' => $tenant->id, 'phone' => '79990004001', 'received_at' => now()->subDay()]); DB::table('ad_campaign_phones')->insert([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'phone' => '79990004099', 'expires_at' => null, 'created_at' => now(), 'updated_at' => now(), ]); $phones = app(CampaignAudienceBuilder::class)->build($campaign); expect($phones)->not->toContain('79990004001') ->and($phones)->toContain('79990004099'); }); it('дедуп: один и тот же номер в сделке и в списке (manual) — один раз', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Дедуп', 'mode' => AdCampaign::MODE_MANUAL, 'audience_days' => 10, 'snapshot_from' => now()->subDays(5)->format('Y-m-d'), 'snapshot_to' => now()->subDays(1)->format('Y-m-d'), 'weekly_budget_rub' => '2500.00', ]); Deal::factory()->create(['tenant_id' => $tenant->id, 'phone' => '79990005001', 'received_at' => now()->subDays(2)]); DB::table('ad_campaign_phones')->insert([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'phone' => '79990005001', 'expires_at' => null, 'created_at' => now(), 'updated_at' => now(), ]); $phones = app(CampaignAudienceBuilder::class)->build($campaign); expect(array_count_values($phones)['79990005001'] ?? 0)->toBe(1); });