diff --git a/app/app/Services/Sms/SmsRouter.php b/app/app/Services/Sms/SmsRouter.php index b8f6255f..2add1296 100644 --- a/app/app/Services/Sms/SmsRouter.php +++ b/app/app/Services/Sms/SmsRouter.php @@ -42,4 +42,27 @@ final class SmsRouter return $candidates[0]; } + + /** + * Запасной канал, если основной отказал. Работает ТОЛЬКО при включённом + * флаге services.sms.failover_to_universal (по умолчанию ВЫКЛ). Возвращает + * универсала, отличного от основного. Точка расширения — сейчас не вызывается + * из джоба (решение владельца 23.07.2026 — без резерва). + */ + public function fallbackFor(string $operator): ?SmsProvider + { + if (! config('services.sms.failover_to_universal')) { + return null; + } + + $primary = $this->pick($operator); + + foreach ($this->providers as $provider) { + if (in_array('*', $provider->servesOperators(), true) && $provider !== $primary) { + return $provider; + } + } + + return null; + } } diff --git a/app/tests/Unit/Sms/SmsRouterFailoverTest.php b/app/tests/Unit/Sms/SmsRouterFailoverTest.php new file mode 100644 index 00000000..cc64a946 --- /dev/null +++ b/app/tests/Unit/Sms/SmsRouterFailoverTest.php @@ -0,0 +1,57 @@ +k; + } + + public function servesOperators(): array + { + return $this->ops; + } + + public function priceKopecks(string $operator): int + { + return 100; + } + + public function send(SmsOutgoing $m): SmsSendResult + { + return new SmsSendResult('x', 1, 100, CarbonImmutable::now()); + } + }; +} + +it('по умолчанию резерва нет — второй канал не отдаётся', function () { + config()->set('services.sms.failover_to_universal', false); + $router = new SmsRouter([ + failover_provider('mts', ['mts']), + failover_provider('smsc', ['*']), + ]); + + expect($router->fallbackFor('mts'))->toBeNull(); +}); + +it('при включённом флаге резерв — универсал', function () { + config()->set('services.sms.failover_to_universal', true); + $router = new SmsRouter([ + failover_provider('mts', ['mts']), + failover_provider('smsc', ['*']), + ]); + + expect($router->fallbackFor('mts')?->key())->toBe('smsc'); +});