tenant = Tenant::factory()->create(); $this->user = User::factory()->create(['tenant_id' => $this->tenant->id]); $this->actingAs($this->user); $this->campaign = AdCampaign::create([ 'tenant_id' => $this->tenant->id, 'name' => 'Кампания под список номеров', 'audience_days' => 10, 'weekly_budget_rub' => '1000.00', ]); }); it('recognizes valid phones from text, dedupes and skips invalid ones', function () { $text = implode("\n", [ '+7 900 000-00-01', '79000000002', '89000000003', '9000000004', // 10 digits without leading 7/8 — valid RU mobile '79000000002', // duplicate of line 2 'not-a-phone', // invalid '123', // invalid ]); $response = $this->postJson("/api/advertising/campaigns/{$this->campaign->id}/phones", [ 'text' => $text, ]); $response->assertOk() ->assertJsonPath('recognized', 4) ->assertJsonPath('skipped', 3); $this->assertDatabaseHas('ad_campaign_phones', [ 'tenant_id' => $this->tenant->id, 'campaign_id' => $this->campaign->id, 'phone' => '79000000001', ]); $this->assertDatabaseHas('ad_campaign_phones', [ 'campaign_id' => $this->campaign->id, 'phone' => '79000000002', ]); $this->assertDatabaseHas('ad_campaign_phones', [ 'campaign_id' => $this->campaign->id, 'phone' => '79000000003', ]); $this->assertDatabaseHas('ad_campaign_phones', [ 'campaign_id' => $this->campaign->id, 'phone' => '79000000004', ]); $count = DB::table('ad_campaign_phones')->where('campaign_id', $this->campaign->id)->count(); expect($count)->toBe(4); }); it('recognizes valid phones from an uploaded csv file', function () { $content = implode("\n", [ '+7 900 000-00-05', '79000000006', 'garbage', ]); $file = UploadedFile::fake()->createWithContent('phones.csv', $content); $response = $this->postJson("/api/advertising/campaigns/{$this->campaign->id}/phones", [ 'file' => $file, ]); $response->assertOk() ->assertJsonPath('recognized', 2) ->assertJsonPath('skipped', 1); $this->assertDatabaseHas('ad_campaign_phones', [ 'campaign_id' => $this->campaign->id, 'phone' => '79000000005', ]); $this->assertDatabaseHas('ad_campaign_phones', [ 'campaign_id' => $this->campaign->id, 'phone' => '79000000006', ]); }); it('does not fail on repeated upload thanks to the unique constraint', function () { $this->postJson("/api/advertising/campaigns/{$this->campaign->id}/phones", [ 'text' => '79000000007', ])->assertOk(); $response = $this->postJson("/api/advertising/campaigns/{$this->campaign->id}/phones", [ 'text' => '79000000007', ]); $response->assertOk()->assertJsonPath('recognized', 1); $count = DB::table('ad_campaign_phones') ->where('campaign_id', $this->campaign->id) ->where('phone', '79000000007') ->count(); expect($count)->toBe(1); }); it('returns 404 when uploading phones for another tenants campaign', function () { $tenantB = Tenant::factory()->create(); $campaignB = AdCampaign::create([ 'tenant_id' => $tenantB->id, 'name' => 'Чужая кампания', 'audience_days' => 10, 'weekly_budget_rub' => '1000.00', ]); $response = $this->postJson("/api/advertising/campaigns/{$campaignB->id}/phones", [ 'text' => '79000000008', ]); $response->assertStatus(404); $this->assertDatabaseMissing('ad_campaign_phones', ['campaign_id' => $campaignB->id]); });