> ## 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.

# API компании: авто и штрафы

> Публичный API компании поверх сервиса автоштрафов: привязка авто с проверкой формата номера и техпаспорта, ограниченный машинами компании список штрафов с фильтрами и сопоставлением аренды и клиента по времени, агрегаты, кастомные статусы, ручное обновление с ограничением по частоте и приёмник вебхука.

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

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

Это публичный API компании (для веб-кабинета и мобильных клиентов) поверх интеграции с сервисом автоштрафов. Он решает три задачи:

1. **Привязка автомобилей компании к сервису автоштрафов** — компания выбирает свои единицы инвентаря, и по ним включается синхронизация штрафов.
2. **Просмотр штрафов**, ограниченный только машинами этой компании, с богатой фильтрацией, сопоставлением штрафа с арендой и клиентом, агрегатами и постраничным списком.
3. **Ручное обновление** штрафов с защитой от частых запросов и **приёмник вебхука** от сервиса автоштрафов.

Все ручки списков и привязок работают строго в рамках текущей компании: выборка всегда фильтруется по компании из контекста запроса.

<Info>
  Почти все адреса требуют авторизованного пользователя. Единственное исключение — приёмник вебхука: он открыт для внешнего сервиса и защищён отдельной аутентификацией по API-ключу, а не пользовательской сессией.
</Info>

## Привязка авто компании

### Список и создание привязки

Список привязок отдаётся **без постраничной разбивки** — сразу все привязки текущей компании. Для каждой привязки в ответ подмешивается связанная единица инвентаря: система заранее строит карту «ID единицы инвентаря → карточка инвентаря» по всем автомобилям инвентаря и берёт из неё нужную запись по полю «ID единицы инвентаря» привязки.

При создании привязки в запросе передаётся только **ID единицы инвентаря** (это идентификатор автомобиля в инвентаре компании). Остальное система достраивает сама.

### Что происходит при создании привязки

Порядок шагов строго такой:

1. **Проверка на дубль.** Если для этой компании уже есть привязка с таким же ID единицы инвентаря — возвращается ошибка «Этот автомобиль уже привязан к данному клиенту».
2. **Поиск единицы инвентаря.** По переданному ID ищется автомобиль в инвентаре. Если не найден — ошибка «Автомобиль не найден.».
3. **Проверка формата госномера.** Если у автомобиля заполнен номер, он должен соответствовать одному из двух шаблонов: либо *3 цифры + 2–3 буквы + 2 цифры*, либо *1 буква + 6 цифр*. Иначе — ошибка о неверном формате номера.
4. **Проверка формата техпаспорта.** Если техпаспорт заполнен, он должен быть в формате *2 буквы + 8 цифр*. Иначе — ошибка о неверном формате техпаспорта.
5. **Поиск или создание автомобиля в сервисе автоштрафов.** Система ищет уже известный ей автомобиль сервиса автоштрафов по паре «номер + техпаспорт». Если такого нет — обращается к внешнему сервису автоштрафов: сначала спрашивает, есть ли там автомобиль; если нет — просит его создать. При ошибке от внешнего сервиса возвращается «Не удалось создать автомобиль. Попробуйте ещё раз.». По полученным данным создаётся или обновляется запись автомобиля сервиса автоштрафов (заполняются ID в сервисе автоштрафов, дата активации и признак активности).
6. **Сохранение привязки** с проставленной компанией и найденным/созданным автомобилем сервиса автоштрафов.

<Warning>
  Шаг создания привязки делает синхронный внешний вызов к сервису автоштрафов прямо во время запроса. Если внешний сервис недоступен или отвечает с ошибкой, привязка не создастся, и пользователь получит ошибку.
</Warning>

### Просмотр и удаление одной привязки

Отдельная привязка (по её идентификатору) доступна только в рамках текущей компании: можно посмотреть её карточку (вместе с подмешанной единицей инвентаря) или удалить.

## Просмотр штрафов

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

### Как формируется выборка штрафов

