Files
portal/app/tests/Feature/ClientTg/AutoMediaCenaTest.php
T

119 lines
4.7 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\ClientTg\AutoRule;
use App\Models\ClientTg\Campaign;
use App\Models\Tenant;
use App\Models\User;
use App\Services\ClientTg\TelegramAutoAccumulator;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Tests\Support\MtsMediaFixture;
/**
* Авто-реклама тоже считает деньги по виду медиа (решение владельца 02.08.2026).
*
* 🔴 Почему отдельным файлом. Накопитель авто-режима — ТРЕТЬЕ место, где считается
* клиентская цена (первые два — создание кампании и её запуск). Разъедутся — экран
* покажет одно, спишется другое. У авто-правила своё медиа, и оно переносится в
* кампанию-пачку: если вид не перенести, пачка с видео будет продана как пачка
* без картинки.
*
* Числа: 400 показов × 0.816 ₽ × 1.40 = 456.96 ₽ с видео против 268.80 ₽ без медиа.
*
* Синтетические файлы и номера 7999… — реальных ПДн нет.
*/
uses(RefreshDatabase::class);
beforeEach(function () {
Storage::fake('local');
$this->withHeaders(['Accept' => 'application/json']);
$this->tenant = Tenant::factory()->create(['balance_rub' => '50000.00']);
$this->user = User::factory()->create(['tenant_id' => $this->tenant->id]);
$this->actingAs($this->user);
config(['client_tg.markup' => '1.40']);
});
/** Правило авто-рекламы с порогом заведомо выше, чем мы наберём (копим, не запускаем). */
function praviloAvtoCena(mixed $test, int $porog = 100000): AutoRule
{
return AutoRule::create([
'tenant_id' => $test->tenant->id,
'enabled' => true,
'ad_text' => 'Приходите к нам',
'ad_link' => 'https://t.me/example',
'ord_category' => 'Размещение рекламы',
'budget_cap_rub' => '5000.00',
'daily_limit_rub' => '5000.00',
'batch_threshold' => $porog,
'updated_by' => $test->user->id,
]);
}
it('видео в авто-правиле помечается как video', function () {
praviloAvtoCena($this);
$this->post('/api/telegram/auto-rule/media', [
'media' => MtsMediaFixture::video(),
])->assertOk();
expect(AutoRule::where('tenant_id', $this->tenant->id)->first()->media_kind)
->toBe(Campaign::MEDIA_VIDEO);
});
it('картинка в авто-правиле помечается как image', function () {
praviloAvtoCena($this);
$this->post('/api/telegram/auto-rule/media', [
'media' => MtsMediaFixture::kartinka(),
])->assertOk();
expect(AutoRule::where('tenant_id', $this->tenant->id)->first()->media_kind)
->toBe(Campaign::MEDIA_IMAGE);
});
it('вид медиа переносится из правила в кампанию-пачку', function () {
praviloAvtoCena($this);
$this->post('/api/telegram/auto-rule/media', [
'media' => MtsMediaFixture::video(),
])->assertOk();
app(TelegramAutoAccumulator::class)->accumulate($this->tenant->id, '79990000001');
$pachka = Campaign::where('tenant_id', $this->tenant->id)->whereNull('created_by')->first();
expect($pachka)->not->toBeNull()
->and($pachka->media_kind)->toBe(Campaign::MEDIA_VIDEO);
});
it('смета пачки с видео считается по видео, а не по «просто показам»', function () {
praviloAvtoCena($this);
$this->post('/api/telegram/auto-rule/media', [
'media' => MtsMediaFixture::video(),
])->assertOk();
$nakopitel = app(TelegramAutoAccumulator::class);
for ($i = 0; $i < 400; $i++) {
$nakopitel->accumulate($this->tenant->id, sprintf('7999%07d', $i));
}
$pachka = Campaign::where('tenant_id', $this->tenant->id)->whereNull('created_by')->first();
expect($pachka->planned_count)->toBe(400)
->and((string) $pachka->estimated_cost_rub)->toBe('456.96');
});
it('пачка без медиа считается по цене без медиа', function () {
praviloAvtoCena($this);
$nakopitel = app(TelegramAutoAccumulator::class);
for ($i = 0; $i < 400; $i++) {
$nakopitel->accumulate($this->tenant->id, sprintf('7999%07d', $i));
}
$pachka = Campaign::where('tenant_id', $this->tenant->id)->whereNull('created_by')->first();
expect((string) $pachka->estimated_cost_rub)->toBe('268.80');
});