6f469fb13d
Денежная модель (куски 1-2): реклама в Телеграме (МТС Маркетолог, робот-в-браузере)
оплачивается с ОБЩЕГО баланса тенанта (как СМС), наценка 40%. Списание при запуске,
возврат при отказе модерации/сбое/отмене (сальдо-идемпотентность tg_ad_charge/tg_ad_refund).
Старый рекламный кошелёк-заморозка убран из потока кампаний (таблицы ad_wallets НЕ удалены).
Новый TelegramCampaignChargeService (зеркало SmsChargeService); F5 money-safety сохранён
(сбой с mts_campaign_id → needs_review без возврата). Уборщик добивает зависшие queued с возвратом.
Чистка СМС-наследия (аудит модуля построчно 5 проверяющими): модуль ресейлит ПОКАЗЫ рекламы,
а не рассылку сообщений — вырезаны выдуманные сущности, механически скопированные из СМС:
- «имя/бренд отправителя» + помесячная абонплата (в телеге МТС имени отправителя нет):
ChargeTgNameFeeJob, TelegramSenderService, SenderController, модели Sender/Setting,
фронт-панель TelegramSenderPanel, админ-карточка, updateTgSettings, тип tg_name_fee.
Таблицы client_tg_senders/_settings дропнуты.
- мёртвые таблицы client_tg_messages (доставка по номеру) и client_tg_templates (шаблоны
сообщений) — без модели/использования, дропнуты (миграция 000017, create-миграции удалены).
- client_tg_optouts переосмыслен как ручной список «не показывать этим номерам» (не «отписки»).
- лексика рассылки → рекламы: «Авторассылка»→«Авто-реклама», «кошелёк/заморожено»→«общий баланс».
Медиа объявления (реальный пробел показов): новый POST /api/telegram/campaigns/{id}/media
(картинка/видео к черновику, png/jpg/gif/mp4 ≤50 МБ, замена удаляет старый файл) + поле
загрузки в форме кабинета. Робот уже принимал media_path (RunTelegramCampaignJob → mediaFile
→ cabinet.js fillAdMedia) — не хватало только приёма файла от клиента.
Схема: db/CHANGELOG_schema.md v8.94 (CHECK += tg_ad_charge/tg_ad_refund) + v8.95 (дроп
СМС-таблиц, tg_name_fee убран). Тесты зелёные поштучно (квирк партиций — гонять по одному):
Schema/Models/AdminTg/CampaignCharge/CampaignApi/Audience/Media; фронт advertising-telegram-view
19 + admin-tg/auto-rule 24. pint/deptrac(0) чисто; larastan исключён (Pest-$this шум). Робот
bots/mts-telegram-ads НЕ трогали.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
2.3 KiB
PHP
53 lines
2.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use App\Services\ClientTg\TelegramTariffService;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
||
uses(RefreshDatabase::class);
|
||
|
||
it('ступень выбирается по объёму показов (границы)', function () {
|
||
$p = app(TelegramTariffService::class);
|
||
expect($p->pricePerImpressionRub(0))->toBe('0.45') // volume floored to >=1
|
||
->and($p->pricePerImpressionRub(999))->toBe('0.45')
|
||
->and($p->pricePerImpressionRub(1000))->toBe('0.42')
|
||
->and($p->pricePerImpressionRub(4999))->toBe('0.42')
|
||
->and($p->pricePerImpressionRub(5000))->toBe('0.40')
|
||
->and($p->pricePerImpressionRub(9999))->toBe('0.40')
|
||
->and($p->pricePerImpressionRub(10000))->toBe('0.38')
|
||
->and($p->pricePerImpressionRub(49999))->toBe('0.38')
|
||
->and($p->pricePerImpressionRub(50000))->toBe('0.36')
|
||
->and($p->pricePerImpressionRub(500000))->toBe('0.36');
|
||
});
|
||
|
||
it('смета = объём показов × цена ступени', function () {
|
||
$p = app(TelegramTariffService::class);
|
||
// 500 показов → ступень 0.45 → 225.00
|
||
expect($p->estimateRub(500))->toBe('225.00')
|
||
// 1000 показов → ступень 0.42 → 420.00
|
||
->and($p->estimateRub(1000))->toBe('420.00')
|
||
// 5000 показов → ступень 0.40 → 2000.00
|
||
->and($p->estimateRub(5000))->toBe('2000.00')
|
||
// 0 показов → 0.00
|
||
->and($p->estimateRub(0))->toBe('0.00');
|
||
});
|
||
|
||
it('клиентская смета = базовая смета × наценка (по умолчанию 1.40)', function () {
|
||
config()->set('client_tg.markup', '1.40');
|
||
$p = app(TelegramTariffService::class);
|
||
// 500 показов: база 225.00 × 1.40 = 315.00
|
||
expect($p->clientEstimateRub(500))->toBe('315.00')
|
||
// 1000 показов: база 420.00 × 1.40 = 588.00
|
||
->and($p->clientEstimateRub(1000))->toBe('588.00')
|
||
// 0 показов → 0.00
|
||
->and($p->clientEstimateRub(0))->toBe('0.00');
|
||
});
|
||
|
||
it('наценка берётся из config (переопределяемая)', function () {
|
||
config()->set('client_tg.markup', '2.00');
|
||
$p = app(TelegramTariffService::class);
|
||
// 500 показов: база 225.00 × 2.00 = 450.00
|
||
expect($p->clientEstimateRub(500))->toBe('450.00');
|
||
});
|