tenant = Tenant::factory()->create(); $this->user = User::factory()->create(['tenant_id' => $this->tenant->id]); $this->actingAs($this->user); config(['services.yandex_direct.min_spend_limit_rub_per_day' => 300]); config(['services.yandex_direct.spend_limit_guard_multiplier' => '1.2']); DB::table('ad_settings')->update(['ad_margin_percent' => '40.00']); }); it('мастер получает минимум площадки в показах и рублях, наценку не раскрывая', function () { $campaign = AdCampaign::create([ 'tenant_id' => $this->tenant->id, 'name' => 'Черновик', 'status' => AdCampaign::STATUS_DRAFT, 'audience_days' => 10, 'mode' => AdCampaign::MODE_AUTO, 'run_days' => 1, 'client_cpm_rub' => '500.00', ]); $otvet = $this->getJson("/api/advertising/campaigns/{$campaign->id}/audience-size?frequency=5&days=10") ->assertOk(); // Срок 1 день → период сегодня…завтра = 2 календарных дня → минимум Яндексу 600 ₽. // Яндексу уходит 60 % от 500 ₽ = 300 ₽ за тысячу; с запасом 1,2 это 0,36 ₽ за показ. // 600 / 0,36 = 1 666,67 → 1 667 показов. Клиенту это 1667 × 500 / 1000 = 833,50 ₽. $otvet->assertJsonPath('min_impressions', 1667) ->assertJsonPath('min_cost_rub', '833.50'); // Наценка, доля Яндекса и его ставка клиенту не видны ни в каком виде. $telo = $otvet->getContent(); expect($telo)->not->toContain('margin') ->and($telo)->not->toContain('yandex_cpm') ->and($telo)->not->toContain('300.00'); }); it('запуск и мастер считают минимум ОДНИМ счётчиком', function () { $schetchik = app(YandexMinimumSpend::class); $itog = $schetchik->minimum(1, '500.00'); expect($itog['impressions'])->toBe(1667) ->and($itog['cost_rub'])->toBe('833.50'); }); it('длиннее срок — выше минимум: неделя стоит семь дней по 300 ₽', function () { $schetchik = app(YandexMinimumSpend::class); // Срок 7 дней → период сегодня…+6 = 7 календарных дней → 2100 ₽ Яндексу. // 2100 / 0,36 = 5 833,33 → 5 834 показа → 2 917,00 ₽ клиенту. $itog = $schetchik->minimum(7, '500.00'); expect($itog['impressions'])->toBe(5834) ->and($itog['cost_rub'])->toBe('2917.00'); });