3864f6f11a
Мы продавали дешевле, чем покупали. Тариф давал скидку за объём — 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>
62 lines
2.3 KiB
PHP
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();
|
|
});
|