Обзор
Эта страница описывает, как залоги и штрафы прикрепляются к аренде и как они связаны с её жизненным циклом: кто их создаёт, что происходит при получении и возврате залога, как ручные и автоматические штрафы попадают в суммы аренды и позиций, и как устроено фоновое начисление штрафов за просрочку.Здесь собрано всё, что относится к аренде: модель залога и штрафа, их связка с заявкой и её статусами, фоновое начисление и формула авто-штрафа за просрочку. Денежная сторона — как платёж-операция попадает в «Оплачено», как считается долг, возвраты и переводы между счетами — описана в финансовом модуле: «Оплата: модель, знак и проверки» и «Переводы между счетами и возвраты».
Модель данных
Залог аренды
Залог всегда принадлежит одной аренде и хранит, что именно оставлено в залог и на какой стадии он находится.
Сумма платежей — это не поле в базе, а вычисляемая величина: система суммирует все платежи, привязанные к залогу, и подставляет её в ответ. По ней видно, насколько внесённые деньги покрывают заявленную сумму залога.
Тип залога и статус залога при создании и изменении обязательны. Если выбран денежный залог, но сумма не указана, запись не сохранится. Если выбран текстовый залог, сумма всегда сбрасывается в ноль — независимо от того, что прислал клиент.
Штраф аренды
Штраф может быть ручным (его добавляет сотрудник) или автоматическим (начисляется за просрочку). Он привязывается либо ко всей аренде, либо к конкретной позиции инвентаря.Где хранятся суммарные штрафы
Итоговые суммы штрафов хранятся прямо в заявке аренды и в позициях инвентаря — чтобы не пересчитывать их при каждом чтении. Штрафные поля аренды:
Штрафные поля позиции инвентаря — сумма штрафа позиции, её автоматическая и ручная части. Сумма штрафа позиции служит источником для пер-позиционного автоматического штрафа (см. ниже).
У поля «Авто-штрафы» единственный владелец — пересчёт сумм аренды. Он считает штраф по живой формуле просрочки, отдельно по каждой позиции, и уважает признак «штрафы отключены» (тогда поле обнуляется). Ни сохранение, ни удаление ручного штрафа это значение не меняют — они пересчитывают только «Ручные штрафы», а «Общая сумма штрафов» выводится как сумма двух частей. Поэтому добавление ручного штрафа больше не может «уронить» авто-штраф, а вместе с ним и итоговую сумму к оплате и долг.
Логика и побочные эффекты
Оформление и возврат залога
Залоги живут на своих адресах под аренды: список и создание, изменение и удаление, отдельное действие «возврат».- Создание. Аренда берётся из адреса запроса, автор проставляется из текущего пользователя. Для текстового залога сумма обнуляется. После сохранения запускается пересчёт сумм аренды, чтобы залог учёлся в общей картине по заявке.
- Изменение. Работает симметрично: текстовый залог снова обнуляет сумму, затем идёт тот же пересчёт сумм аренды.
- Удаление. После удаления также выполняется пересчёт сумм аренды.
- Возврат. Отдельное действие возвращает залог клиенту: оно создаёт встречные расходные операции на внесённые по залогу деньги, переводит залог в статус «возвращён», проставляет дату возврата текущим моментом и пересчитывает суммы аренды. Залог ищется одновременно по своему идентификатору и по аренде из адреса запроса, поэтому вернуть через одну аренду залог другой нельзя.
Что происходит с деньгами при возврате залога
Раньше возврат менял только статус и дату: касса и баланс счёта продолжали держать сумму залога, а «Оплачено» по аренде оставалось завышенным на приход, которого у компании уже нет. Теперь смена статуса и движение денег происходят в одной операции:- Считается остаток по залогу. Берутся все успешные операции, привязанные к этому залогу, и суммируются по каждой паре «вид оплаты + счёт». Возвращается именно остаток (приходы минус уже сделанные возвраты), а не номинал залога.
- Создаются встречные расходные операции. На каждый положительный остаток создаётся расходная операция с отметкой возврата — той же формы, что и ручной возврат оплаты. Деньги уходят с того счёта, на который приходили (счёт определяется видом оплаты).
- Залог помечается возвращённым. Проставляются статус «возвращён» и дата возврата, затем пересчитываются суммы аренды.
Действие идемпотентно: поскольку возвращается остаток, а не номинал, повторный вызов ничего не создаёт. Корректно отрабатывают и крайние случаи — залог без операций (текстовый или неоплаченный), операция в статусе ожидания оплаты, ранее сделанный частичный ручной возврат: все они доводят остаток до нуля и лишнего не создают.
Уведомления по этим операциям намеренно не отправляются: операции по залогам и операции с отрицательной суммой не шумят в мессенджеры — возврат залога это правило сохраняет.
Ручные штрафы и пересчёт полей аренды
Ручные штрафы создаются и редактируются сотрудником через адреса под аренды. Список и создание, а также удаление работают только с ручными штрафами — автоматические через этот интерфейс не видны и не редактируются. Аренда, тип и автор при этом только для чтения: тип всегда «ручной», автор берётся из текущего пользователя, аренда — из адреса. Каждое сохранение или удаление ручного штрафа автоматически пересчитывает штрафные поля аренды:- Ручные штрафы заявки суммируются заново.
- Авто-штрафы не пересчитываются и не затираются — их владелец пересчёт сумм аренды.
- Общая сумма штрафов выводится как сохранённые авто-штрафы плюс новая сумма ручных.
- Если сумма ручных штрафов совпала с прежней, запись в базу не делается вовсе (пустой пересчёт пропускается).
Для автоматических штрафов этот пересчёт по сохранению не выполняется вообще: авто-штрафы — это материализованный след того же начисления, которое считает формула просрочки, поэтому в сводные поля аренды они напрямую не входят и обновлять им нечего.
Ручной штраф можно оформить и на клиента, без привязки к аренде. Такой штраф в штрафные поля какой-либо аренды не попадает — обновлять просто нечего, и сохранение проходит штатно.
График разбивки штрафа
У ручного штрафа может быть график — набор дат с суммами, на которые штраф разбивается (строки графика оплат, помеченные как пользовательские). При создании и изменении штрафа система синхронизирует эти строки: удаляет исчезнувшие, добавляет новые, обновляет существующие.Если у штрафа задан непустой график, сумма по всем датам обязана в точности совпадать с суммой штрафа. Иначе сохранение отклоняется с ошибкой.
Автоматические штрафы по позициям инвентаря
Автоматические штрафы, начисленные на отдельные позиции, синхронизируются с суммами штрафов самих позиций отдельной фоновой задачей пересчёта. Задача берёт заявку и приводит пер-позиционные авто-штрафы в соответствие со штрафными полями позиций:- Если у позиции сумма штрафа стала нулевой — соответствующий авто-штраф по этой позиции удаляется.
- Если сумма изменилась (и не ноль) — авто-штраф обновляется.
- Если у позиции появился штраф, а записи ещё нет — авто-штраф создаётся.
Фоновое начисление штрафов за просрочку
Формула авто-штрафа за просрочку
Основной расчёт выполняется в центральном пересчёте по аренде — отдельно для каждой строки инвентаря. Штраф начисляется, только если позиция уже была выдана (есть фактическая выдача), это аренда (не продажа), и фактическое время возврата превысило плановое окончание больше, чем на буфер (грейс-период):- шаг начисления штрафа — из настройки аренды «Шаг начисления штрафа», а если не задан — 1 час;
- буфер (грейс-период) — по умолчанию 1 час;
- шаг округления суммы — по умолчанию 1;
- ОКРУГЛ_ШАГОВ — округление вверх, если включена настройка «штраф вперёд», иначе вниз. Округление вверх/вниз применяется только к числу просроченных шагов; внешнее приведение к целому округляет итог к ближайшему целому и от настройки «штраф вперёд» не зависит.
Расписание авто-штрафа
Для планирования периодических начислений используется отдельная запись-расписание, которая живёт в общей (глобальной) таблице, так как ссылается на компанию.
Расписание уникально по сочетанию компании, индекса и идентификатора аренды.
Как строится расписание
Расписания создаёт генератор расписаний штрафов, который вызывается при изменениях аренды. Он смотрит на позиции инвентаря аренды (кроме обменянных) и группирует их по дате окончания. Для каждой уникальной даты окончания создаётся своё расписание со своим индексом:- Дата старта начислений = дата окончания позиции.
- Шаг начисления берётся из настройки шага начисления штрафа в аренде.
- Активно = аренда находится в статусе «в аренде» или «просрочка» и не удалена. В остальных статусах расписание помечается неактивным.
Генератор попутно планирует и уведомления о приближении просрочки: для настроенных триггеров сообщений он создаёт разовые задачи-оповещения, привязанные к моменту «конец аренды минус запас времени».
Как начисляются штрафы
Периодическая фоновая задача обходит расписания, которым пора сработать, и начисляет по ним штрафы. Ключевые правила связки с жизненным циклом:- Обрабатываются только компании с активным подключением интеграции аренды. Если у компании нет действующего подключения, её расписания в этом цикле не трогаются.
- Расписание считается «пора», если оно активно и дата старта уже наступила, при этом выполнено хотя бы одно из условий: запусков ещё не было, с прошлого запуска прошёл хотя бы один шаг начисления, либо дата старта оказалась позже последнего запуска.
- Для каждой аренды из расписания:
- Если аренда удалена или её статус не «в аренде» и не «просрочка» — расписание по этой аренде удаляется, начисление не производится. Так завершённые, отменённые и забронированные аренды автоматически перестают штрафоваться.
- Иначе выполняется начисление: пересчёт сумм аренды (который и обновляет штрафные поля), а для просроченных аренд дополнительно ставится уведомление «Аренда просрочена» — оно уходит сотрудникам, работавшим с этой арендой, и её создателю.
- После обработки у обработанных за цикл расписаний обновляется отметка последнего запуска.
Как это используется
- Сотрудник фиксирует залог при выдаче (текстом или суммой), а при возврате инвентаря отмечает залог возвращённым — обе операции сразу отражаются в суммах аренды. Возврат денежного залога при этом сам снимает деньги со счёта и уменьшает «Оплачено» по аренде, поэтому руками встречный возврат оформлять не нужно.
- Ручные штрафы сотрудник добавляет вручную с причиной и, при необходимости, графиком разбивки; они мгновенно попадают в поле ручных штрафов аренды и не влияют на посчитанный авто-штраф.
- Автоматические штрафы за просрочку начисляются сами, пока аренда остаётся в статусе «в аренде» или «просрочка»; как только она завершается, отменяется или удаляется, начисление прекращается автоматически.
- Итоговые суммы (общая сумма штрафов, авто и ручные отдельно) всегда доступны прямо в заявке, а по позициям — в их штрафных полях, без пересчёта на лету.
Особенности поведения
- Автоматический пересчёт штрафных полей аренды при сохранении/удалении штрафа срабатывает только для ручных штрафов; для автоматических он завершается сразу и ничего не пересчитывает.
- Поле авто-штрафов аренды пишет только пересчёт сумм аренды — по живой формуле просрочки и по всем позициям; сохранение или удаление ручного штрафа его не затрагивает.
- Ручной штраф, оформленный на клиента без привязки к аренде, сохраняется штатно и штрафные поля какой-либо аренды не меняет.
- Текстовый залог всегда принудительно обнуляет сумму при создании и изменении, даже если сумма была передана.
- Пропуск записи при пересчёте штрафных полей сравнивает только сумму ручных штрафов; общая сумма отдельно в условии не участвует, но пересчитывается вместе с ней.
- Возврат залога создаёт встречные расходные операции на остаток по залогу, поэтому повторный возврат ничего не создаёт, а по залогу без операций возврат просто меняет статус.
- Операции по возврату залога не порождают уведомлений — это то же правило, по которому не шумят операции по залогам и операции с отрицательной суммой.
- Условие срабатывания расписания включает три альтернативы: запусков ещё не было, с прошлого запуска прошёл шаг начисления, либо дата старта позже последнего запуска.
- Если у аренды нет позиций с датой окончания, удаление лишних расписаний внутри цикла не выполняется, так как оно вложено в перебор найденных дат.
- График штрафа валиден только если сумма по всем датам в точности равна сумме штрафа; проверка применяется только к непустому списку дат.
- Фоновое начисление за один цикл обрабатывает не более 100 расписаний; при превышении лишние переносятся на следующий цикл и пишется предупреждение в лог.
- Штрафы начисляются только для компаний с активным подключением интеграции аренды; без действующего подключения расписания компании в цикле не обрабатываются.
- При обработке аренды, которая удалена или вышла из статусов «в аренде»/«просрочка», расписание авто-штрафа по этой аренде удаляется, что автоматически прекращает начисления.
- Ограничение базы данных требует заполненности хотя бы клиента либо аренды у штрафа.
- Адреса ручных штрафов работают только со штрафами типа «ручной»; автоматические штрафы через них не отображаются и не редактируются.
Связанные страницы
Глоссарий: Депозиты и штрафы
Полный перечень полей залогов, штрафов и расписаний авто-штрафа.
Аренда: заявки и жизненный цикл
Обзорный раздел обо всём модуле аренды и его страницах.
Аренда и статусы
Ядро заявки, автомат статусов и статус оплаты, а также создание, редактирование и архивация заявок.
Выдача и приёмка
Действия по аренде — бронирование, сборка, выдача, приёмка, отмена — и отмена действия с восстановлением статуса.
Позиции инвентаря и обмен
Строки инвентаря аренды и продажи, их тарифы и периоды, массовые операции и обмен позиций внутри заявки.
Услуги и доставка
Услуги в составе аренды и доставки с привязкой к действиям выдачи и приёмки.
Пересчёт сумм и цен
Движок пересчёта итогов: цены позиций и услуг, скидки, налоги, продление и суммарные поля заявки.
График оплат, паузы и рабочие дни
График платежей, автосписание, паузы аренды и рабочие/выходные дни, влияющие на длительность и суммы.
Уведомления, бонусы и воронка
Реакции на смену статуса: уведомления, бонусы, реферальные выплаты и продвижение по воронке продаж.