Всё свели к пересчетам

Посоветовался с менеджерами, которые занимаются пересчетами - они не воодушевились. Сейчас объясню, почему.
Пересчеты у нас бывают двух типов:
1) "Внешние" - пересчеты по договорённости, суммы берутся с потолка. Например, возмещают время простоя из-за аварии, делают скидку, если клиент много накачал по трафику и т.п.
2) Пересчеты из-за неверного начисления в биллинге:
а) Ошибка на уровне договора (был указан не тот тариф, неправильно проставлена абонплата и т.п.)
б) Ошибка глобальной конфигурации (в глобальных тарифах, конфигурации модулей и т.п.)
2-а: Сейчас менеджеры считают разницу руками и проставляют соответствующий расход. Предложил, чтобы это считал биллинг - не увидел интереса. Во-первых, большинство таких пересчетов - абонплаты, которые легко считаются на калькуляторе (а если не абонплаты, то можно взять примерную сумму). Во-вторых, придётся изменять сущности на договоре задним числом, откатывать период - потом сложнее, чем в 2-б, разбираться, откуда взялась именно такая наработка. Нарушается та самая целостность (она и сейчас нарушается, но только в результате ошибок - см. сноску *).
Важно: Поскольку в этом случае открывается период, то не стоит привязывать логику таких начислений дельты к нему - будет много ошибок, т.к. сначала нужно открыть период для внесения изменений, затем закрыть и уже тогда пересчитать, чтобы баланс не съехал.
2-б: Здесь уже можно использовать contract_account_delta как средство пересчетов. Но такое бывает довольно редко.
Я вспоминаю только один раз - неправильно посчитались какие-то трафики, пришлось пересчитывать предыдущий месяц куче клиентов, предварительно сделав срез балансов, затем скриптом создавать догоняющие счета на дельту. Ужас.По пунктам:
Администратор писал(а):
1) По результату переобсчёта дельта заносится в отдельную таблицу contract_account_delta со столбцами:
год
месяц
услуга
стоимость
перенесена на год
перенесена на месяц
Если переобсчёт производится ещё раз, то таблица дельты меняется. Если месяц закрыт, то результаты переобсчётов меняют только таблицу дельты.
Да. Хранить или дельту, или новую наработку - без разницы. Только пожалуй лучше не привязывать эту логику к закрытому периоду, а сделать отдельный параметр. Закрытый период часто откатывается. Кроме того, сейчас в закрытом периоде начисления производить нельзя, но проблемы возникают, когда его открывают и пересчитывают не то и не тем. Т.е. лучше эту настройку отделить.
Корни проблемы в том, что глобальные действия и действия уровня договора не разделяются в закрытом периоде: приходится открывать его для всех действий.
Администратор писал(а):
2) В какой-то последующий месяц дельту нужно зачесть в баланс.
Всякая дельта должна быть зачтена в какой-то из последующих месяцев.
Насчет "должна" - не думаю.
Администратор писал(а):
Незачтённые дельты как-то заносятся на баланс и отображаются там наподобие расходов разных знаков.
Тоже необязательно. Т.е. не стоит строго требовать обработки дельты и вести учет: обработано, или нет.
Попробую представить, как будем пользоваться этим.
Возможны два случая:
1) Дельта появилась в результате осознанных действий пользователя: мы сами разбираемся с дельтой - после пересчета вносим её расходом соответствующего знака в текущем месяце. Причём в нашем случае расход один - сумма дельт по услугам.
2) Пересчет произошел по ошибке - за определённый месяц на некотором договоре появились дельты => нужно разбираться. По резульатам ошибка либо исправляется, либо нет (те же netflow.link в dialup), но таблица contract_account_delta обнуляется руками для этого договора + бьём по рукам тому, кто запускал начисление. Отслеживать такие изменения можно глобальным скриптом по расписанию, который шлёт на email отчет. Тогда в первом случае тоже нужно обнулять contract_account_delta для договора при "легальном" пересчете, чтобы они не появлялись в отчетах.
restart писал(а):
Тогда тут же еще вопрос: нужно ли заводить под это дело совершенно новую сущности типа "Перерасчет", которая будет идти отдельным столбцом в таблице contract_balance? Или же просто вносить это изменение как платеж (если положительный) или расход (если отрицательный)?
Подводные камни какие: есть 100500 отчетов и 200500 скриптов, в которых а) наличествует своя логика подсчета текущего баланса, б) вычисляется, является ли договор должником, что в общем случае приводит к тому, что не происходит вызовов getBalance из BalanceUtils, а идет прямое обращение к таблице. Соответственно, добавляя эту новую сущность мы получаем некорректно работающие отчеты и скрипты. Это самое очевидное следствие, возможно есть что-то еще.
Есть ли объективные непреодолимые причины считать эти "дельты" отдельными сущностями баланса или же можно обойтись существующими (расход и платеж)?
Нет, это всё лишнее.
Цитата:
3) Соответственно в модуле Bill будут отдельные макросы для извлечения этих перерасчётов и подстановки в счета-фактуры-акты.
Ну, нам оно не требуется пока.
Вообще, за полгода использования схемы
пересчетов через расходы никто не просил расшифровать в детализации, что значит строка "Корректировка" в счете, за какие услуги и месяцы она посчитана - уже знают от менеджеров.
Цитата:
По поводу детализации - если документы уже выставлены, то детализация в них включена.
От перерасчётов она не изменится. Так что можно в базе менять её, наверное.
Я имею в виду данные в ЛК: логи сессий, звонков и т.п.
Главное для нас - это не переписывать contract_account. Пересчеты - уже как приятное(?) дополнение.
---
* По поводу целостности.
restart писал(а):
Просто напросто нарушается целостность системы
Долго думал - выходит, она и сейчас нарушена: если внести изменения задним числом, но не запускать пересчет, то будет несовпадение исходных данных и наработки. Просто при нашей схеме целостность будет нарушена и после пересчета, но взамен наработка не будет съезжать задним числом.
В любом случае нужно выбирать подход: либо мы жестко задаём процесс обработки данных без промежуточных состояний - любое изменение сразу влечёт полный пересчет вплоть до баланса. Либо ставить забор на каком-то уровне, через который последствия изменений не перелезут.