7bd9c67053
Одно имя «на всех» стало полуправдой 05.08.2026: номера с несогласованным именем перестали уходить вовсе, а к Билайну и МегаФону канала пока нет. Экран продолжал обещать отправку — половина базы исчезала бы для клиента молча. Теперь на экране «Имя отправителя» разложено по четырём сетям владельца: ✓ МТС уйдёт под именем «mybrand.ru» ✗ Билайн не уйдёт — сюда мы пока не шлём ✗ МегаФон не уйдёт — сюда мы пока не шлём ✗ Теле2 не уйдёт — ваше имя у этого оператора не согласовано Показываем ВСЕ четыре сети, включая недоступные: клиент, у которого половина базы на Билайне, должен видеть, куда она делась, а не гадать. Причины разведены и проверяются в том же порядке, что у отборщика получателей: сперва запрет владельца, потом канал, потом имя. Иначе клиент прочитал бы про имя там, где мы и так не шлём, и пошёл бы зря его согласовывать. Названия операторов словами — на ЭКРАНЕ, не на сервере: сервер отдаёт ключ и причину, как назвать это человеку — дело интерфейса (так же в соседних экранах). Тесты экрана — с настоящим монтированием, а не сверкой исходника: проверяем, что надпись дошла до глаз, а не что нужное слово где-то есть в файле. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
125 lines
5.0 KiB
PHP
125 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\ClientSmsSender;
|
|
use App\Models\ClientSmsSettings;
|
|
use App\Models\Tenant;
|
|
use App\Services\ClientSms\AllowedSmsOperators;
|
|
use App\Services\ClientSms\ClientSmsSenderOverview;
|
|
use App\Services\ClientSms\ClientSmsSenderResolver;
|
|
use App\Services\Sms\OperatorNormalizer;
|
|
use App\Services\Sms\Providers\MtsSmsProvider;
|
|
use App\Services\Sms\Providers\T2SmsProvider;
|
|
use App\Services\Sms\SmsRouter;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
/**
|
|
* Честная картина по операторам для экрана «Имя отправителя».
|
|
*
|
|
* Клиент должен видеть по КАЖДОЙ сети, что с его рассылкой будет: уйдёт под его
|
|
* именем, уйдёт от имени Лидерры или не уйдёт вовсе — и почему. До 05.08.2026
|
|
* экран показывал ОДНО имя на всех, и после отсева по имени
|
|
* (см. ClientSmsSenderResolver) это стало прямой полуправдой: номера молча
|
|
* исчезали бы из рассылки, а экран продолжал бы обещать отправку.
|
|
*
|
|
* Названия операторов словами живут на ЭКРАНЕ, а не здесь: сервер отдаёт ключи
|
|
* и причины, экран решает, как их назвать человеку.
|
|
*/
|
|
uses(RefreshDatabase::class);
|
|
|
|
function overviewFor(int $tenantId): array
|
|
{
|
|
// Роутер собран руками: в песочнице синглтон — заглушка, которая
|
|
// маршрутизирует всё подряд, и картина вышла бы неправдой.
|
|
$router = new SmsRouter([
|
|
new MtsSmsProvider(token: 'test', serves: ['mts'], priceKopecks: ['*' => 0]),
|
|
new T2SmsProvider('login', 'pass', ['tele2'], ['*' => 692]),
|
|
]);
|
|
|
|
$overview = new ClientSmsSenderOverview(
|
|
$router,
|
|
new AllowedSmsOperators(new OperatorNormalizer),
|
|
new ClientSmsSenderResolver,
|
|
);
|
|
|
|
return collect($overview->forTenant($tenantId))->keyBy('operator')->all();
|
|
}
|
|
|
|
function makeOverviewSender(?array $operators): Tenant
|
|
{
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
ClientSmsSender::create([
|
|
'tenant_id' => $tenant->id,
|
|
'name' => 'mybrand.ru',
|
|
'name_type' => ClientSmsSender::TYPE_WEBSITE,
|
|
'status' => ClientSmsSender::STATUS_ACTIVE,
|
|
'operators' => $operators,
|
|
'monthly_fee_rub' => '0.00',
|
|
'consent_at' => now(),
|
|
]);
|
|
|
|
return $tenant;
|
|
}
|
|
|
|
it('показывает все четыре сети владельца, а не только те, куда можем', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
// Клиент должен видеть и недоступные сети — иначе он не понимает, куда
|
|
// делась половина его базы.
|
|
expect(array_keys(overviewFor((int) $tenant->id)))
|
|
->toBe(['mts', 'beeline', 'megafon', 'tele2']);
|
|
});
|
|
|
|
it('своего имени нет — уйдёт от имени Лидерры', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
$row = overviewFor((int) $tenant->id)['mts'];
|
|
|
|
expect($row['will_send'])->toBeTrue()
|
|
->and($row['reason'])->toBe('liderra_name')
|
|
->and($row['sender_name'])->toBeNull();
|
|
});
|
|
|
|
it('имя согласовано у этой сети — уйдёт под именем клиента', function () {
|
|
$tenant = makeOverviewSender(['mts', 'tele2']);
|
|
|
|
$row = overviewFor((int) $tenant->id)['tele2'];
|
|
|
|
expect($row['will_send'])->toBeTrue()
|
|
->and($row['reason'])->toBe('own_name')
|
|
->and($row['sender_name'])->toBe('mybrand.ru');
|
|
});
|
|
|
|
it('имя есть, но у этой сети не согласовано — НЕ уйдёт', function () {
|
|
$tenant = makeOverviewSender(['mts']);
|
|
|
|
$row = overviewFor((int) $tenant->id)['tele2'];
|
|
|
|
expect($row['will_send'])->toBeFalse()
|
|
->and($row['reason'])->toBe('name_not_approved');
|
|
});
|
|
|
|
it('канала к сети нет вовсе — НЕ уйдёт, и причина именно про канал', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
foreach (['beeline', 'megafon'] as $operator) {
|
|
$row = overviewFor((int) $tenant->id)[$operator];
|
|
|
|
expect($row['will_send'])->toBeFalse()
|
|
->and($row['reason'])->toBe('no_channel');
|
|
}
|
|
});
|
|
|
|
it('оператор вычеркнут владельцем — причина про запрет, а не про канал', function () {
|
|
// Запрет важнее наличия канала: канал к МТС есть, но слать запрещено.
|
|
ClientSmsSettings::query()->update(['allowed_operators' => ['tele2']]);
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
$row = overviewFor((int) $tenant->id)['mts'];
|
|
|
|
expect($row['will_send'])->toBeFalse()
|
|
->and($row['reason'])->toBe('operator_denied');
|
|
});
|