Договор не стоит собирать прямой заменой «что пришло из формы, то вставили в Word». Сначала определите данные документа: сторона, реквизиты, предмет, сумма, сроки, подписанты и приложения. У каждого поля должны быть тип, обязательность, источник и правило отображения. После этого веб-форма создаёт проверенную запись, а отдельный генератор берёт её вместе с конкретной версией шаблона. Такая граница позволяет повторить выпуск документа и понять, откуда взялась каждая строка.
Автоматизация не подменяет юридическое согласование текста. Она уменьшает ошибки переноса данных и ускоряет выпуск утверждённого шаблона. Если пользователь может менять условия, которые влияют на обязательства сторон, эти варианты должны проходить отдельную бизнес-проверку, а не незаметно попадать в свободное текстовое поле.
Схема полей важнее красивой формы
| Поле | Хранить как | Проверка перед генерацией |
|---|---|---|
| название организации | строка и отдельное полное имя | длина, допустимые символы, не пусто |
| ИНН/регистрационный номер | строка | формат и контрольное правило страны |
| сумма | десятичное значение плюс валюта | диапазон, округление, единый источник |
| дата | ISO-дата | допустимый период и часовой пояс не участвует |
| адрес | структурированные части плюс отображаемая строка | обязательные компоненты |
| позиции приложения | массив строк | количество, цена, итог и единицы |
Не храните деньги как уже отформатированную строку «10 000,00 руб.»: её трудно пересчитать и сравнить. Отдельно храните числовое значение и валюту, а словесное и визуальное представление создавайте при генерации. Точно так же дата в базе должна быть однозначной, а формат «9 октября 2026 года» — свойством документа. Нормализация выполняется до сохранения, но исходный ввод можно оставить в аудите, если это нужно для разбора.
Шаблон получает только именованные значения
template_version: contract-v12
fields:
customer_full_name: "ООО Пример"
contract_date_iso: "2026-10-09"
amount_minor: 12500000
currency: "RUB"
signatory_basis: "Устав"
items:
- title: "Техническая поддержка"
quantity: 3
unit: "месяц"В DOCX используйте уникальные маркеры вроде ${customer_full_name}; PHPWord TemplateProcessor умеет заменять одиночные значения, изображения, блоки и клонировать строки таблицы. Не вставляйте готовый XML из формы и не рассчитывайте на визуально одинаковые пробелы: DOCX является пакетом OOXML, а редактор может разбить текст маркера на несколько runs. Шаблон проходит автоматический тест на список обязательных маркеров до публикации новой версии.
Необязательные разделы задаются правилами, а не пустыми словами
- пустой банковский реквизит либо блокирует выпуск, либо удаляет весь согласованный абзац;
- таблица приложения клонирует строку по числу позиций, а итоги считаются из тех же числовых данных;
- склонение имени, числа прописью и формат даты покрываются тестами на граничные значения;
- логотип и подпись берутся только из разрешённого хранилища, а не по URL из формы;
- пользовательский многострочный текст ограничивается по длине и не меняет стили документа;
- каждая версия шаблона неизменяема после первого выпущенного договора.
Если условие влияет на сам текст договора, лучше выбрать заранее согласованный вариант блока, чем склеивать предложение из фрагментов. В интерфейсе это выглядит как понятный выбор, а в данных сохраняется идентификатор варианта. Так юрист проверяет конечные формулировки один раз, а разработчик не становится автором договорного текста.
Генерация идёт через очередь и оставляет доказуемый результат
После отправки формы создайте snapshot входных данных, идентификатор шаблона и задачу генерации. Worker формирует файл во временном каталоге с непредсказуемым именем, проверяет отсутствие нераскрытых маркеров, сохраняет результат в закрытое хранилище и записывает hash. Повторный запуск с тем же request ID не должен создавать пять разных договоров; либо возвращается тот же artifact, либо явно создаётся новая редакция.
Не помещайте реквизиты и полный текст договора в обычный debug-лог. Для диагностики достаточно document ID, template version, перечня отсутствующих ключей, статуса конвертации и correlation ID. Доступ к готовому файлу выдаётся после проверки права на конкретный документ, а публичная ссылка не используется как механизм авторизации.
Приёмка читает текст и смотрит на страницы
- Сгенерировать документ с минимальными, типичными и максимально длинными допустимыми значениями.
- Проверить, что ни один маркер ${...} не остался в DOCX и итоговые суммы сходятся.
- Открыть DOCX в целевых редакторах и отдельно получить PDF тем же конвертером, что на сервере.
- Визуально проверить перенос таблиц, подписи, колонтитулы, нумерацию и последнюю страницу.
- Сверить сохранённые template version, input snapshot и hash с выданным файлом.
Для разработки подготовьте обезличенный утверждённый шаблон, словарь полей, три тестовых набора и правила доступа. Реальные паспортные данные, банковские реквизиты и подписи для отладки не нужны. Начните с одного вида договора и ручного подтверждения перед выдачей; автоматическую отправку клиенту включайте только после серии успешных контрольных генераций.