feat(sms): понятные причины ошибок в карточке доставки — техстроки планировщика (code=106, not delivered, limit exceeded) переводятся в человеческие

This commit is contained in:
Hermes 2026-09-16 16:19:17 +02:00
parent 5c98a54895
commit 4192e44998
2 changed files with 41 additions and 0 deletions

View File

@ -323,6 +323,24 @@ export const getSmsFailureReason = (log) => {
const text = log.trim(); const text = log.trim();
const onlyCode = text.match(/^(\d{3})$/)?.[1]; const onlyCode = text.match(/^(\d{3})$/)?.[1];
if (onlyCode && SMS_ERROR_REASONS[onlyCode]) return SMS_ERROR_REASONS[onlyCode]; if (onlyCode && SMS_ERROR_REASONS[onlyCode]) return SMS_ERROR_REASONS[onlyCode];
// Технические строки из планировщика вида «Not delivered after 2 attempts
// (code=106)» переводим в человеческие: код объясняем словами.
const embedded = text.match(/code\s*=\s*(\d{3})/i)?.[1];
if (embedded && SMS_ERROR_REASONS[embedded]) {
return `${SMS_ERROR_REASONS[embedded]} (код ${embedded})`;
}
// «Не доставлено после N попыток» без кода — говорим так, как есть.
const attempts = text.match(/after\s+(\d+)\s+attempts?/i);
if (/not delivered|delivery failed|failed after/i.test(text)) {
return attempts
? `клиент не получил сообщение за ${attempts[1]} попытки — телефон недоступен или оператор не доставил`
: "клиент не получил сообщение — телефон недоступен или оператор не доставил";
}
if (/limit exceeded/i.test(text)) {
return embedded && SMS_ERROR_REASONS[embedded]
? `${SMS_ERROR_REASONS[embedded]} (код ${embedded})`
: "сработал лимит отправки — SMS-сервис временно блокирует рассылку";
}
return text.slice(0, 120) || null; return text.slice(0, 120) || null;
} }
const code = smsErrorCode(log); const code = smsErrorCode(log);

View File

@ -55,6 +55,29 @@ describe("isSmsFundsError", () => {
}); });
}); });
describe("технические строки из планировщика переводятся в человеческие", () => {
it("«Second SMS failed after 2 attempts (code=106)» — код объяснён словами", () => {
const reason = getSmsFailureReason("Second SMS failed after 2 attempts (code=106)");
expect(reason).toContain("сбой на телефоне абонента");
expect(reason).toContain("код 106");
});
it("«Not delivered after 2 attempts» без кода — говорим прямо", () => {
const reason = getSmsFailureReason("Not delivered after 2 attempts");
expect(reason).toContain("не получил сообщение");
expect(reason).toContain("2 попытки");
});
it("«Second SMS limit exceeded (code=232)» — лимит словами", () => {
const reason = getSmsFailureReason("Second SMS limit exceeded (code=232)");
expect(reason).toContain("лимит одинаковых сообщений в сутки");
});
it("одна цифра 201 с переводом строки по-прежнему расшифровывается", () => {
expect(getSmsFailureReason("201\n")).toBe("на счёте SMS-сервиса закончились средства");
});
});
describe("подсветка SMS в таблице остаётся прежней", () => { describe("подсветка SMS в таблице остаётся прежней", () => {
it("без отправленных SMS — «не отправлено»", () => { it("без отправленных SMS — «не отправлено»", () => {
expect(getSmsProblemTone({})).toBe("not_sent"); expect(getSmsProblemTone({})).toBe("not_sent");