Files
portal/app/tests/Unit
Дмитрий 3333e48450 fix обзвон: сторож бетонировал неверный потолок 602 руб, стык счётчика с таблицей не был исполнен
Беда 1. Сторож закрепил цифру, которой не существует.

В бумагах записано, что крайняя цена одного разговора — 602 руб, и эту цифру по
требованию показывают КЛИЕНТУ перед запуском. Замерил своим прибором на тарифе
2 руб / 10 руб:

  робот 40 с   + менеджер 60 мин = 612 руб
  робот 59 мин + менеджер 60 мин = 1192 руб
  крайний случай 3900 + 3600 с   = 1252 руб

Причина не в расчёте: предел 60 минут отсчитывается от мига соединения с
менеджером, значит режет только ВТОРОЕ плечо. Первое плечо не ограничено ничем,
кроме тревоги, оба складываются, и настоящий потолок вдвое выше обещанного.
А на секунду дальше крайнего случая расчёт не дорожает, а падает с тревогой —
длинный звонок не выставит счёт, он уронит счёт.

Проверка "за 60 минут, а не за 61" была снята при роботе = 0 — на здоровом
случае, где второе плечо идёт в одиночку. Она верна для своего случая, но
потолка звонка не сторожит вовсе, и своим зелёным закрепляла неверные 602 руб.

Что сделано: проверка не удалена, переименована и снабжена оговоркой, что 602 —
цена этого случая, а не потолок. Добавлены проверки на больном случае — длинные
оба плеча разом: 612, 1192, 1252. Добавлена граница падения с обеих сторон:
ровно на краю считается, на секунду дальше по любому плечу — тревога. Крайний
случай выведен из констант класса, а не прибит числом: расширят допуск —
проверка покраснеет и потолок придётся назвать заново.

Сторож показан красным: заменил в счётчике сложение плеч на
min от суммы плеч и предела — 5 проверок из 25 покраснели, а старая проверка
про 602 руб осталась ЗЕЛЁНОЙ. Возврат сверен по git hash-object.

Правило цены НЕ менялось. Счётчик считает верно.

ВОПРОС ВЛАДЕЛЬЦУ: потолка 602 руб не существует, крайняя цена 1252 руб.
Решать одно из двух — либо исправить цифру в бумагах, либо завести предел на
весь звонок, а не только на второе плечо. Сегодня клиенту обещают одно число, а
списать могут вдвое большее.

Беда 2. Стык двух кругов: имена сошлись, смысл разъехался.

Счётчик писал, что tarificiruetsya: false значит "строки в счёте нет вовсе", и
велел класть это в столбец billable. А billable в базе — признак существующей
бесплатной строки: DEFAULT TRUE плюс CHECK billable OR price_kopecks = 0.
Прочитавший подсказку буквально строку не завёл бы и счёт закрытых номеров
потерял.

Смысл сведён по бумагам, не по догадке. З-3.7 проверка 4: в журнале клиента эти
попытки видны ОТДЕЛЬНОЙ СТРОКОЙ. Проверка 5: строк В СЧЁТЕ нет. Т86 требует
счётчик попаданий в пустоту по каждому человеку — считать нечего, если строк
нет. Значит строка звонка заводится всегда, а на закрытом номере она бесплатная:
billable = FALSE при price_kopecks = 0.

Что сделано: подсказки в счётчике исправлены в трёх местах, смысл billable
назван словами в модели строки звонка тремя случаями. Заведён тест стыка — он
берёт ответ schet, кладёт его в obzvon_calls и читает обратно; проверяет, что
закрытый номер даёт строку, что три дозвона в пустоту дают три строки и ноль
денег, что недозвон и закрытый номер в базе различимы, и что база не примет
бесплатную строку с деньгами.

Единицы: перевод копеек в рубли и правда завёлся вторым местом — свой bcdiv в
модели строки звонка. Схлопнуть его НЕ ВЫШЛО, и это отдельная находка: попытка
позвать ObzvonTarifikator::rubli из модели упёрлась в правило слоёв —
App\Models не вправе зависеть от App\Services, deptrac и ADR-005.
Предкоммитный сторож остановил меня, и правильно сделал.

Раз схлопнуть нельзя — два места привязаны друг к другу проверкой: они обязаны
отвечать одинаково на наборе сумм, включая крайнюю цену звонка. Плюс датчик на
класс беды: ТРЕТЬЕ место деления на 100 по коду обзвона запрещено, оба
известных названы поимённо, и отдельная проверка следит, что список
разрешённых не устарел вслепую.

ВОПРОС АРХИТЕКТУРЕ: правильно было бы вынести перевод копеек в рубли в общего
помощника, доступного обоим слоям. Это правка deptrac.yaml либо новый слой —
решение не моё, оставляю названным, а не сделанным втихую.

Сторожа показаны красными трижды. Первый заход: закрытый номер стал
тарифицируемым и в модель вернулся лишний bcdiv — 4 из 8 покраснели, датчик
назвал точную строку. Второй заход после переделки: у модели сбита точность
перевода — 3 из 9 покраснели. Третий: из списка разрешённых убран один файл —
датчик третьего места назвал ObzvonCall.php и номер строки. Каждый возврат
сверен по git hash-object.

Схема БД и миграции не тронуты.
2026-08-05 13:37:07 +03:00
..