> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yume.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Уведомления о штрафах

> Как для свежих штрафов находится арендатор, покрывавший машину в момент нарушения, создаётся уведомление и автоматически уходит сообщение в WhatsApp с PDF протокола плюс внутреннее уведомление сотрудникам.

Полный перечень полей — в [глоссарии](/ru/logic/auto-penalties/notifications-glossary).

## Что делает эта часть

Когда во время синхронизации в систему попадают новые **Штрафы**, задача рассылки уведомлений о штрафах пытается для каждого свежего штрафа найти конкретного арендатора, который управлял машиной в момент нарушения, и предупредить его. Если такой арендатор найден, создаётся запись **Уведомление о штрафе**, а её появление автоматически запускает отправку сообщения клиенту в WhatsApp вместе с PDF протокола и постановку внутреннего уведомления для сотрудников компании.

<Info>
  Уведомляется не водитель-нарушитель из данных сервиса автоштрафов, а клиент-арендатор из заявки аренды вашей компании — тот, у кого автомобиль был в аренде на дату и время нарушения.
</Info>

## Когда это запускается

Рассылка не работает сама по себе, она стоит в конце цепочки синхронизации:

1. Синхронизация штрафов (по расписанию или по вебхуку) подтягивает и сохраняет штрафы.
2. После этого запускается дозагрузка PDF-протоколов.
3. Дозагрузка PDF в самом конце ставит задачу рассылки уведомлений о штрафах.

Ключевой момент, который передаётся по всей цепочке, — **момент запуска синхронизации** (время, зафиксированное в самом начале синхронизации, ещё до того как новые штрафы были записаны). Именно относительно этой точки отсчёта задача рассылки понимает, какие штрафы считать «свежими».

## Отбор свежих штрафов

Задача берёт не все штрафы подряд, а только те, что удовлетворяют одновременно двум условиям:

| Условие                                                        | Смысл                                                                                     |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Штраф создан в системе не раньше момента запуска синхронизации | отсекает всё, что уже было раньше — уведомляем только о том, что появилось в этом прогоне |
| Дата нарушения не старше 14 дней до момента запуска            | отсекает старые нарушения, даже если запись только что подтянулась                        |

**Нижняя граница даты нарушения** вычисляется как момент запуска синхронизации минус 14 дней. То есть окно нарушений — последние две недели.

Дополнительно каждый штраф проверяется на два обязательных реквизита: у него должен быть привязан **Автомобиль** и заполнена **Дата нарушения**. Если чего-то из этого нет — штраф пропускается.

<Note>
  Окно в 14 дней задано в коде жёстко и не настраивается из интерфейса. Нарушение, зафиксированное больше двух недель назад, уже не породит уведомление, даже если штраф по нему пришёл только сейчас.
</Note>

## Как находится получатель

Для каждого отобранного штрафа задача проходит по цепочке проверок. На любом шаге, где связь не находится, штраф молча пропускается — уведомление по нему не создаётся.

### Шаг 1. Привязка автомобиля к компании

По автомобилю штрафа ищется **Привязка авто компании к сервису автоштрафов**. Она отвечает на вопрос «чья это машина». Если привязки нет — значит, ни одна компания не заявляла этот автомобиль на слежение за штрафами, и штраф пропускается. Компания-арендодатель берётся из найденной привязки.

<Warning>
  Берётся первая найденная привязка по этому автомобилю. Если один и тот же автомобиль сервиса автоштрафов привязан сразу к нескольким компаниям, уведомление получит только одна из них — та, чья привязка окажется первой.
</Warning>

### Шаг 2. Проверка настройки WhatsApp у компании

Проверяется настройка компании, отвечающая за WhatsApp-рассылку. Если у компании эта настройка явно выключена — штраф пропускается, уведомление не создаётся. Если настройки нет вовсе, рассылка считается включённой (выключает её только явно установленное значение «выключено»).

### Шаг 3. Название компании для сообщения

Определяется, как компания подпишется в тексте сообщения:

* берётся значение настройки с названием компании;
* если это значение отсутствует или равно техническому плейсхолдеру-заглушке, вместо него подставляется название самой компании.

### Шаг 4. Автомобиль в автопарке компании

Дальше работа устанавливает контекст компании на конкретную компанию. По госномеру автомобиля штрафа ищется **Единица автопарка компании**. Если машины с таким номером в автопарке компании нет — штраф пропускается.

### Шаг 5. Покрывающая аренда

Из даты и времени нарушения собирается точный момент нарушения. По нему ищется аренда, которая этот момент покрывает: заявка не удалена, единица инвентаря — та самая машина, обмен по позиции отсутствует, а период аренды (от начала до конца) включает момент нарушения. Учитываются аренды в статусах «в аренде», «превышение срока», «завершена» и «должник».

Если подходящей аренды нет — штраф пропускается (например, машина в этот момент стояла свободной или была на обслуживании).

### Шаг 6. Клиент-арендатор

Из найденной аренды берётся клиент. Если клиент к заявке не привязан — штраф пропускается. Иначе это и есть получатель уведомления.

## Создание уведомления и защита от дублей

Когда все шаги пройдены, создаётся запись **Уведомление о штрафе** с телефоном клиента, ссылкой на штраф, компанией и дополнительными данными (имя клиента и название компании для текста сообщения).