1. Строится карта «госномер автомобиля → ID единицы инвентаря» по всем привязкам текущей компании.
2. Штрафы ограничиваются только теми, чей госномер попадает в эту карту — то есть только по машинам компании.
3. Для каждого штрафа вычисляется единое **«дата и время нарушения»** — сложением даты нарушения и времени нарушения (нужно для сопоставления с арендами).
4. Собираются релевантные аренды по этим машинам (все, кроме отменённых), чтобы затем сопоставить штраф с арендой и клиентом.

Аренды для сопоставления берутся с такими условиями: аренда не удалена, у единицы инвентаря есть автомобиль, это не запись обмена, и статус аренды **не «Отменена»**. Аренды сортируются по статусу — при совпадении по времени в приоритете более «поздние» по статусу.

### Фильтры выборки

Часть фильтров применяется на уровне общей выборки (в самой логике представления), часть — в наборе фильтров штрафов.

| Фильтр                                | Как работает                                                                                                                               |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| По единице инвентаря                  | Оставляет штрафы только по указанной единице инвентаря (через её автомобиль и привязку компании). Если такой единицы нет — выборка пустая. |
| По точке проката                      | Оставляет штрафы по всем машинам указанной точки проката.                                                                                  |
| По аренде / По клиенту                | Оставляет штрафы, попавшие во **временное окно** соответствующих аренд, и только по машинам этих аренд (см. ниже).                         |
| Тип штрафа                            | «Дорожное нарушение (с фото)» — есть хотя бы одно фото нарушения; «Прочее (без фото)» — фото нет.                                          |
| С водителем                           | Флаг: истина — только штрафы, у которых есть водитель; ложь — только без водителя.                                                         |
| Дата нарушения (от/до), Сумма (от/до) | Диапазоны «от» и «до».                                                                                                                     |
| Оплачен, Просмотрен                   | Флаги.                                                                                                                                     |
| Кастомный статус                      | Точное совпадение, вхождение в список, либо «без статуса».                                                                                 |

Дополнительно работает **поиск по тексту** (номер протокола, описание нарушения, адрес нарушения, госномер и техпаспорт автомобиля) и **сортировка** (по дате нарушения, сумме, дате создания, номеру протокола). По умолчанию список отсортирован по дате нарушения и дате создания в обратном порядке (сначала свежие).

<Note>
  Фильтры «по единице инвентаря», «по клиенту», «по аренде» и «по точке проката» в самом наборе фильтров ничего не делают — они объявлены как параметры, но фактическая фильтрация по ним выполняется в логике представления. Это сделано, чтобы параметры отображались в документации и валидировались как числа.
</Note>

### Сопоставление штрафа с арендой и клиентом по времени

Ключевая идея — привязать штраф к конкретной аренде и клиенту по **моменту нарушения**.

При фильтрации по аренде или клиенту система берёт временное окно каждой подходящей аренды: начало — время начала аренды, конец — фактическое время завершения, а если его нет — плановое время окончания. Штраф остаётся в выборке, только если дата нарушения попадает в одно из таких окон.

В карточке каждого штрафа отдельно вычисляются:

* **Аренда** — первая аренда этой машины, чьё окно (от начала до конца аренды) содержит момент нарушения. В ответ идут идентификатор и статус аренды.
* **Клиент** — клиент той же найденной аренды (идентификатор, имя, телефон). Если у аренды нет клиента — поле пустое.

Момент нарушения для этого сопоставления собирается из даты и времени нарушения и при необходимости приводится к таймзоне.

<Warning>
  Сопоставление всегда «best-effort»: если ни одна аренда не покрывает момент нарушения, поля аренды и клиента будут пустыми — это нормальная ситуация, а не ошибка.
</Warning>

### Три представления над одной выборкой

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

### Карточка и обновление штрафа

Отдельный штраф доступен для просмотра и **частичного обновления**. Большинство полей штрафа — только для чтения (они приходят из сервиса автоштрафов): реквизиты, суммы, документы, связи с автомобилем/водителем/компанией. Редактировать можно прикладные поля — признак «Просмотрен» и кастомный статус.

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

