119 lines
4.7 KiB
PHP
119 lines
4.7 KiB
PHP
|
|
<?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');
|
|||
|
|
});
|