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

112 lines
5.9 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\ClientTg\Campaign;
use App\Services\ClientTg\TelegramTariffService;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
/**
* 🔴 Замер живьём 02.08.2026 (кабинет МТС + прайс «Скачать прайс», страница 13).
*
* Прежний тариф был ступенчатым (0.45 → 0.36 ₽ за показ по объёму) и строился на
* числе «CPM 400 ₽», которое кабинет показывает БЕЗ НДС. Обе посылки оказались
* неверными:
*
* 1. Скидки за объём у МТС НЕТ. Прайс, раздел «Реклама в Telegram по своей базе»:
* «1 показ в Telegram абонентам других операторов РФ — 0,48 ₽», плоско.
* 2. 0,48 ₽ — цена С НДС («Бюджет рекламы и CPM включает НДС»). Сходится с кабинетом:
* аудитория 420 × 400 ₽/1000 × 1,2 = 201,60 ₽ — ровно счёт кампании 2231134.
*
* Из-за этого наценка 1.40 существовала только на бумаге: на объёме от 50 000 клиент
* платил 504 ₽ за тысячу при себестоимости 480 ₽ — наценка 5%, а не 40%.
*
* Медиа кабинет тарифицирует отдельно (шаг «Объявление», блок «Медиа»):
* «CPM с изображением — 600 ₽, с видео — 680 ₽» — это ПОЛНАЯ ставка, а не надбавка.
* Числа показаны по тому же правилу без НДС ⇒ с НДС 720 и 816 ₽ за тысячу.
* 🪤 Последнее — ВЫВОД по правилу, а не замер: доказать можно только кампанией с
* картинкой, доведённой до шага «Стоимость» (туда не попасть без загрузки живых номеров).
*/
it('себестоимость показа плоская и зависит только от медиа', function () {
$p = app(TelegramTariffService::class);
expect($p->costPerImpressionRub(Campaign::MEDIA_NONE))->toBe('0.480')
->and($p->costPerImpressionRub(Campaign::MEDIA_IMAGE))->toBe('0.720')
->and($p->costPerImpressionRub(Campaign::MEDIA_VIDEO))->toBe('0.816');
});
it('объём на себестоимость не влияет — скидки за объём у МТС нет', function () {
$p = app(TelegramTariffService::class);
// Прежний тариф на этих же объёмах давал 0.45 / 0.42 / 0.40 / 0.38 / 0.36.
foreach ([1, 999, 1000, 5000, 10000, 50000, 500000] as $volume) {
expect($p->estimateRub($volume, Campaign::MEDIA_NONE))
->toBe(bcmul((string) $volume, '0.480', 2));
}
});
it('смета = показы × себестоимость вида медиа', function () {
$p = app(TelegramTariffService::class);
expect($p->estimateRub(1000, Campaign::MEDIA_NONE))->toBe('480.00')
->and($p->estimateRub(1000, Campaign::MEDIA_IMAGE))->toBe('720.00')
->and($p->estimateRub(1000, Campaign::MEDIA_VIDEO))->toBe('816.00')
->and($p->estimateRub(0, Campaign::MEDIA_NONE))->toBe('0.00');
});
it('клиентская цена = себестоимость × наценка: 672 / 1008 / 1142 ₽ за тысячу', function () {
config()->set('client_tg.markup', '1.40');
$p = app(TelegramTariffService::class);
expect($p->clientEstimateRub(1000, Campaign::MEDIA_NONE))->toBe('672.00')
->and($p->clientEstimateRub(1000, Campaign::MEDIA_IMAGE))->toBe('1008.00')
// 816.00 × 1.40 = 1142.40
->and($p->clientEstimateRub(1000, Campaign::MEDIA_VIDEO))->toBe('1142.40')
->and($p->clientEstimateRub(0, Campaign::MEDIA_NONE))->toBe('0.00');
});
it('без медиа — вид по умолчанию (старые вызовы не начинают считать по видео)', function () {
config()->set('client_tg.markup', '1.40');
$p = app(TelegramTariffService::class);
expect($p->clientEstimateRub(1000))->toBe('672.00');
});
it('наценка берётся из настроек', function () {
config()->set('client_tg.markup', '2.00');
$p = app(TelegramTariffService::class);
expect($p->clientEstimateRub(1000, Campaign::MEDIA_NONE))->toBe('960.00');
});
/**
* Сторож от молчаливого убытка: клиент обязан платить БОЛЬШЕ, чем платим мы.
* Именно этой проверки не было, и потому ступенчатый тариф годами уводил бы
* крупные кампании с медиа в минус, ничего не сказав.
*/
it('клиентская цена всегда выше себестоимости — на любом объёме и любом медиа', function () {
config()->set('client_tg.markup', '1.40');
$p = app(TelegramTariffService::class);
foreach ([Campaign::MEDIA_NONE, Campaign::MEDIA_IMAGE, Campaign::MEDIA_VIDEO] as $kind) {
foreach ([1, 367, 1000, 5000, 50000, 500000] as $volume) {
$nasha = $p->estimateRub($volume, $kind);
$klienta = $p->clientEstimateRub($volume, $kind);
expect(bccomp($klienta, $nasha, 2))->toBe(
1,
"объём {$volume}, медиа {$kind}: клиент платит {$klienta}, мы платим {$nasha}"
);
}
}
});
it('неизвестный вид медиа не проходит молча', function () {
$p = app(TelegramTariffService::class);
expect(fn () => $p->costPerImpressionRub('gif'))
->toThrow(InvalidArgumentException::class);
});