Files
portal/app/tests/Feature/ClientTg/SchemaTest.php
T
Дмитрий 3864f6f11a feat,телеграм-реклама: цена показа по виду медиа вместо ступеней по объёму
Мы продавали дешевле, чем покупали. Тариф давал скидку за объём — 0.45 → 0.36 ₽
за показ, — а у МТС такой скидки нет: прайс кабинета, стр. 13, берёт 0,48 ₽ за
показ плоско. Скидку давали мы, а нам её не давал никто: на объёме от 50 000
наценка 1.40 превращалась в 5%.

Второе. Кабинет показывает CPM БЕЗ НДС — колонка списка так и названа. Счёт
кампании 2231134 сошёлся: 420 × 400 ₽/1000 × 1,2 = 201,60 ₽. Мы ИП на УСН, НДС
не возмещается, это расход. Себестоимость с НДС: 0.480 без медиа, 0.720 с
картинкой, 0.816 с видео.

Третье. Вид медиа до расчёта не доходил вовсе — объявление с видео продавалось
по цене объявления без картинки. На видео уходили в минус до 176 ₽ с тысячи, и
портал нигде свою цену с ценой МТС не сравнивал. Песочница выключена с 02.08 —
деньги живые.

Что сделано:
- миграция client_tg_cena_po_media: min_qty → media_kind, точность цены 6,2 →
  6,3, три строки вместо пяти ступеней, media_kind на кампании и авто-правиле;
- вид медиа определяется по СОДЕРЖИМОМУ файла, а не по расширению имени;
- экран админки переделан: три фиксированные строки по видам медиа, рядом цена
  за тысячу для сверки с кабинетом, добавлять и удалять нечего;
- запись v9.65 в журнале схемы.

Замеры этой смены: телеграм-модуль 313 тестов 0 падений, экраны 242 файла
1841 тест 0 падений, статанализ 0, форматтер чисто. Проверка типов — 6 ошибок,
все в чужих файлах, были до нас.

Тест экрана тарифов проверен вырезанием, а не только зелёным: сломал передачу
media_kind — красный; сломал расчёт цены за тысячу — красный.

Осталось незакрытым: числа 0.720 и 0.816 — вывод по правилу «кабинет пишет без
НДС», а не замер. Счёт кампании с картинкой живьём не снимали, шаг «Стоимость»
недостижим без загрузки живых номеров. Замерите — правится одной строкой.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 22:15:46 +03:00

62 lines
2.3 KiB
PHP

<?php
declare(strict_types=1);
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
it('creates client_tg_campaigns with expected columns', function () {
expect(Schema::hasTable('client_tg_campaigns'))->toBeTrue();
expect(Schema::hasColumns('client_tg_campaigns', [
'tenant_id', 'status', 'ad_text', 'ad_link', 'media_path', 'ord_category',
'budget_cap_rub', 'audience_kind', 'audience_params', 'matched_count', 'created_by',
]))->toBeTrue();
});
it('creates client_tg_campaign_phones with expected columns', function () {
expect(Schema::hasTable('client_tg_campaign_phones'))->toBeTrue();
expect(Schema::hasColumns('client_tg_campaign_phones', [
'tenant_id', 'campaign_id', 'phone', 'expires_at',
]))->toBeTrue();
});
it('creates client_tg_optouts with expected columns', function () {
expect(Schema::hasTable('client_tg_optouts'))->toBeTrue();
expect(Schema::hasColumns('client_tg_optouts', [
'tenant_id', 'phone',
]))->toBeTrue();
});
it('creates client_tg_contacts with expected columns', function () {
expect(Schema::hasTable('client_tg_contacts'))->toBeTrue();
expect(Schema::hasColumns('client_tg_contacts', [
'tenant_id', 'phone', 'name', 'operator',
]))->toBeTrue();
});
it('creates client_tg_tariffs with expected columns and seeds exactly 3 rows', function () {
expect(Schema::hasTable('client_tg_tariffs'))->toBeTrue();
expect(Schema::hasColumns('client_tg_tariffs', [
'media_kind', 'price_rub',
]))->toBeTrue();
// Ступеней по объёму больше нет — у МТС цена плоская (миграция client_tg_cena_po_media).
expect(Schema::hasColumn('client_tg_tariffs', 'min_qty'))->toBeFalse();
expect(DB::table('client_tg_tariffs')->count())->toBe(3);
});
it('enables row level security on client_tg_campaigns with a tenant_isolation policy', function () {
$rls = DB::selectOne("SELECT relrowsecurity FROM pg_class WHERE relname = 'client_tg_campaigns'");
expect((bool) $rls->relrowsecurity)->toBeTrue();
$policyExists = DB::table('pg_policies')
->where('tablename', 'client_tg_campaigns')
->where('policyname', 'tenant_isolation')
->exists();
expect($policyExists)->toBeTrue();
});