2026-07-27 18:40:14 +03:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
use App\Models\ClientTg\Campaign;
|
2026-07-27 18:40:14 +03:00
|
|
|
|
use App\Models\ClientTg\Tariff;
|
|
|
|
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-02 22:15:46 +03:00
|
|
|
|
* SaaS-admin «Клиентская Telegram-реклама» — себестоимость показа (client_tg_tariffs).
|
|
|
|
|
|
* Гейт группы — saas-admin,admin-db (crm_admin_user); admin-db переключает соединение
|
|
|
|
|
|
* на pgsql_admin, а SharesAdminPdo (глобально в Pest.php) отдаёт ему ту же PDO-сессию,
|
2026-07-29 06:26:07 +03:00
|
|
|
|
* что у default (видимость засеянной схемы).
|
2026-07-27 18:40:14 +03:00
|
|
|
|
*
|
2026-08-02 22:15:46 +03:00
|
|
|
|
* 🔴 Форма таблицы изменилась 02.08.2026 (миграция client_tg_cena_po_media): было пять
|
|
|
|
|
|
* ступеней по объёму, стало три строки по видам медиа. У МТС скидки за объём НЕТ —
|
|
|
|
|
|
* цена плоская и зависит только от медиа (прайс кабинета, стр. 13).
|
|
|
|
|
|
*
|
|
|
|
|
|
* Здесь правится ЗАКУПОЧНАЯ цена (что платим мы), а не цена клиента: клиент платит
|
|
|
|
|
|
* её × наценку config client_tg.markup.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Сидировано миграцией: none/0.480, image/0.720, video/0.816 — с НДС.
|
2026-07-27 18:40:14 +03:00
|
|
|
|
*/
|
|
|
|
|
|
uses(DatabaseTransactions::class);
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
test('GET /api/admin/telegram/tariffs возвращает три вида медиа', function () {
|
2026-07-27 18:40:14 +03:00
|
|
|
|
$r = $this->getJson('/api/admin/telegram/tariffs');
|
|
|
|
|
|
$r->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
|
|
$tariffs = $r->json('tariffs');
|
2026-08-02 22:15:46 +03:00
|
|
|
|
expect($tariffs)->toHaveCount(3);
|
|
|
|
|
|
expect(collect($tariffs)->pluck('media_kind')->all())
|
|
|
|
|
|
->toBe([Campaign::MEDIA_NONE, Campaign::MEDIA_IMAGE, Campaign::MEDIA_VIDEO]);
|
|
|
|
|
|
expect($tariffs[0]['price_rub'])->toBe('0.480');
|
|
|
|
|
|
expect($tariffs[2]['price_rub'])->toBe('0.816');
|
2026-07-27 18:40:14 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
test('PUT /api/admin/telegram/tariffs заменяет себестоимость всех трёх видов', function () {
|
2026-07-27 18:40:14 +03:00
|
|
|
|
$r = $this->putJson('/api/admin/telegram/tariffs', [
|
|
|
|
|
|
'rows' => [
|
2026-08-02 22:15:46 +03:00
|
|
|
|
['media_kind' => Campaign::MEDIA_NONE, 'price_rub' => '0.500'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_IMAGE, 'price_rub' => '0.750'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_VIDEO, 'price_rub' => '0.900'],
|
2026-07-27 18:40:14 +03:00
|
|
|
|
],
|
|
|
|
|
|
]);
|
|
|
|
|
|
$r->assertStatus(200);
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
expect(Tariff::count())->toBe(3)
|
|
|
|
|
|
->and(Tariff::where('media_kind', Campaign::MEDIA_NONE)->first()->price_rub)->toBe('0.500')
|
|
|
|
|
|
->and(Tariff::where('media_kind', Campaign::MEDIA_VIDEO)->first()->price_rub)->toBe('0.900');
|
|
|
|
|
|
|
|
|
|
|
|
expect(collect($r->json('tariffs'))->pluck('media_kind')->all())
|
|
|
|
|
|
->toBe([Campaign::MEDIA_NONE, Campaign::MEDIA_IMAGE, Campaign::MEDIA_VIDEO]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('PUT /api/admin/telegram/tariffs с нулевой ценой → 422', function () {
|
|
|
|
|
|
$this->putJson('/api/admin/telegram/tariffs', [
|
|
|
|
|
|
'rows' => [
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_NONE, 'price_rub' => '0.000'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_IMAGE, 'price_rub' => '0.750'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_VIDEO, 'price_rub' => '0.900'],
|
|
|
|
|
|
],
|
|
|
|
|
|
])->assertStatus(422);
|
|
|
|
|
|
|
|
|
|
|
|
// Исходные строки не тронуты.
|
|
|
|
|
|
expect(Tariff::count())->toBe(3)
|
|
|
|
|
|
->and(Tariff::where('media_kind', Campaign::MEDIA_NONE)->first()->price_rub)->toBe('0.480');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 🔴 Главное, что охраняет эта ручка. Прежняя принимала произвольный список ступеней:
|
|
|
|
|
|
* владелец мог сохранить сетку без нужной строки, и расчёт упал бы уже в бою — в момент
|
|
|
|
|
|
* списания денег с клиента. Теперь набор строго три вида, каждый ровно один раз.
|
|
|
|
|
|
*/
|
|
|
|
|
|
test('PUT /api/admin/telegram/tariffs без одного вида медиа → 422, старое сохранено', function () {
|
|
|
|
|
|
$this->putJson('/api/admin/telegram/tariffs', [
|
|
|
|
|
|
'rows' => [
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_NONE, 'price_rub' => '0.500'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_IMAGE, 'price_rub' => '0.750'],
|
|
|
|
|
|
],
|
|
|
|
|
|
])->assertStatus(422);
|
2026-07-27 18:40:14 +03:00
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
expect(Tariff::count())->toBe(3)
|
|
|
|
|
|
->and(Tariff::where('media_kind', Campaign::MEDIA_NONE)->first()->price_rub)->toBe('0.480');
|
2026-07-27 18:40:14 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
test('PUT /api/admin/telegram/tariffs с задвоенным видом → 422', function () {
|
2026-07-27 18:40:14 +03:00
|
|
|
|
$this->putJson('/api/admin/telegram/tariffs', [
|
2026-08-02 22:15:46 +03:00
|
|
|
|
'rows' => [
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_NONE, 'price_rub' => '0.500'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_NONE, 'price_rub' => '0.600'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_VIDEO, 'price_rub' => '0.900'],
|
|
|
|
|
|
],
|
2026-07-27 18:40:14 +03:00
|
|
|
|
])->assertStatus(422);
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
expect(Tariff::count())->toBe(3);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('PUT /api/admin/telegram/tariffs с выдуманным видом медиа → 422', function () {
|
2026-07-27 18:40:14 +03:00
|
|
|
|
$this->putJson('/api/admin/telegram/tariffs', [
|
2026-08-02 22:15:46 +03:00
|
|
|
|
'rows' => [
|
|
|
|
|
|
['media_kind' => 'gif', 'price_rub' => '0.500'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_IMAGE, 'price_rub' => '0.750'],
|
|
|
|
|
|
['media_kind' => Campaign::MEDIA_VIDEO, 'price_rub' => '0.900'],
|
|
|
|
|
|
],
|
2026-07-27 18:40:14 +03:00
|
|
|
|
])->assertStatus(422);
|
|
|
|
|
|
|
2026-08-02 22:15:46 +03:00
|
|
|
|
expect(Tariff::count())->toBe(3);
|
2026-07-27 18:40:14 +03:00
|
|
|
|
});
|