<Note>
  Кастомный статус, который можно присвоить штрафу, выбирается **только из статусов своей компании и общих** статусов — ровно из того набора, который отдаёт список статусов. Присвоить своему штрафу приватный статус другой компании невозможно.
</Note>

## Кастомные статусы штрафов

Компания может завести свои статусы штрафов (название и цвет в HEX, по умолчанию белый). При создании статуса он автоматически привязывается к текущей компании.

Здесь важно различать две операции:

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

## Ручное обновление штрафов

Кнопка «обновить штрафы» запускает подтягивание штрафов из сервиса автоштрафов по всем автомобилям компании. Действие защищено ограничением по частоте.

### Как работает ограничение по частоте

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

<Warning>
  Метка времени последнего запуска записывается **до** обращения к внешнему сервису. Поэтому даже если внешний вызов завершился ошибкой, повторный запуск будет заблокирован на 3 часа.
</Warning>

## Приёмник вебхука от сервиса автоштрафов

Отдельный адрес принимает уведомления о штрафах напрямую от сервиса автоштрафов. Он защищён аутентификацией по API-ключу (не пользовательской сессией). Полученные данные сразу передаются в обработку штрафа, и в ответ отправляется подтверждение о приёме.

## Как это используется

Типичный сценарий работы компании:

1. Компания привязывает свои автомобили (по ID единиц инвентаря) — при этом каждая машина заводится/находится в сервисе автоштрафов.
2. Штрафы приезжают двумя путями: автоматически через вебхук от сервиса автоштрафов и по кнопке ручного обновления (не чаще раза в 3 часа).
3. В кабинете компания смотрит штрафы только по своим машинам, фильтрует их (по клиенту, аренде, точке, типу, датам, суммам, статусу), видит сводку и сопоставление каждого штрафа с арендой и клиентом.
4. Прикладные поля штрафа (просмотрен, кастомный статус) редактируются вручную — статус выбирается из своих и общих статусов.

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

Прочее, что стоит держать в голове:

* **Неудачное ручное обновление всё равно блокирует повтор.** Метка времени последнего запуска пишется до вызова внешнего сервиса, поэтому даже упавший вызов закрывает окно на 3 часа.
* **Приёмник вебхука обрабатывает данные синхронно** прямо в запросе (массовое создание и обновление записей), поэтому большая партия задерживает ответ внешнему сервису. Скачивание файлов протоколов при этом вынесено в отдельную фоновую задачу и на время ответа не влияет.
* **Два разных временных окна аренды.** Окно, по которому штрафы отбираются при фильтрации (начало и фактическое или плановое завершение позиции аренды), не совпадает с окном, по которому аренда и клиент подставляются в карточку штрафа (там берутся плановые время начала и окончания самой заявки). На граничных случаях набор совпавших штрафов и подставленная в карточку аренда могут расходиться.
* **Тип штрафа — вычисляемый признак.** Он определяется по наличию фотографий нарушения (с фото — дорожное нарушение, без фото — прочее) и в самой записи штрафа не хранится.
* **Проверка формата номера и техпаспорта при привязке выполняется, только если значение задано.** Если у автомобиля инвентаря номер или техпаспорт не заполнен, соответствующая проверка формата пропускается.
* **Список привязок отдаётся целиком без постраничной разбивки** — при большом парке это может быть тяжёлым ответом.
* **Общий статус штрафа доступен на выбор, но не на правку.** Компания может присвоить общий статус своему штрафу, однако переименовать, перекрасить или удалить его может только владелец платформы.

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

<CardGroup cols={2}>
  <Card title="Глоссарий: API компании: авто и штрафы" icon="book" href="/ru/logic/auto-penalties/company-api-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="Уведомления о штрафах" icon="whatsapp" href="/ru/logic/auto-penalties/notifications">
    Сопоставление штрафа с активной арендой и отправка клиенту двуязычного сообщения в WhatsApp с документом.
  </Card>
</CardGroup>
