Билайн: опрос судьбы перестал глотать отказ молча
Беда. Платформа Билайна отдаёт отказ кодом ответа 200, а слова кладёт в тело:
{"error":{"code":"-20107","message":"Ошибка авторизации"}}. Отправка это уже
проверяла, а опрос судьбы — нет: fetchOne звал разбор напрямую, разбор поля
`error` не смотрит и возвращал пустой список, неотличимый от честного «такого
сообщения нет».
Чем грозило. Сломается ключ — судьба сообщений просто перестанет обновляться,
МОЛЧА. А за «не доставлено» клиенту возвращаются рубли (В-198), то есть
молчание = невозвращённые деньги. Тот же класс, что 04.08 с уровнем журнала.
Правка. В fetchOne перед разбором прогоняется уже готовый kodOshibki(); нашёлся
код — бросается SmsSendException с terminal: false. Не окончательный намеренно:
судьбу всегда можно переспросить следующим заходом, в отличие от отправки.
Приёмник обратного звонка платформы не тронут — у него своя дорога.
Кто ловит. PollClientSmsDeliveryCommand уже пишет Log::warning и идёт дальше;
у Билайна пачка = 1 сообщение, так что отказ стоит одного номера за заход, а не
всего прохода. Warning на бою слышен — ниже него журнал глотает (урок 04.08).
Доказано, а не «должно работать». Тест написан ПЕРВЫМ и был увиден красным:
без проверки падал ровно один тест, новый, со словами «опрос прошёл молча»,
остальные 15 стояли зелёными. Вторым тестом закрыта обратная сторона: ответ без
отказа и без действий по-прежнему считается честным «сообщения нет» и НЕ роняет
заход — иначе один забытый номер срывал бы весь опрос.
Прогон: СМС 577/577, 7155 проверок (было 575/575 и 7151 — ровно на два теста и
четыре проверки больше). Pint чист, PHPStan 0 ошибок.
На бой НЕ выкачено — отдельным разрешением владельца.
This commit is contained in:
@@ -263,6 +263,19 @@ final class BeelineSmsProvider implements SmsDeliveryPayloadParser, SmsDeliveryR
|
||||
throw new SmsSendException($e->getMessage(), terminal: false);
|
||||
}
|
||||
|
||||
// 🪤 Та же ловушка, что при отправке: платформа отвечает кодом 200 и на
|
||||
// отказ, а слова кладёт в тело. Промолчать здесь опаснее, чем при отправке:
|
||||
// сломается ключ — судьба сообщений просто перестанет обновляться, и
|
||||
// пустой ответ будет неотличим от честного «такого сообщения нет».
|
||||
// А за недоставленное клиенту возвращаются рубли (В-198), то есть
|
||||
// молчание = невозвращённые деньги.
|
||||
if ($this->kodOshibki($otvet) !== '') {
|
||||
throw new SmsSendException(
|
||||
'Билайн отказал в опросе судьбы: '.$this->tekstOshibki($otvet),
|
||||
terminal: false,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->parseDeliveryPayload($otvet);
|
||||
}
|
||||
|
||||
|
||||
@@ -218,6 +218,36 @@ it('незнакомое слово о судьбе не угадывает', fu
|
||||
->and($reports[0]->rawState)->toBe('nechto-novoe');
|
||||
});
|
||||
|
||||
it('отказ платформы при опросе судьбы не проглатывает молча', function () {
|
||||
// 🪤 Билайн отдаёт отказ кодом ответа 200, а слова кладёт в тело. Раньше
|
||||
// разбор поля `error` не смотрел и возвращал пустоту, неотличимую от честного
|
||||
// «такого сообщения нет»: сломался бы ключ — судьба перестала бы обновляться
|
||||
// МОЛЧА, а за недоставленное клиенту возвращаются рубли (В-198).
|
||||
Http::fake(['a2p-sms-https.beeline.ru/*' => Http::response([
|
||||
'error' => ['code' => '-20107', 'message' => 'Ошибка авторизации'],
|
||||
], 200)]);
|
||||
|
||||
try {
|
||||
bee_provider()->fetchDelivery(['508909732338141600334']);
|
||||
throw new RuntimeException('ожидалось SmsSendException, но опрос прошёл молча');
|
||||
} catch (SmsSendException $e) {
|
||||
// Судьбу всегда можно переспросить следующим заходом — отказ здесь
|
||||
// НЕ окончательный, в отличие от отправки.
|
||||
expect($e->terminal)->toBeFalse()
|
||||
->and($e->getMessage())->toContain('20107')
|
||||
->and($e->getMessage())->toContain('Ошибка авторизации');
|
||||
}
|
||||
});
|
||||
|
||||
it('честное «такого сообщения нет» отказом не считает', function () {
|
||||
// Обратная сторона: ответ без отказа и без действий — это НЕ поломка, а
|
||||
// «платформа про такое сообщение ничего не знает». Ругаться здесь значило бы
|
||||
// сорвать весь заход опроса из-за одного забытого номера.
|
||||
Http::fake(['a2p-sms-https.beeline.ru/*' => Http::response(['actions' => []], 200)]);
|
||||
|
||||
expect(bee_provider()->fetchDelivery(['1']))->toBe([]);
|
||||
});
|
||||
|
||||
it('принятое оператором и отклонённое им разводит по разным судьбам', function () {
|
||||
$slova = ['accepted', 'rejected', 'undeliverable', 'aborted'];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user