Files
portal/app/tests/Feature/ClientSms/AdminTariffTest.php
T
Дмитрий ba8e936848 feat(смс-клиент): владелец сам задаёт, через сколько считать рассылку зависшей
Строка листа 4.3, Этап 4 Task 2.

Срок, после которого сторож считает рассылку зависшей, переехал из кода в
админку «СМС» — рядом с границами окна отправки. Поле подписано человеческими
словами и объясняет последствие: портал сперва попробует рассылку дожать, потом
остановит и вернёт клиенту замороженные деньги, а ту, что честно ждёт утра
получателей, не тронет.

Границы 5…1440 минут — не вкусовщина. Ниже пяти сторож срывал бы рассылки,
которые просто идут медленно: проверка средств и запись в журнал на каждый номер
занимают время. Выше суток чужие деньги висели бы замороженными дольше, чем
клиент вообще помнит про эту рассылку. Отказы написаны словами, а не кодами.

Поле НЕобязательное — как и границы окна: этот адрес зовут и те, кому нужны
только настройки имени отправителя, и ломать им запросы права не имеем.
(План велел сделать поле обязательным — это была ошибка плана, журнал В-139.)

Проверено вырезанием, два выреза, оба вернуты:
— убрал границы на сервере → покраснели оба теста про границы;
— убрал отправку срока с экрана → покраснели три фронтовых, включая новый.

Живой прогон в браузере: выставил 120 → сохранилось → пережило перезагрузку
страницы; ввёл 2 минуты → отказ «Слишком мало: рассылка может идти медленно,
и сторож срывал бы живые. Ставьте хотя бы 5 минут», в базу не легло. Вернул 60.

Прогоны: затронутые тесты 32/32, фронт целиком 1678 + 3 намеренно пропущенных
(было 1676, мои +2; одна ошибка — та же чужая давняя), vue-tsc ровно 8 чужих
давних в 6 файлах, pint чисто.
2026-07-29 10:25:57 +03:00

147 lines
5.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Models\ClientSmsSettings;
use App\Models\ClientSmsTariff;
use Illuminate\Foundation\Testing\DatabaseTransactions;
uses(DatabaseTransactions::class);
/**
* Task 8: SaaS-admin «Клиентские СМС» — тарифная сетка (client_sms_tariffs)
* и общие настройки (client_sms_settings, singleton).
*
* Сидированы миграциями: 5 ступеней (1/9.00, 100/8.50, 250/8.30, 500/8.10,
* 1000/8.00) + settings (fee 2500.00, grace 29 дней).
*/
test('GET /api/admin/sms/tariffs возвращает сидированные ступени и настройки', function () {
$r = $this->getJson('/api/admin/sms/tariffs');
$r->assertStatus(200);
$tariffs = $r->json('tariffs');
expect($tariffs)->toHaveCount(5);
expect(collect($tariffs)->pluck('min_qty')->all())->toBe([1, 100, 250, 500, 1000]);
expect($tariffs[0]['price_rub'])->toBe('9.00');
expect($r->json('settings.name_fee_rub_per_operator'))->toBe('2500.00');
expect($r->json('settings.name_debt_grace_days'))->toBe(29);
});
test('PUT /api/admin/sms/tariffs заменяет весь набор ступеней', function () {
$r = $this->putJson('/api/admin/sms/tariffs', [
'rows' => [
['min_qty' => 1, 'price_rub' => '10.00'],
['min_qty' => 500, 'price_rub' => '7.50'],
],
]);
$r->assertStatus(200);
expect(ClientSmsTariff::count())->toBe(2);
$rows = ClientSmsTariff::orderBy('min_qty')->get();
expect($rows[0]->min_qty)->toBe(1);
expect($rows[0]->price_rub)->toBe('10.00');
expect($rows[1]->min_qty)->toBe(500);
expect($rows[1]->price_rub)->toBe('7.50');
$responseTariffs = $r->json('tariffs');
expect($responseTariffs)->toHaveCount(2);
expect(collect($responseTariffs)->pluck('min_qty')->all())->toBe([1, 500]);
});
test('PUT /api/admin/sms/settings обновляет singleton настроек', function () {
$r = $this->putJson('/api/admin/sms/settings', [
'name_fee_rub_per_operator' => '3000.00',
'name_debt_grace_days' => 14,
]);
$r->assertStatus(200);
expect($r->json('name_fee_rub_per_operator'))->toBe('3000.00');
expect($r->json('name_debt_grace_days'))->toBe(14);
$settings = ClientSmsSettings::first();
expect($settings->name_fee_rub_per_operator)->toBe('3000.00');
expect($settings->name_debt_grace_days)->toBe(14);
});
test('PUT /api/admin/sms/tariffs с некорректной ступенью → 422', function () {
$r = $this->putJson('/api/admin/sms/tariffs', [
'rows' => [
['min_qty' => 0, 'price_rub' => '10.00'],
],
]);
$r->assertStatus(422);
$r2 = $this->putJson('/api/admin/sms/tariffs', [
'rows' => [
['min_qty' => 1, 'price_rub' => '0.00'],
],
]);
$r2->assertStatus(422);
// Исходные 5 ступеней не тронуты.
expect(ClientSmsTariff::count())->toBe(5);
});
/**
* Строка листа 4.3: срок, после которого рассылка считается зависшей, правит
* владелец — без выпуска новой версии. Значение живёт в тех же общих настройках,
* что и границы окна отправки.
*/
test('4.3 — владелец меняет срок «рассылка зависла», и он сохраняется', function () {
$r = $this->putJson('/api/admin/sms/settings', [
'name_fee_rub_per_operator' => '2500.00',
'name_debt_grace_days' => 29,
'stuck_after_minutes' => 120,
]);
$r->assertStatus(200);
expect($r->json('stuck_after_minutes'))->toBe(120);
expect(ClientSmsSettings::first()->stuck_after_minutes)->toBe(120);
});
test('4.3 — GET отдаёт срок «рассылка зависла» вместе с остальными настройками', function () {
$r = $this->getJson('/api/admin/sms/tariffs');
$r->assertStatus(200);
expect($r->json('settings.stuck_after_minutes'))->toBe(60);
});
test('4.3 — слишком короткий срок админка не принимает: сторож срывал бы живые рассылки', function () {
$base = ['name_fee_rub_per_operator' => '2500.00', 'name_debt_grace_days' => 29];
$this->putJson('/api/admin/sms/settings', $base + ['stuck_after_minutes' => 0])
->assertStatus(422)
->assertJsonValidationErrors('stuck_after_minutes');
$this->putJson('/api/admin/sms/settings', $base + ['stuck_after_minutes' => 4])
->assertStatus(422);
// Срок не тронут.
expect(ClientSmsSettings::first()->stuck_after_minutes)->toBe(60);
});
test('4.3 — срок дольше суток админка не принимает: деньги висели бы замороженными', function () {
$r = $this->putJson('/api/admin/sms/settings', [
'name_fee_rub_per_operator' => '2500.00',
'name_debt_grace_days' => 29,
'stuck_after_minutes' => 1441,
]);
$r->assertStatus(422);
expect(ClientSmsSettings::first()->stuck_after_minutes)->toBe(60);
});
test('4.3 — кто присылает только настройки имени, продолжает работать', function () {
// Контракт адреса менять права не имеем: срок необязателен, как и границы окна.
$r = $this->putJson('/api/admin/sms/settings', [
'name_fee_rub_per_operator' => '3000.00',
'name_debt_grace_days' => 20,
]);
$r->assertStatus(200);
expect(ClientSmsSettings::first()->stuck_after_minutes)->toBe(60);
});