Система документов и генерация
Как в системе работают загруженные файлы, шаблоны документов и генерация готовых артефактов для клиентов.
Два типа документов в системе
1. Файлы (Files)
Загруженные пользователем артефакты — ТЗ, чертежи, фотографии, спецификации, которые нужны для работы.
2. Документы (Documents)
Сгенерированные системой документы — счета, договоры, акты, отчеты, которые создаются на основе данных проекта и шаблонов.
Часть 1: Файлы (Files)
Что такое файл в системе
Файл — это любой загруженный в систему файл, привязанный к сущности проекта (или задаче, или чату).
Структура файла
File:
- ID: 123
- EntityType: "project" (к какой сущности привязан)
- EntityID: 456 (ID этой сущности)
- FolderID: 789 (в какую папку)
- Bucket: "files" (где хранится)
- Key: "project-456/2026-04-20/specifications.pdf" (путь в хранилище)
- OriginalName: "specifications.pdf" (оригинальное имя)
- MimeType: "application/pdf" (тип)
- SizeBytes: 1234567 (размер в байтах)
- Category: "document" (категория)
- UploadedBy: 789 (кто загрузил)
- CreatedAt: 2026-04-20 12:00:00 (когда загружено)
- DeletedAt: null (если удален)Категории файлов
| Категория | Примеры | Назначение |
|---|---|---|
| general | Любые вложения, информационные материалы | Общие файлы проекта |
| document | ТЗ, требования, регламенты | Служебная документация |
| image | Фотографии, схемы, чертежи, макеты | Визуальные материалы |
| contract | Договоры, контракты, соглашения | Юридические документы |
| invoice | Счета, накладные, акты, отчеты | Финансовые документы |
| other | Все остальное | Разное |
Где находятся файлы
Хранилище:
- По умолчанию: локально в
tmp/files - Для масштабирования: S3-совместимое хранилище (AWS S3, MinIO и т.п.)
- Максимальный размер загрузки: 1 GB
- Исполняемые файлы и исполняемые MIME-типы не принимаются
Структура хранилища:
files/
project-456/
2026-04-01/
specifications.pdf
floor-plan.png
2026-04-20/
notes.mdПапки в проекте
При создании проекта триггер create_default_project_folders заводит стандартный набор (миграция 0138, по ТЗ «Создание проекта»):
type | Папка | Что хранится |
|---|---|---|
tz | ТЗ | Техническое задание и исходные материалы |
proposals | Коммерческие предложения | КП и сметы для клиента |
contracts | Договоры | Договоры, допсоглашения, акты |
photo | Фотоотчёты | Фото монтажа, процесса и демонтажа |
reports | Отчётность | Отчёты по проекту |
other | Прочее | Всё остальное |
type стабилен и уникален в проекте, имя можно переименовать. Существующим проектам недостающие папки добавлены миграцией; старые системные имена TZ и Фото переименованы в ТЗ и Фотоотчёты, ручные имена не тронуты.
| Сценарий | Endpoint |
|---|---|
| Папки проекта | GET /api/v1/projects/:id/folders — конверт {items, meta}, дерево через children |
| Файлы папки | GET /api/v1/folders/:id/files |
| Загрузить в папку | POST /api/v1/folders/:id/files |
| Все файлы проекта | GET /api/v1/projects/:id/files (у каждого файла folder_id или null) |
Как работает с файлами
Загрузка
- Открыть проект
- Перейти в раздел "Files"
- Нажать "Upload"
- Выбрать файл(ы)
- Выбрать категорию
- Нажать "Upload" — файл сохранен
Организация
- Можно создавать папки
- Перемещать файлы между папками
- Переименовывать файлы
- Удалять файлы (soft delete, т.е. помечаются как удаленные)
Поиск
- Фильтр по категориям
- Фильтр по дате загрузки
- Фильтр по пользователю (кто загрузил)
- Поиск по имени
Ограничения
- Максимальный размер файла: опционально ограничивается (например, 100 МБ)
- Форматы: опционально ограничиваются (например, только PDF, DOC, PNG)
Где используются файлы
В проекте
- В разделе "Files" проекта — видны все файлы, привязанные к проекту
В задачах
- Файл может быть привязан к конкретной задаче
- Помогает исполнителю понять требования
В чатах
- В сообщениях чата могут быть прикреплены файлы
- Файлы загружаются в entity type
chat, а затем прикладываются к сообщению черезfile_ids - Команда обсуждает напрямую в общих чатах или в чате задачи
При генерации документов
- Система может ссылаться на загруженные файлы (например, вставить чертеж в счет)
Часть 2: Документы (Documents)
Что такое документ в системе
Документ — это готовый артефакт, обычно сгенерированный на основе:
- Данных проекта
- Шаблона
- Заданных параметров
Примеры:
- Счет за выполненные работы
- Договор с клиентом
- Акт выполненных работ
- Отчет о проделанной работе
Документы vs Файлы
| Параметр | Файл | Документ |
|---|---|---|
| Источник | Загружен пользователем | Сгенерирован системой |
| Содержание | Исходные данные (ТЗ, чертежи) | Готовый артефакт (счет, договор) |
| Обновление | Вручную загружается новая версия | Пересчитывается при изменении данных проекта |
| Назначение | Справочный материал для работы | Отправка клиенту, архивирование |
Типы документов
Invoice (Счет)
Когда создается: Когда нужно выставить счет клиенту.
Что включает:
- Дату и номер счета
- Реквизиты поставщика (ваша компания)
- Реквизиты клиента: сначала карточка Company, затем primary-набор из Requisites, если он есть
- Список работ/услуг с ценами
- Список материалов/оборудования
- Итоговую сумму
- Условия оплаты
Источник данных:
- Project: название, компания проекта
- Requisites: internal-реквизиты поставщика и primary-реквизиты компании-клиента
- Team: состав и ставки
- Finance: все Cost Items
- Tasks: список выполненных работ
Contract (Договор)
Когда создается: При инициации работ с клиентом.
Что включает:
- Реквизиты сторон
- Описание услуг/работ
- Стоимость и условия оплаты
- Сроки выполнения
- Ответственность сторон
- Подписи
Источник данных:
- Project: название, сроки
- Requisites: реквизиты исполнителя и заказчика
- Finance: плановая стоимость
- Custom fields: условия, ответственность
Act (Акт выполненных работ)
Когда создается: При завершении проекта или этапа.
Что включает:
- Дату акта
- Описание выполненных работ
- Подтверждение качества
- Подписи сторон
Источник данных:
- Project: название, сроки
- Requisites: реквизиты исполнителя и заказчика
- Tasks: список закрытых задач
- Team: кто выполнял
Addendum (Дополнительное соглашение)
Когда создаётся: Когда после подписания договора нужно зафиксировать изменение сроков, состава работ, стоимости или других условий.
- Создаётся только для договора того же проекта через
POST /api/v1/projects/:id/documents/addendum. - В запросе обязательны
contract_idи непустойdata.changes;data.new_totalиnotesопциональны. - Связь с договором хранится в
documents.parent_document_idи возвращается какparent_document_idв единомsnake_caseDTO. - PDF содержит номер и дату исходного договора, нумерованный перечень изменений, опциональную новую стоимость, реквизиты и подписи сторон.
- Удаление договора с существующими дополнительными соглашениями ограничено внешним ключом
ON DELETE RESTRICT.
Report (Отчет)
Когда создается: По запросу для анализа хода работ.
Что включает:
- Статус проекта
- Выполненные задачи (%)
- Израсходованный бюджет
- Ожидаемые сроки завершения
- Проблемы и риски
Источник данных:
- Project: статус, сроки
- Tasks: прогресс, статусы
- Finance: затраты
- Team: статус команды
Шаблоны документов
Смета, счёт, акт, договор и доп. соглашение собираются из шаблона Word — стандартного или загруженного на экране «Администрирование → Шаблоны документов» (общего или для одного нашего юрлица). Документ хранится в Word и PDF; PDF делает конвертер Gotenberg. Синтаксис полей, выбор шаблона и настройка — в Шаблоны документов в Word.
Как было до шаблонов Word
В текущей реализации дефолтные HTML-шаблоны создаются миграцией для типов invoice, estimate, act, contract с locale ru. Структурированный PDF-рендер используется как основной путь для сметы, standalone-счета, акта и договора, а HTML-шаблоны остаются доступными для проектного счета и fallback/template-flow.
Проектный счёт без явно переданного template_id также генерируется структурированным fpdf-рендерером. Он выводит позиции, НДС, сумму прописью, назначение платежа и блок подписей. Явно выбранный HTML-шаблон сохраняет прежний fallback-flow.
Для сметы поддерживаются два режима детализации:
detail: "categories"— агрегированные категории бюджета (режим по умолчанию);detail: "items"— исходные статьи затрат и налоговые строки.
Акт не дублирует итоговую строку и показывает НДС. В договоре реквизиты заказчика дополняются основным банковским счётом компании, а формулировка «в лице …» и блок подписей используют director_name и director_title обеих сторон, если эти поля заполнены.
Список сгенерированных документов доступен через GET /api/v1/documents с фильтрами project_id, type, status, limit, offset; фильтр type принимает также addendum. Для пользователей без глобального доступа project_id обязателен и проверяется доступ к проекту. Ответы создания и изменения статуса используют единый snake_case DTO, включая parent_document_id.
Правила формирования и статусов
- Продавец (исполнитель) — набор «Моей компании», выбранный в проекте как плательщик (
payer_requisite_id); если он не выбран или удалён — основной набор. Реквизиты попадают в PDF иpayloadдокумента на момент формирования, id набора — вdocuments.seller_requisite_id. Реквизитов нашей компании нет вовсе — документ не выпускается:400 documents_seller_requisites_required(«Заполните их в разделе „Моя компания“»). - НДС документа — по продавцу: переопределение проекта, иначе режим и ставка набора-продавца (плательщик, иначе основной набор), иначе без НДС. Счёт своими строками (и счёт компании без проекта) считает цены окончательными: НДС «в том числе» по ставке продавца, продавец без НДС — «НДС не облагается».
- Закрытый проект (
status = closed): документы не формируются и не меняют статус —409 documents_project_closed. Проверка идёт до выдачи номера и до сохранения, поэтому отказ финансов не оставляет «полусохранённый» счёт. - Счёт на ноль не выставляется:
400 documents_invoice_total_must_be_positive(проектный счёт — итог сметы; счёт компании без проекта — сумма позиций). Номер при отказе не расходуется. - Документ выпускается сразу выпущенным (
issued) — с номером и PDF; черновик (draft) без номера бывает только у счёта по проекту (см. «Счёт по проекту»). Черновик не выпускается сменой статуса —PATCH …/status {"status":"issued"}выпускает его какPOST /documents/:id/issue, а отмена черновика отклоняется (409 documents_draft_cancel: его удаляют). Старые акты и договоры в статусеdraftс номером живут по прежним правилам. - Статусы по типу (
ValidateStatusTransitionForType):draft → issued | cancelled; изissuedсчёт — вpaidилиcancelled, акт — вactedилиcancelled, смета, договор и доп. соглашение — только вcancelled. «Оплачен» бывает только у счёта (documents_paid_only_for_invoice), «Актирован» — только у акта (documents_acted_only_for_act). - Отмена счёта с платежами: если на счёт разнесены платежи (
payment_allocations, платёж не отменён) —409 documents_invoice_has_payments; сначала отмените платёж или уберите разнесение. - Договоры и доп. соглашения формируют
legal.manageилиdocuments.manage; интерфейс узнаёт это из capabilitylegal_documents_manageв/org/me, а не из матрицы «договоры».
Счёт по проекту
POST /api/v1/projects/:id/documents/invoice — счёт клиенту проекта. Выставляют менеджер, который ведёт бюджет клиента этого проекта (запись client_budget и право задавать бюджет именно этого проекта — то же правило, что для сметы), финансы и documents.manage. Отметку «Оплачен» и остальные статусы ставят только финансы (PATCH /documents/:id/status).
kind | Сумма | Строки PDF |
|---|---|---|
full (по умолчанию) | итог сметы (с налогами) | статьи сметы, наценка внутри цен |
advance | percent сметы (0–100] или amount | одна строка «Аванс N % по проекту …», НДС в той же доле, что в смете |
remainder | смета минус выставленные счета проекта (не черновики и не отменённые) | «Окончательный расчёт по проекту …» |
custom | сумма items (name, qty, unit, unit_price) | свои строки, НДС по продавцу |
Ещё в теле: due_date (YYYY-MM-DD, «Оплатить до» в PDF и списке), notes (назначение платежа; пусто — «Оплата по счёту № … по проекту …»), issue (по умолчанию true). Пустое тело — счёт на всю смету, выпущенный сразу (как раньше); с template_id — прежний путь по шаблону.
issue: false сохраняет черновик: без номера и PDF, ввод хранится в payload.invoice_input и возвращается в ответе полем invoice. Черновик:
PUT /api/v1/documents/:id— правка (то же тело;issue: true— сохранить и выпустить);POST /api/v1/documents/:id/issue— выпустить: сумма аванса и остатка пересчитывается от сметы на момент выпуска;DELETE /api/v1/documents/:id— удалить (204).
Менять и удалять можно только черновик счёта проекта: выпущенный документ — 409 documents_not_draft. Ошибки вида: documents_invoice_estimate_required (аванс или остаток от пустой сметы), documents_invoice_advance_required, documents_invoice_above_estimate, documents_invoice_nothing_left (всё уже выставлено), documents_invoice_kind_unknown.
Выпуск регистрирует плановую выручку проекта (RegisterPlannedRevenue), как и раньше.
Счёт компании без проекта — POST /api/v1/companies/:id/invoices (финансы, documents.manage): свои строки, notes, due_date; продавец — основной набор «Моей компании», PDF — в файлах компании. В интерфейсе — «Выставить счёт» в меню карточки компании.
Документ для клиента
Строки и итоги сметы PDF и счёта на всю смету (аванс, остаток) берутся из действующей сметы проекта (Смета проекта): разделы или строки с количеством и периодом, скидки строками со знаком минус, УСН и НДС сверху строками. Без сметы — из бюджета (статьи по категориям).
Смета и счёт — документы для клиента:
- наценки нет отдельной строкой — она разнесена по позициям пропорционально их сумме; «Сумма без наценки» не печатается;
- фактических сумм и заметок нет — только плановые позиции; факт без плана (часы, платежи) в смету не попадает; позиция без названия подписана названием статьи («Логистика», а не
logistics); - налоги — строками (УСН, НДС сверху) или «В том числе НДС»;
- место для подписи: в смете — блок «Исполнитель / Заказчик» (организация, ИНН, ФИО, подпись, М. П.), в счёте — «Руководитель / Бухгалтер» и М. П.
PDF ложится в папку проекта по виду: счёт — «Счета» (invoices, заводится для всех проектов миграцией 0165), смета — «Коммерческие предложения», договор, акт и доп. соглашение — «Договоры». Имя файла — «Счёт № 12.pdf». Загрузку делает система: права на документ уже проверены, отдельное право на файлы проекта не нужно.
Процесс генерации документа
Пример: Генерация счета
Шаг 1: Подготовка
Менеджер проекта:
- Проверяет, что все данные в проекте заполнены
- Проверяет финальный бюджет
- Проверяет реквизиты клиентаШаг 2: Выбор шаблона
Менеджер:
1. Открывает проект
2. Нажимает "Generate Document"
3. Выбирает "Invoice"
4. Выбирает шаблон (стандартный или кастомный)Шаг 3: Подстановка данных
Система автоматически собирает:
- DocNumber: 2026-001 (следующий номер)
- DocDate: 2026-04-20
- ClientName: ООО "Клиент"
- ClientAddress: ул. Примерная, 1
- ClientTIN: 123456789
- SellerRequisites: набор «Моей компании», выбранный плательщиком в проекте
(projects.payer_requisite_id), иначе primary internal-реквизиты из
/settings/my-company/requisites
- ClientRequisites: primary-реквизиты компании из /requisites
- Tasks: [
{Name: "Setup chairs", Amount: 10000},
{Name: "Setup tables", Amount: 5000}
]
- Equipment: [
{Name: "Chairs", Qty: 10, Amount: 0}, // со склада
{Name: "Projector rental", Qty: 1, Amount: 10000}
]
- LogisticsCost: [
{Description: "Delivery", Amount: 2000}
]
- TotalAmount: 27000
- TaxAmount: 4860
- FinalAmount: 31860Шаг 4: Генерация
Система:
1. Берет шаблон
2. Заменяет все {{Переменные}} на реальные данные
3. Генерирует готовый документ (PDF или DOCX)Шаг 5: Результат
Готовый счет (PDF):
- Красиво оформлен
- Все данные подставлены
- Готов к отправке клиенту
- Сохранен в проекте как Document (не как File)Управление документами
Просмотр
- Открыть проект
- Перейти в раздел "Documents"
- Видно все сгенерированные документы
Регенерация
Если данные проекта изменились, документ можно пересоздать:
- Нажать "Regenerate" на готовом документе
- Система заново соберет данные и создаст новую версию
- Старая версия архивируется (с отметкой "superseded")
Скачивание
- Выбрать документ
- Нажать "Download"
- Получить PDF или DOCX
Отправка клиенту
- Скачать документ
- Отправить по email (вручную или через систему, если есть интеграция)
Акт по счёту
Акт формируется по одному из двух оснований (POST /api/v1/projects/:id/documents/act):
- по счёту —
basis_invoice_id: строки, сумма и НДС берутся из выставленного счёта проекта, у актаparent_document_id= счёт, в печатной форме — строка «Основание: Счёт № N от ДД.ММ.ГГГГ» (поле шаблона Wordbasis). По одному счёту — один неотменённый акт: второй даёт409 documents_invoice_already_acted; черновик, отменённый счёт или счёт другого проекта —400 documents_act_basis_must_be_invoice; - по смете целиком — без
basis_invoice_id, как раньше: итоговый акт по действующей смете проекта.
Договоры одним списком
Договор, сформированный в проекте, сервер сразу заносит в реестр договоров (contracts): контрагент — клиент проекта, номер «N от ДД.ММ.ГГГГ», предмет «Договор по проекту «…»», сумма, document_id — PDF. Доп. соглашение прикрепляется к договору реестра связью amendment (contract_links). Срабатывает по событию document.created (internal/app/document_events.go → contracts.SyncGenerated), повтор ничего не дублирует; сбой реестра выпуск документа не отменяет. Миграция 0184 перенесла уже сформированные договоры и соглашения.
Реестр документов для финансов
GET /api/v1/finance/documents — счета, акты, договоры и соглашения всех проектов (и счета без проекта) одним списком для бухгалтерии. Видят финансы, бухгалтерия (accounting.*), юристы и затраты «все».
- Отбор:
type(через запятую:invoice,act,contract,addendum),status,preset(unpaid,overdue,unacted,paid,draft,signed,pending),company_id,project_id,date_from,date_to,q(номер, клиент, проект),limit(до 200),offset. - Строка: клиент и проект по имени,
paid_amount(проведённые разнесения платежей; «Оплачен» вручную — вся сумма),outstanding,overdue_days, номер и вид основания (parent_number,parent_type),act_numbers— акты по счёту. summary— итоги по отбору без пресета: к оплате, просрочено, оплачено, без акта, акты подписанные и ждущие подписи, черновики иaging— остаток к оплате: в срок, 1–30, 31–60, больше 60 дней просрочки.
Нумерация документов
Номер выдаётся нашим юрлицом-продавцом по виду документа и году: у счетов ООО и ИП своя нумерация, у счетов и смет — своя (document_counters, scope = 'seller', seller_requisite_id). Первый номер года продолжает уже выданные этим видом (раньше нумерация шла по клиенту) — номера не повторяются.
Номер берётся в той же транзакции, что рендер PDF, загрузка файла и запись документа (DocumentsRepository.IssueNumbered): строка счётчика блокируется до конца транзакции, сбой рендера или загрузки номер не тратит, два одновременных выпуска получают разные номера. Черновик номера не получает — только при выпуске.
Интеграция Files и Documents
Как они связаны
Сценарий:
- Менеджер загружает ТЗ в Files
- При генерации счета система может ссылаться на ТЗ (прикрепить QR код или ссылку)
- Клиент видит в счете ссылку на требования
Пример: Полный цикл проекта
1. Проект создан
├─ Upload: specifications.pdf (File)
├─ Upload: floor-plan.png (File)
└─ Upload: nda.pdf (File)
2. Проект выполнен
├─ Tasks: все закрыты
├─ Team: все отработали часы
└─ Finance: все затраты учтены
3. Генерируются документы
├─ Generate: Invoice (Document)
│ └─ Ссылка на specification.pdf внутри
├─ Generate: Act (Document)
│ └─ Список выполненных Tasks
└─ Generate: Report (Document)
└─ Анализ бюджета
4. Документы готовы к отправке
├─ Invoice (PDF) → отправка клиенту
├─ Act (PDF) → подпись
└─ Report (PDF) → архивВажные правила
1. Данные должны быть полными перед генерацией
Чтобы счет выглядел хорошо:
- У проекта должна быть привязана Company
- Реквизиты клиента должны быть заполнены в Company и, для банковских данных, в primary-наборе Requisites компании
- Реквизиты поставщика должны быть заполнены в primary internal-реквизитах
- Все работы должны быть в Tasks
- Все затраты должны быть в Finance
- Все участники должны быть в Team с ставками
2. Документы "привязаны" к моменту времени
Когда вы генерируете счет, он отражает данные на момент генерации. Если потом меняется проект, счет не обновляется автоматически (нужно его перегенерировать или отредактировать вручную).
3. Файлы — "сырьё", документы — "готовый продукт"
- Файлы: техническое задание, чертежи, черновики
- Документы: счета, контракты, официальные акты
4. История версий
Система может хранить историю сгенерированных документов:
- Версия 1 (2026-04-15): первый черновик
- Версия 2 (2026-04-20): после корректировок
- Версия 3 (2026-04-25): финальная
Чек-лист перед генерацией документа
Перед тем как генерировать важный документ (счет, акт), менеджер должен проверить:
- [ ] Проект имеет статус
in_progress,doneилиclosed, а не начальныйplanned - [ ] Все члены команды добавлены и имеют ставки
- [ ] Все задачи имеют плановые и фактические часы
- [ ] Все оборудование добавлено через логистические операции
- [ ] Все затраты учтены в Finance
- [ ] Плановый бюджет заполнен (если требуется)
- [ ] Реквизиты клиента указаны в Company/Contact
- [ ] Нет открытых логистических операций (все завершены)
- [ ] Сроки проекта соответствуют действительности
Резюме
Файлы (Files):
- Загруженные пользователем исходные материалы
- Организованы в папки и категории
- Используются для справки и работы
Документы (Documents):
- Сгенерированные на основе шаблонов артефакты
- Содержат данные проекта, подставленные в шаблон
- Готовы к отправке клиенту
- Имеют номера и историю версий
Процесс:
Project Data + Template → Generate → Document → Download/SendСистема автоматизирует создание официальных документов, менеджер лишь выбирает шаблон и нажимает "Generate".