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

# Генерация документа и PDF

> Подстановка данных заявки/клиента в шаблон, построчные таблицы, рендер HTML в PDF, QR-штамп и страница-подтверждение подписания.

Этот раздел описывает процесс, а не отдельные модели — сущности, которые в нём участвуют (Документ, Шаблон документа), описаны в [«Документы: карточки, файлы и статусы»](/ru/logic/documents/crud-glossary) и [«Шаблоны документов»](/ru/logic/documents/templates-glossary); каталог плейсхолдеров — в [«Плейсхолдеры шаблонов»](/ru/logic/documents/placeholders).

## Логика

Любой документ в системе рано или поздно превращается в PDF-файл — сгенерированный из шаблона и заполненный данными заявки/клиента, загруженный менеджером (Word, Excel и т.п.), либо кассовый чек. Во всех случаях превращение выполняет один и тот же внешний сервис конвертации (движок на базе Chromium и утилиты работы с PDF). Модуль отвечает за то, что передать в этот сервис и как собрать результат: подставить данные в шаблон, отрисовать PDF, поставить QR-штамп с UUID документа и, при необходимости, приложить страницу-подтверждение с историей подписания.

### Подстановка данных в шаблон (сборка HTML документа)

Когда документ создаётся или запрашивается пересборка контента, система берёт шаблон и связанную заявку на аренду и строит готовый HTML-текст, заменяя плейсхолдеры реальными значениями.

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

**Ключевые формулы (плейсхолдеры итоговых сумм заявки):**

| Показатель                    | Как считается                                                                                                                                  |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Итоговое число дней аренды    | плановая длительность минус дни, отмеченные выходными в графике заявки                                                                         |
| Цена аренды за день           | цена со скидкой, делённая на итоговое число дней (не менее одного — деление на ноль исключено)                                                 |
| Стоимость инвентаря по заявке | без фильтра — готовая сумма заявки целиком; с фильтром — пересчитывается заново только по отфильтрованным позициям                             |
| Сумма депозита                | запрашивается из базы только если в шаблоне реально присутствует плейсхолдер суммы депозита                                                    |
| «Цена доставки по заявке»     | сумма стоимости со скидкой всех типизированных доп. услуг заявки (кроме типа «не выбрано») — фактически не ограничена только услугами доставки |

<Info>
  Версия «прописью» любой денежной суммы озвучивает её в валюте компании — из той же настройки, что и числовая версия. Для валют без словесной формы прописью выводится целая часть плюс символ валюты, копейки — цифрами; незаполненная сумма читается как ноль. Подробности — в [«Плейсхолдерах шаблонов»](/ru/logic/documents/placeholders).
</Info>

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

### Построчные таблицы документа

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

<Info>
  Во всех шести таблицах неизвестный (или ещё не поддерживаемый) плейсхолдер внутри строки просто остаётся текстом «как есть» — сборка документа не прерывается, а сам факт записывается в журнал, чтобы опечатку в шаблоне можно было найти. Раньше в таблицах услуг, штрафов и доставок такой плейсхолдер завершал сборку документа ошибкой.
</Info>

### Рендер HTML в PDF

Готовый HTML оборачивается в общий шаблон печати и отправляется во внешний сервис как задание «HTML в PDF». Настройки страницы берутся из шаблона документа, только если он вообще выбран — если нет, эти параметры не передаются, и размер страницы определяется настройками сервиса по умолчанию. Результат сохраняется как файл типа «Оригинал» — «чистый» PDF без отметок о подписании.

### QR-штамп и страница-подтверждение подписания

Помимо «чистого» оригинала, для каждого документа готовится «Подписанный файл» — тот же контент, но с QR-кодом и UUID документа в подвале каждой страницы, а также (при выполнении условий) с приложенной страницей-подтверждением подписания.

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

**Страница-подтверждение подписания** строится отдельной операцией и добавляется через слияние PDF-файлов. На ней перечисляются: сторона компании и клиента(ов), результат проверки электронной подписи (сертификаты, время подписания) и история подтверждения по SMS.

<Warning>
  Страница-подтверждение формируется только если по документу уже есть файл с ЭЦП (подписывали через ЕГОВ), сторона компании тоже имеет запрос на подписание, а хотя бы одна подпись клиента — в статусе «Подписан». Если никто не подписывал через ЭЦП/ЕГОВ, страница-подтверждение не создаётся вообще.
</Warning>

### Когда файлы пересобираются

Отдельная фоновая задача поддерживает актуальность производных файлов документа и запускается при создании документа, при добавлении/изменении подписанта и при завершении подписания по SMS-коду.

<Warning>
  После того как хотя бы одна подпись документа получила статус «Подписан», «Оригинал» перестаёт автоматически перегенерироваться из текущего содержимого документа — это защищает текст уже подписанного документа от подмены задним числом. «Подписанный файл» и «Слой для подписи» продолжают пересобираться и после начала подписания.
</Warning>

### Конвертация загруженных файлов и генерация чеков

Если менеджер загружает документ не в формате PDF (Word, Excel и т.п.), система по расширению имени файла определяет, что конвертация нужна, и прогоняет файл через отдельную операцию конвертации того же внешнего сервиса — исходный файл не хранится отдельно.

<Info>
  В модуле подготовлена (и полностью реализована) отдельная функция генерации кассового чека, но по всему проекту ни один сценарий её сейчас не использует.
</Info>

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

* Плейсхолдер «цена доставки по заявке» на самом деле суммирует стоимость всех типизированных доп. услуг заявки, включая, например, услуги мастерской, а не только услуги доставки.
* После подстановки всех значений из готового HTML убираются переносы строк, а также любое буквальное вхождение служебного слова-маркера — если оно случайно встретится в тексте шаблона, оно молча исчезнет из документа.
* Расширенный синтаксис плейсхолдера с уточняющим суффиксом в квадратных скобках распознаётся при поиске строки для клонирования, но логика подстановки значения по суффиксу нигде не реализована.
* Определение, нужно ли конвертировать загруженный файл в PDF, делается по расширению имени файла без анализа реального содержимого.
* В модуле есть более старая функция построения PDF с жёстко заданным форматом страницы (близким к A4); она нигде не используется — реальный процесс использует более новую функцию с настройками страницы из шаблона.
* Для загруженных документов QR-штамп накладывается отдельной операцией поверх уже готового PDF, тогда как для сгенерированных документов подвал с QR-кодом встраивается сразу при рендере HTML в PDF.