Запись создаётся по принципу «создать, если ещё нет»: пара «телефон + штраф» уникальна. Поэтому повторный прогон рассылки по тому же штрафу и тому же телефону не создаст второе уведомление и не отправит клиенту дубль сообщения.

<Tip>
  Уникальность именно по паре «телефон + штраф». Если аренда одного и того же штрафа связана с разными телефонами, теоретически возможны отдельные уведомления на каждый телефон, но не повтор на один и тот же номер.
</Tip>

## Что происходит при создании уведомления

Само появление записи об уведомлении (а не редактирование существующей) автоматически запускает две вещи. Если сохранение — это обновление уже существующей записи, ничего не происходит. Также, если у штрафа почему-то не оказалось автомобиля, обработчик просто выходит.

### Сообщение в WhatsApp

Клиенту на его телефон отправляется двуязычное сообщение (казахский текст, затем русский) с обращением по имени. Отправка выполняется **фоновой задачей**, поставленной в очередь после того, как запись уведомления фактически сохранилась, — сохранение не ждёт ответа внешнего сервиса. В сообщении указываются:

* номер автомобиля;
* дата нарушения;
* сумма штрафа;
* орган, выявивший правонарушение;
* название компании-арендодателя.

Текст также предупреждает клиента, что сообщение отправлено ботом и отвечать в этот чат (присылать чеки, подтверждения оплаты) бесполезно — бот не отвечает. Вместе с текстом прикладывается PDF протокола штрафа.

<Note>
  Если WhatsApp-сервис недоступен, задача повторяется **до трёх раз с интервалом 5 минут**. Если протокол по штрафу ещё не скачан, сообщение не отправляется, а в журнал попадает предупреждение — молчаливой потери отправки нет.
</Note>

<Warning>
  В сообщении фигурирует сумма и орган именно по одному конкретному штрафу — это не сводная сумма всех нарушений клиента (хотя подпись к сумме в тексте сформулирована как «общая сумма штрафов»). По каждому штрафу клиент получает отдельное сообщение.
</Warning>

### Внутреннее уведомление для сотрудников

Параллельно ставится фоновая задача создания внутреннего уведомления по теме «получен штраф» с коротким текстом (номер машины, дата нарушения, сумма). Оно доставляется по трём каналам: веб, push и Telegram. К уведомлению прикладываются данные о штрафе, машине, сумме, дате, органе и клиенте, чтобы сотрудники видели контекст.

## Заготовки на самих штрафах

На модели **Штраф** есть два подключённых обработчика — на сохранение и на удаление штрафа. Сейчас это пустые заготовки: логики в них нет, они зарезервированы под будущие сценарии (например, уведомления при появлении штрафа или очистку данных при удалении). Вся текущая логика рассылки живёт в задаче рассылки и в обработчике создания уведомления, а не здесь.

## Особенности поведения

* Свежесть штрафа определяется по моменту создания записи не раньше точки отсчёта синхронизации; штрафы, обновлённые (а не созданные) в этом прогоне, под рассылку не попадают.
* Окно нарушений жёстко зафиксировано в 14 дней и не настраивается: нарушение старше двух недель уведомления не породит, даже если штраф пришёл только что.
* WhatsApp-рассылка считается включённой по умолчанию — она отключается только явно установленным значением «выключено»; отсутствие настройки отправку не блокирует.
* Автомобиль в автопарке компании ищется по совпадению госномера со штрафом; расхождение в формате или регистре номера приведёт к пропуску штрафа даже при наличии привязки.
* Защита от дублей построена на паре «телефон + штраф»: повторная отправка на тот же номер по тому же штрафу невозможна, а сообщение в WhatsApp уходит только при первичном создании записи уведомления.
* И сообщение в WhatsApp, и внутреннее уведомление сотрудникам ставятся в фоновую очередь; сообщение в WhatsApp дополнительно повторяется до трёх раз с интервалом 5 минут при недоступности сервиса.
* Покрывающей считается аренда в статусах «в аренде», «превышение срока», «завершена» и «должник» без обмена по позиции; свободная или сервисная машина покрывающей аренды не даёт.
* Обработчики сохранения и удаления штрафа подключены, но пусты — это заготовки без логики.

## Связанные страницы

<CardGroup cols={2}>
  <Card title="Глоссарий: Уведомления о штрафах" icon="book" href="/ru/logic/auto-penalties/notifications-glossary">
    Полный перечень полей уведомления о штрафе и связанных сущностей.
  </Card>

  <Card title="Сервис автоштрафов (штрафы и синхронизация авто)" icon="car-burst" href="/ru/logic/auto-penalties">
    Обзорная страница модуля интеграции с сервисом автоштрафов.
  </Card>

  <Card title="Модель данных" icon="database" href="/ru/logic/auto-penalties/models">
    Справочные и транзакционные модели сервиса автоштрафов: авто, водители, компании-нарушители, штрафы, привязки и логи синхронизации.
  </Card>

  <Card title="Синхронизация автомобилей" icon="arrows-rotate" href="/ru/logic/auto-penalties/car-sync">
    Выгрузка списка авто из сервиса автоштрафов, сверка активных и неактивных и активация или деактивация отдельной машины.
  </Card>

  <Card title="API компании: авто и штрафы" icon="list-check" href="/ru/logic/auto-penalties/company-api">
    Адреса арендодателя: привязка своих машин к сервису автоштрафов и просмотр штрафов только по ним с сопоставлением аренд и клиентов.
  </Card>
</CardGroup>
