Commit Graph

2 Commits

Author SHA1 Message Date
Дмитрий fc235bb5a6 feat(смс-клиент): недоставленное закрывается через трое суток, деньги возвращаются клиенту
Этап 5, Task 4. ДЕНЕЖНАЯ задача — решения владельца В-198 и В-199.

Что появилось:
- через трое суток «ещё в пути» становится «не доставлено». Довод не только
  продуктовый: оператор помнит судьбу ровно трое суток, после этого ответа не
  будет вовсе — закрыть сообщение обязаны мы, иначе итог рассылки никогда не
  станет окончательным и досыл не будет знать, кого досылать;
- за «не доставлено» и за «оператор не отправил» деньги возвращаются клиенту на
  кошелёк. МТС за недоставленное с нас не берёт (В-7), значит эти рубли лежали
  у нас ни за что;
- у кошелька появился метод refund() — ОТДЕЛЬНО от пополнения, и это не
  украшение: у topup() нет ключа события, а команда по расписанию по своей
  природе повторяется. На topup() второй заход вернул бы деньги ДВАЖДЫ.

ИДЕМПОТЕНТНОСТЬ ДВОЙНАЯ, и проверено, что нужны обе опоры:
  - ключ события sms:refund:{рассылка}:{номер} + уникальный ключ в базе;
  - отметка refunded_at на сообщении, ставится в ТОЙ ЖЕ транзакции.
Вырез только ключа тест НЕ красит (спасает отметка). Вырез только отметки тоже.
Сняв ОБЕ, тест краснеет числом 117.00 вместо 108.50 — деньги вернулись дважды.
Так и должно быть: одна опора страхует другую.

Вырезы (все вернуты): убрать «оператор не отправил» из возвращаемых -> 1 красный;
убрать закрытие по сроку -> 3 красных; возвращать за ЛЮБУЮ судьбу -> 2 красных
(значит тесты «за доставленное не возвращаем» и «за в пути не возвращаем» —
настоящие приборы, а не зелень вхолостую).

ЖИВОЙ ДЕНЕЖНЫЙ ПРОГОН (sandbox выключен — в песочнице деньги не двигаются вовсе,
и прогон доказал бы НОЛЬ): баланс 100.00 -> 108.50 ₽, движение типа refund ровно
одно, отметка у недоставленного стоит, у доставленного нет. ВТОРОЙ заход той же
команды: баланс тот же, движений по-прежнему одно. Стенд возвращён в исходное.

Прогоны: модуль 343/343 (13 пачек, все с первой попытки), рекламный кошелёк 5/5
(я трогал общий AdWalletService), phpstan ровно 2 чужие давние, pint чисто.
2026-07-31 06:36:27 +03:00
Дмитрий 5356bf3ed6 feat(смс-клиент): опрос судьбы отправленных сообщений у операторов
Этап 5, Task 3. Появилась команда client-sms:poll-delivery — каждые десять минут
спрашивает у канала, что стало с отправленными сообщениями, и проставляет судьбу
в журнал.

Устройство:
- умение рассказать судьбу — способность КАНАЛА: канал без разъёма просто
  пропускается. Когда у Т2/Мегафона/Билайна появятся кабинеты, команда не
  изменится ни строчкой;
- отчёт ПРАВИТ существующую строку, новых не пишет (В-204): сторож зависших
  меряет движение рассылки по последней записи журнала, и новые строки делали бы
  зависшую рассылку «живой» — деньги остались бы замороженными;
- спрашиваем только реально отправленные этим каналом, с номером сообщения,
  не старше трёх суток и с неокончательной судьбой. Оператор помнит судьбу трое
  суток — спрашивать про старое бессмысленно;
- незнакомое слово оператора судьбу НЕ меняет: пишем слово в журнал и оставляем
  графу как была. Угадать значило бы соврать про деньги.

ЖИВОЙ ПРОГОН ПОД БОЕВОЙ РОЛЬЮ, тройкой (политика srv_bypass воспроизведена тем же
текстом, что в db/03, — на стенде их нет ни одной):
  А) право UPDATE есть + политика есть -> «уточнено: 1», судьба delivered;
  Б) права UPDATE нет -> команда ПАДАЕТ «нет доступа к таблице» (видно);
  В) права есть, политики нет -> «успех», «уточнено: 0», судьба пустая (НЕ видно).
Подтверждает В-181: у двух опор разная цена отказа, и опаснее вторая. Стенд
вернулся в исходное, политик srv_bypass не осталось.

ПРО ПРИБОРЫ — два теста оказались НЕ приборами, починены, а не подогнаны:
- «незнакомое слово не меняет судьбу» не отличал «графу не тронули» от «записали
  пусто» — теперь у сообщения есть стартовая судьба, и проверяется, что она цела;
- «пробное не спрашиваем» краснел бы не от того: пробное отсекает фильтр по
  КАНАЛУ, а не по статусу. Переименован по тому, что реально охраняет, и под две
  оставшиеся защиты заведены свои тесты.
После починки каждый из четырёх вырезов добавляет ровно один красный тест.

Прогоны: модуль 336/336 (13 пачек, все с первой попытки), phpstan ровно 2 чужие
давние, pint чисто. Команда в расписании — проверено schedule:list.
2026-07-31 06:23:24 +03:00