593030271b
Имя согласовывает ОПЕРАТОР, и у каждого оно своё. Клиентская рассылка несла одно имя всем каналам, а умолчанием ему служило `services.sms.mts.naming` — то есть имя, согласованное с МТС, подставлялось Теле2 и подставилось бы Мегафону и Билайну. Живой отказ Теле2 `invalid_source_address` 04.08.2026 — ровно этот механизм. На бою у клиентов заведено НОЛЬ своих имён, значит это касалось каждой отправки. Появился ClientSmsSenderResolver: спрашивает имя у той сети, чей номер. Пустая строка на выходе — не «имени нет», а «своего имени для этой сети нет, канал подпишется собственным согласованным именем из настроек». Переведены на него оба места отправки: рассылка (SendClientSmsCampaignJob) и авто-СМС по сделке (SendAutoSmsForDealJob). Универсальный СМС-центр передавал имя КАК ЕСТЬ — теперь тоже падает на своё (SMSC_NAMING). Раньше пустое имя туда не приходило никогда, с этой правкой стало бы приходить: ушли бы СМС без отправителя. Заплатка внутри канала Теле2 (приведение написания к своему регистру) остаётся, но больше не несущая: она чинила следствие в одном канале, а причина была общая. Экранное имя (ResolvesClientSmsSenderName) НЕ трогали — это запись намерения, а не то, чем подпишется сеть; в его шапке теперь написано почему, чтобы не «починили» обратно. 🪤 Урок по дороге: авто-СМС ловит любую ошибку и молча выходит. Справочник имён был передан не в ту функцию — вместо падения получилась ТИШИНА, не уходило ничего. Поймали три чужих теста, до того зелёных. Проверено: 4614 тестов, упал один чужой (ExampleTest — в этой папке не собран фронтенд). Статанализ 0. Стиль правленых файлов чист. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
87 lines
4.0 KiB
PHP
87 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\ClientSmsSender;
|
|
use App\Models\Tenant;
|
|
use App\Services\ClientSms\ClientSmsSenderResolver;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
|
|
/**
|
|
* Имя отправителя согласовывает ОПЕРАТОР, а не канал: через универсальный
|
|
* СМС-центр можно слать в любую сеть, и спрашивать надо у той сети, чей номер.
|
|
*
|
|
* До 05.08.2026 клиентская рассылка несла ОДНО имя всем, а умолчанием служило
|
|
* `services.sms.mts.naming` — то есть имя, согласованное с МТС, подставлялось
|
|
* Теле2 и любому будущему каналу. Живой отказ `invalid_source_address` от Теле2
|
|
* 04.08 — ровно этот механизм.
|
|
*
|
|
* Пустая строка на выходе — НЕ «нет имени», а «своего имени нет, подпишись
|
|
* собственным именем канала»: каждый канал знает своё согласованное написание
|
|
* из настроек (MtsSmsProvider: `senderName !== '' ? senderName : $this->naming`).
|
|
*/
|
|
uses(DatabaseTransactions::class);
|
|
|
|
function makeSenderFor(?array $operators, string $status = ClientSmsSender::STATUS_ACTIVE, string $name = 'mybrand.ru'): Tenant
|
|
{
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
ClientSmsSender::create([
|
|
'tenant_id' => $tenant->id,
|
|
'name' => $name,
|
|
'name_type' => ClientSmsSender::TYPE_WEBSITE,
|
|
'status' => $status,
|
|
'operators' => $operators,
|
|
'monthly_fee_rub' => '0.00',
|
|
'consent_at' => now(),
|
|
]);
|
|
|
|
return $tenant;
|
|
}
|
|
|
|
it('своего имени нет вовсе — отдаёт пустую строку, чтобы канал подписался своим', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'tele2'))->toBe('');
|
|
});
|
|
|
|
it('имя согласовано у этого оператора — отдаёт его', function () {
|
|
$tenant = makeSenderFor(['mts', 'tele2']);
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'tele2'))->toBe('mybrand.ru');
|
|
});
|
|
|
|
it('имя согласовано у ДРУГОГО оператора — своим именем не подписывает', function () {
|
|
$tenant = makeSenderFor(['mts']);
|
|
|
|
// Ровно тот случай, что дал живой отказ Теле2 04.08.2026.
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'tele2'))->toBe('');
|
|
});
|
|
|
|
it('список операторов не заполнен — считаем, что имя годится всем', function () {
|
|
// Старые записи заведены до появления разбора по операторам: отнять у них
|
|
// имя молча — значит поменять поведение задним числом.
|
|
$tenant = makeSenderFor(null);
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'megafon'))->toBe('mybrand.ru');
|
|
});
|
|
|
|
it('имя ещё на согласовании — не подписывает им', function () {
|
|
$tenant = makeSenderFor(['tele2'], ClientSmsSender::STATUS_PENDING);
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'tele2'))->toBe('');
|
|
});
|
|
|
|
it('имя приостановлено за долг — не подписывает им', function () {
|
|
$tenant = makeSenderFor(['tele2'], ClientSmsSender::STATUS_SUSPENDED);
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($tenant->id, 'tele2'))->toBe('');
|
|
});
|
|
|
|
it('чужое имя соседа не подставляет', function () {
|
|
makeSenderFor(['tele2'], ClientSmsSender::STATUS_ACTIVE, 'sosed.ru');
|
|
$mine = Tenant::factory()->create();
|
|
|
|
expect(app(ClientSmsSenderResolver::class)->forOperator($mine->id, 'tele2'))->toBe('');
|
|
});
|