Save all currently accumulated repository changes as a backup snapshot for Gitea so no local work is lost.
934 lines
38 KiB
Markdown
934 lines
38 KiB
Markdown
# 📘 МОДУЛЬ DocTemplate - ПОЛНЫЙ МАНУАЛ
|
||
|
||
**Версия:** 1.0
|
||
**Дата:** 2026-01-22
|
||
**Статус:** План реализации
|
||
|
||
---
|
||
|
||
## 📋 СОДЕРЖАНИЕ
|
||
|
||
1. [Обзор модуля](#обзор-модуля)
|
||
2. [Архитектура](#архитектура)
|
||
3. [Структура модуля](#структура-модуля)
|
||
4. [База данных](#база-данных)
|
||
5. [Процесс работы](#процесс-работы)
|
||
6. [Интерфейс пользователя](#интерфейс-пользователя)
|
||
7. [Технические детали](#технические-детали)
|
||
8. [Интеграция с PDFMaker](#интеграция-с-pdfmaker)
|
||
9. [План реализации](#план-реализации)
|
||
|
||
---
|
||
|
||
## 🎯 ОБЗОР МОДУЛЯ
|
||
|
||
### **Назначение**
|
||
|
||
Модуль `DocTemplate` предназначен для генерации документов (DOCX) из шаблонов Nextcloud с автоматическим заполнением переменных данными из модулей CRM.
|
||
|
||
### **Основные возможности**
|
||
|
||
- ✅ Создание и редактирование шаблонов документов
|
||
- ✅ Автоматическое заполнение переменных данными из CRM
|
||
- ✅ Поддержка связанных модулей
|
||
- ✅ Интеграция с OnlyOffice для редактирования
|
||
- ✅ Сохранение готовых документов в S3
|
||
- ✅ Двухпанельный редактор (переменные + OnlyOffice)
|
||
|
||
### **Аналогия**
|
||
|
||
Модуль аналогичен PDFMaker, но работает с DOCX файлами вместо PDF и использует шаблоны из Nextcloud.
|
||
|
||
---
|
||
|
||
## 🏗️ АРХИТЕКТУРА
|
||
|
||
### **Общая схема**
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ NEXTCLOUD │
|
||
│ /Templates/ │
|
||
│ ├── pretenziya.docx ← ФИЗИЧЕСКИЕ ФАЙЛЫ │
|
||
│ ├── iskovoe_zayavlenie.docx │
|
||
│ └── soglashenie.docx │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
▲
|
||
│ WebDAV (скачивание/загрузка)
|
||
│
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ CRM MODULE DocTemplate │
|
||
│ │
|
||
│ База данных: │
|
||
│ ┌─────────────────────────────────────┐ │
|
||
│ │ vtiger_doctemplate │ │
|
||
│ │ - templateid │ │
|
||
│ │ - templatename: "Претензия" │ │
|
||
│ │ - filename: "pretenziya.docx" │ ← Ссылка │
|
||
│ │ - module: "Project" │ │
|
||
│ │ - mapping: { │ │
|
||
│ │ "CLIENT_NAME": "$PROJECT_..." │ │
|
||
│ │ } │ │
|
||
│ └─────────────────────────────────────┘ │
|
||
│ │
|
||
│ Процесс генерации: │
|
||
│ 1. Получить метаданные из БД │
|
||
│ 2. Скачать шаблон из Nextcloud │
|
||
│ 3. Получить данные записи (CRMEntity) │
|
||
│ 4. Заполнить переменные по маппингу │
|
||
│ 5. Сохранить в S3 │
|
||
│ 6. Открыть в OnlyOffice │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### **Разделение ответственности**
|
||
|
||
- **Nextcloud:** Хранение физических файлов шаблонов (DOCX)
|
||
- **CRM:** Метаданные, маппинг переменных, логика генерации
|
||
- **S3:** Хранение готовых документов
|
||
- **OnlyOffice:** Редактирование шаблонов и готовых документов
|
||
|
||
---
|
||
|
||
## 📁 СТРУКТУРА МОДУЛЯ
|
||
|
||
```
|
||
modules/DocTemplate/
|
||
├── DocTemplate.php # Основной класс модуля
|
||
├── schema.xml # Схема БД (таблицы)
|
||
├── language/ # Языковые файлы
|
||
│ └── ru_ru.lang.php
|
||
├── models/ # Модели
|
||
│ ├── Module.php # Модель модуля
|
||
│ ├── Record.php # Модель записи
|
||
│ ├── Template.php # Модель шаблона
|
||
│ ├── TemplateGenerator.php # Генератор документов
|
||
│ ├── VariableProcessor.php # Обработчик переменных
|
||
│ ├── VariableExtractor.php # Извлечение переменных из DOCX
|
||
│ └── FieldMapper.php # Маппер полей
|
||
├── views/ # Представления
|
||
│ ├── List.php # Список шаблонов
|
||
│ ├── Detail.php # Детальный вид шаблона
|
||
│ ├── Edit.php # Редактирование шаблона (двухпанельный)
|
||
│ └── Create.php # Создание шаблона
|
||
├── actions/ # Действия
|
||
│ ├── GenerateDocument.php # Генерация документа
|
||
│ ├── ListTemplates.php # Список шаблонов для модуля
|
||
│ ├── ExtractVariables.php # Извлечение переменных из DOCX
|
||
│ ├── SaveMapping.php # Сохранение маппинга
|
||
│ ├── GetModuleFields.php # Получение списка полей модуля
|
||
│ ├── SaveTemplateContent.php # Сохранение содержимого шаблона
|
||
│ └── OnlyOfficeCallback.php # Callback от OnlyOffice
|
||
├── resources/ # Ресурсы
|
||
│ ├── DocTemplate.js # JS для UI
|
||
│ ├── DocTemplate.css # Стили
|
||
│ └── images/ # Иконки
|
||
└── helpers/ # Вспомогательные классы
|
||
└── NextcloudClient.php # Клиент Nextcloud (WebDAV)
|
||
```
|
||
|
||
---
|
||
|
||
## 🗄️ БАЗА ДАННЫХ
|
||
|
||
### **Таблица: `vtiger_doctemplate`**
|
||
|
||
Основная таблица для хранения шаблонов:
|
||
|
||
```sql
|
||
CREATE TABLE `vtiger_doctemplate` (
|
||
`templateid` int(11) NOT NULL AUTO_INCREMENT,
|
||
`templatename` varchar(255) NOT NULL, -- "Претензия"
|
||
`filename` varchar(255) NOT NULL, -- "pretenziya.docx"
|
||
`module` varchar(100) NOT NULL, -- "Project"
|
||
`description` text, -- Описание шаблона
|
||
`mapping` longtext, -- JSON маппинг переменных
|
||
`nextcloud_path` varchar(255) DEFAULT '/Templates/', -- Путь в Nextcloud
|
||
`is_active` tinyint(1) DEFAULT '1',
|
||
`owner` int(11) NOT NULL,
|
||
`createdtime` datetime NOT NULL,
|
||
`modifiedtime` datetime NOT NULL,
|
||
`deleted` tinyint(1) DEFAULT '0',
|
||
PRIMARY KEY (`templateid`)
|
||
) ENGINE=InnoDB;
|
||
```
|
||
|
||
**Пример записи:**
|
||
```json
|
||
{
|
||
"templateid": 1,
|
||
"templatename": "Претензия",
|
||
"filename": "pretenziya.docx",
|
||
"module": "Project",
|
||
"description": "Шаблон претензии для проектов",
|
||
"mapping": {
|
||
"CLIENT_NAME": "$PROJECT_PROJECTNAME$",
|
||
"DATE": "$PROJECT_CREATEDTIME$",
|
||
"AMOUNT": "$PROJECT_CF_1885$",
|
||
"CONTACT_NAME": "$CONTACTS_LASTNAME$"
|
||
},
|
||
"nextcloud_path": "/Templates/"
|
||
}
|
||
```
|
||
|
||
### **Таблица: `vtiger_doctemplate_seq`**
|
||
|
||
Счетчик для генерации ID:
|
||
|
||
```sql
|
||
CREATE TABLE `vtiger_doctemplate_seq` (
|
||
`id` int(11) NOT NULL DEFAULT '1'
|
||
) ENGINE=InnoDB;
|
||
```
|
||
|
||
### **Таблица: `vtiger_doctemplate_settings`**
|
||
|
||
Настройки шаблона:
|
||
|
||
```sql
|
||
CREATE TABLE `vtiger_doctemplate_settings` (
|
||
`templateid` int(11) NOT NULL,
|
||
`output_folder` varchar(255), -- Папка для сохранения готовых документов
|
||
`file_naming` varchar(255), -- Правило именования файлов
|
||
`auto_open` tinyint(1) DEFAULT '1', -- Автоматически открывать после генерации
|
||
`owner` int(11) NOT NULL,
|
||
`sharingtype` char(7) DEFAULT 'public',
|
||
PRIMARY KEY (`templateid`)
|
||
) ENGINE=InnoDB;
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 ПРОЦЕСС РАБОТЫ
|
||
|
||
### **1. Создание шаблона**
|
||
|
||
#### **Сценарий A: Создание пустого шаблона**
|
||
|
||
```
|
||
1. Пользователь создает запись шаблона в CRM
|
||
- Название: "Претензия"
|
||
- Модуль: Project
|
||
- Имя файла: pretenziya.docx
|
||
|
||
2. CRM создает пустой DOCX через PHPWord
|
||
|
||
3. CRM загружает файл в Nextcloud /Templates/
|
||
|
||
4. Открывается редактор (двухпанельный интерфейс)
|
||
```
|
||
|
||
#### **Сценарий B: Загрузка существующего файла**
|
||
|
||
```
|
||
1. Пользователь загружает DOCX файл через интерфейс CRM
|
||
|
||
2. CRM загружает файл в Nextcloud /Templates/
|
||
|
||
3. CRM создает запись в БД
|
||
|
||
4. CRM автоматически находит переменные в документе
|
||
|
||
5. Показывается форма настройки маппинга
|
||
```
|
||
|
||
---
|
||
|
||
### **2. Редактирование шаблона**
|
||
|
||
#### **Двухпанельный интерфейс:**
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ Редактирование: Претензия [💾 Сохранить] │
|
||
├──────────────┬──────────────────────────────────────────┤
|
||
│ │ │
|
||
│ ПЕРЕМЕННЫЕ │ ONLYOFFICE РЕДАКТОР │
|
||
│ │ ┌────────────────────────────────────┐ │
|
||
│ [🔍 Поиск] │ │ │ │
|
||
│ │ │ ПРЕТЕНЗИЯ │ │
|
||
│ Прямые поля: │ │ │ │
|
||
│ • projectname│ │ От: {CLIENT_NAME} │ │
|
||
│ • createdtime│ │ Дата: {DATE} │ │
|
||
│ • cf_1885 │ │ │ │
|
||
│ │ │ Сумма: {AMOUNT} │ │
|
||
│ Связанные: │ │ │ │
|
||
│ • Contacts │ │ │ │
|
||
│ - lastname │ └────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ Функции: │ │
|
||
│ • formatDate │ │
|
||
│ │ │
|
||
└──────────────┴──────────────────────────────────────────┘
|
||
```
|
||
|
||
**Как работает:**
|
||
|
||
1. **Левая панель:** Список полей модуля (через `PDFMaker_Fields_Model`)
|
||
2. **Правая панель:** OnlyOffice редактор в iframe
|
||
3. **Клик по переменной:** Копируется в буфер обмена → вставить в документ (Ctrl+V)
|
||
4. **Сохранение:** Документ сохраняется в Nextcloud → CRM находит переменные → настройка маппинга
|
||
|
||
---
|
||
|
||
### **3. Настройка маппинга**
|
||
|
||
После сохранения шаблона CRM автоматически:
|
||
|
||
1. Скачивает DOCX из Nextcloud
|
||
2. Парсит через PHPWord
|
||
3. Находит все переменные `{VAR_NAME}`
|
||
4. Показывает форму настройки:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ Настройка маппинга для "Претензия" │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Найдены переменные: │
|
||
│ │
|
||
│ Переменная → Поле модуля │
|
||
│ ┌─────────────┐ ┌──────────────────────────────┐ │
|
||
│ │ CLIENT_NAME │ → │ $PROJECT_PROJECTNAME$ │ │
|
||
│ │ DATE │ → │ $PROJECT_CREATEDTIME$ │ │
|
||
│ │ AMOUNT │ → │ $PROJECT_CF_1885$ │ │
|
||
│ └─────────────┘ └──────────────────────────────┘ │
|
||
│ │
|
||
│ [+ Добавить переменную] │
|
||
│ │
|
||
│ [💾 Сохранить маппинг] │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
### **4. Генерация документа**
|
||
|
||
#### **Процесс:**
|
||
|
||
```
|
||
1. Пользователь в детальном виде записи (Project, HelpDesk, etc.)
|
||
нажимает кнопку "Создать из шаблона"
|
||
|
||
2. Показывается список шаблонов для модуля
|
||
|
||
3. Пользователь выбирает шаблон
|
||
|
||
4. CRM выполняет:
|
||
a. Получает метаданные шаблона из БД
|
||
b. Скачивает шаблон из Nextcloud (WebDAV)
|
||
c. Получает данные записи через CRMEntity
|
||
d. Заполняет переменные по маппингу
|
||
e. Сохраняет готовый документ в S3
|
||
f. Открывает документ в OnlyOffice
|
||
```
|
||
|
||
#### **Алгоритм генерации:**
|
||
|
||
```php
|
||
// Псевдокод
|
||
function generate($module, $recordId, $templateId) {
|
||
// 1. Получить шаблон
|
||
$template = getTemplate($templateId);
|
||
|
||
// 2. Скачать из Nextcloud
|
||
$docxContent = downloadFromNextcloud($template->filename);
|
||
|
||
// 3. Получить данные записи (как PDFMaker)
|
||
$focus = CRMEntity::getInstance($module);
|
||
$focus->retrieve_entity_info($recordId, $module);
|
||
|
||
// 4. Построить переменные из маппинга
|
||
$variables = buildVariables($template->mapping, $focus, $module);
|
||
|
||
// 5. Заменить переменные в DOCX
|
||
$filledContent = replaceVariables($docxContent, $variables);
|
||
|
||
// 6. Сохранить в S3
|
||
$filePath = saveToS3($filledContent, $module, $recordId);
|
||
|
||
// 7. Вернуть URL для OnlyOffice
|
||
return getOnlyOfficeUrl($filePath);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 ИНТЕРФЕЙС ПОЛЬЗОВАТЕЛЯ
|
||
|
||
### **1. Список шаблонов (List View)**
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ Шаблоны документов [+ Создать] │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Название │ Модуль │ Файл │ Действия│
|
||
│ ───────────────────────────────────────────────────── │
|
||
│ Претензия │ Project │ pretenziya.docx │ [✏️][👁️]│
|
||
│ Исковое заявл. │ Project │ isk.docx │ [✏️][👁️]│
|
||
│ Соглашение │ Contacts │ soglashenie.docx │ [✏️][👁️]│
|
||
│ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### **2. Детальный вид шаблона**
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ Претензия [Редактировать] [×]│
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Модуль: Project │
|
||
│ Файл: pretenziya.docx │
|
||
│ Путь: /Templates/ │
|
||
│ │
|
||
│ [📝 Редактировать содержимое] │
|
||
│ → Откроет двухпанельный редактор │
|
||
│ │
|
||
│ ──────────────────────────────────────────────────── │
|
||
│ │
|
||
│ Маппинг переменных: │
|
||
│ ┌──────────────────────────────────────────────────┐ │
|
||
│ │ CLIENT_NAME → $PROJECT_PROJECTNAME$ │ │
|
||
│ │ DATE → $PROJECT_CREATEDTIME$ │ │
|
||
│ │ AMOUNT → $PROJECT_CF_1885$ │ │
|
||
│ └──────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ [+ Добавить переменную] │
|
||
│ │
|
||
│ [💾 Сохранить] │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### **3. Кнопка в модулях CRM**
|
||
|
||
В детальном виде модулей (Project, HelpDesk, Contacts) добавляется кнопка:
|
||
|
||
```
|
||
[📄 Создать из шаблона]
|
||
```
|
||
|
||
При клике открывается диалог выбора шаблона.
|
||
|
||
---
|
||
|
||
## 🔧 ТЕХНИЧЕСКИЕ ДЕТАЛИ
|
||
|
||
### **1. Формат переменных**
|
||
|
||
#### **В шаблоне DOCX:**
|
||
|
||
Пользователь пишет переменные в формате:
|
||
```
|
||
{CLIENT_NAME}
|
||
{DATE}
|
||
{AMOUNT}
|
||
```
|
||
|
||
#### **В маппинге CRM:**
|
||
|
||
Используется формат PDFMaker:
|
||
```json
|
||
{
|
||
"CLIENT_NAME": "$PROJECT_PROJECTNAME$",
|
||
"DATE": "$PROJECT_CREATEDTIME$",
|
||
"AMOUNT": "$PROJECT_CF_1885$"
|
||
}
|
||
```
|
||
|
||
**Преимущества формата PDFMaker:**
|
||
- Префикс модуля (`PROJECT_`) позволяет различать поля
|
||
- Поддержка связанных модулей (`$CONTACTS_LASTNAME$`)
|
||
- Единый формат с существующей системой
|
||
|
||
---
|
||
|
||
### **2. Получение данных записи**
|
||
|
||
Используется подход PDFMaker:
|
||
|
||
```php
|
||
// Создать экземпляр модуля
|
||
$focus = CRMEntity::getInstance($module);
|
||
|
||
// Очистить поля
|
||
foreach ($focus->column_fields as $cf_key => $cf_value) {
|
||
$focus->column_fields[$cf_key] = '';
|
||
}
|
||
|
||
// Получить данные записи
|
||
$focus->retrieve_entity_info($recordId, $module);
|
||
$focus->id = $recordId;
|
||
|
||
// Все поля доступны через:
|
||
$focus->column_fields['fieldname']
|
||
```
|
||
|
||
**Преимущества:**
|
||
- Работает со всеми модулями
|
||
- Учитывает кастомные поля
|
||
- Автоматическое форматирование значений
|
||
|
||
---
|
||
|
||
### **3. Обработка переменных**
|
||
|
||
#### **Прямые поля модуля:**
|
||
|
||
```php
|
||
// Маппинг: "CLIENT_NAME" => "$PROJECT_PROJECTNAME$"
|
||
// Извлечение: PROJECT_PROJECTNAME → module=PROJECT, field=projectname
|
||
$value = $focus->column_fields['projectname'];
|
||
```
|
||
|
||
#### **Связанные модули:**
|
||
|
||
```php
|
||
// Маппинг: "CONTACT_NAME" => "$CONTACTS_LASTNAME$"
|
||
// Извлечение: CONTACTS_LASTNAME → module=CONTACTS, field=lastname
|
||
$value = getRelatedFieldValue($recordId, 'Contacts', 'lastname');
|
||
```
|
||
|
||
#### **Вычисляемые поля:**
|
||
|
||
```php
|
||
// Маппинг: "FULL_DATE" => {"type": "function", "function": "formatDate", "params": ["createdtime", "d.m.Y"]}
|
||
$value = formatDate($focus->column_fields['createdtime'], 'd.m.Y');
|
||
```
|
||
|
||
---
|
||
|
||
### **4. Замена переменных в DOCX**
|
||
|
||
Для DOCX файлов используется PHPWord:
|
||
|
||
```php
|
||
function replaceDocxVariables($docxContent, $variables) {
|
||
// Сохранить во временный файл
|
||
$tempFile = tempnam(sys_get_temp_dir(), 'template_') . '.docx';
|
||
file_put_contents($tempFile, $docxContent);
|
||
|
||
// Загрузить через PHPWord
|
||
$phpWord = \PhpOffice\PhpWord\IOFactory::load($tempFile);
|
||
|
||
// Заменить переменные во всех секциях
|
||
foreach ($phpWord->getSections() as $section) {
|
||
foreach ($section->getElements() as $element) {
|
||
if ($element instanceof \PhpOffice\PhpWord\Element\Text) {
|
||
$text = $element->getText();
|
||
$text = replaceVariables($text, $variables);
|
||
$element->setText($text);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Сохранить результат
|
||
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
|
||
$outputFile = tempnam(sys_get_temp_dir(), 'output_') . '.docx';
|
||
$writer->save($outputFile);
|
||
|
||
$result = file_get_contents($outputFile);
|
||
|
||
// Удалить временные файлы
|
||
unlink($tempFile);
|
||
unlink($outputFile);
|
||
|
||
return $result;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### **5. Интеграция с Nextcloud**
|
||
|
||
#### **Скачивание шаблона:**
|
||
|
||
```php
|
||
function downloadFromNextcloud($filename, $path = '/Templates/') {
|
||
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
||
$username = 'admin';
|
||
$password = 'office';
|
||
|
||
$webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' .
|
||
$username . $path . $filename;
|
||
|
||
$ch = curl_init($webdavUrl);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
|
||
$content = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode !== 200) {
|
||
throw new Exception("Шаблон не найден: {$filename}");
|
||
}
|
||
|
||
return $content;
|
||
}
|
||
```
|
||
|
||
#### **Загрузка шаблона:**
|
||
|
||
```php
|
||
function uploadToNextcloud($localFile, $filename, $path = '/Templates/') {
|
||
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
||
$username = 'admin';
|
||
$password = 'office';
|
||
|
||
$webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' .
|
||
$username . $path . $filename;
|
||
|
||
$ch = curl_init($webdavUrl);
|
||
curl_setopt($ch, CURLOPT_PUT, true);
|
||
curl_setopt($ch, CURLOPT_INFILE, fopen($localFile, 'r'));
|
||
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localFile));
|
||
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
|
||
curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode !== 201 && $httpCode !== 204) {
|
||
throw new Exception("Ошибка загрузки в Nextcloud");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 ИНТЕГРАЦИЯ С PDFMAKER
|
||
|
||
### **Что используем из PDFMaker:**
|
||
|
||
1. **Формат переменных:** `$MODULE_FIELDNAME$`
|
||
2. **Получение данных:** `CRMEntity::getInstance()` + `retrieve_entity_info()`
|
||
3. **Список полей:** `PDFMaker_Fields_Model::getSelectModuleFields()`
|
||
4. **Обработка типов полей:** `PDFMaker_PDFContentUtils_Model::getUITypeName()`
|
||
|
||
### **Преимущества:**
|
||
|
||
- ✅ Переиспользование проверенной логики
|
||
- ✅ Единый формат с существующей системой
|
||
- ✅ Поддержка связанных модулей из коробки
|
||
- ✅ Автоматическое форматирование полей
|
||
|
||
---
|
||
|
||
## 📋 ПЛАН РЕАЛИЗАЦИИ
|
||
|
||
### **Этап 1: Базовая структура модуля**
|
||
|
||
**Задачи:**
|
||
1. Создать структуру папок `modules/DocTemplate/`
|
||
2. Создать `DocTemplate.php` (основной класс)
|
||
3. Создать `schema.xml` с таблицами БД
|
||
4. Создать базовые модели (`Module.php`, `Record.php`, `Template.php`)
|
||
5. Зарегистрировать модуль в системе
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/DocTemplate.php`
|
||
- `modules/DocTemplate/schema.xml`
|
||
- `modules/DocTemplate/models/Module.php`
|
||
- `modules/DocTemplate/models/Record.php`
|
||
- `modules/DocTemplate/models/Template.php`
|
||
|
||
---
|
||
|
||
### **Этап 2: Интеграция с Nextcloud**
|
||
|
||
**Задачи:**
|
||
1. Создать `helpers/NextcloudClient.php` (WebDAV клиент)
|
||
2. Реализовать скачивание шаблонов
|
||
3. Реализовать загрузку шаблонов
|
||
4. Реализовать проверку существования файлов
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/helpers/NextcloudClient.php`
|
||
|
||
---
|
||
|
||
### **Этап 3: Генератор документов**
|
||
|
||
**Задачи:**
|
||
1. Создать `models/TemplateGenerator.php`
|
||
2. Интегрировать с PDFMaker (получение данных через CRMEntity)
|
||
3. Реализовать обработку переменных
|
||
4. Реализовать замену переменных в DOCX через PHPWord
|
||
5. Реализовать сохранение в S3
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/models/TemplateGenerator.php`
|
||
- `modules/DocTemplate/models/VariableProcessor.php`
|
||
|
||
---
|
||
|
||
### **Этап 4: Извлечение переменных**
|
||
|
||
**Задачи:**
|
||
1. Создать `models/VariableExtractor.php`
|
||
2. Реализовать парсинг DOCX через PHPWord
|
||
3. Реализовать поиск переменных `{VAR_NAME}`
|
||
4. Интегрировать с процессом сохранения шаблона
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/models/VariableExtractor.php`
|
||
|
||
---
|
||
|
||
### **Этап 5: UI - Список и детальный вид**
|
||
|
||
**Задачи:**
|
||
1. Создать `views/List.php` (список шаблонов)
|
||
2. Создать `views/Detail.php` (детальный вид)
|
||
3. Создать `views/Create.php` (создание шаблона)
|
||
4. Добавить языковые файлы
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/views/List.php`
|
||
- `modules/DocTemplate/views/Detail.php`
|
||
- `modules/DocTemplate/views/Create.php`
|
||
- `modules/DocTemplate/language/ru_ru.lang.php`
|
||
|
||
---
|
||
|
||
### **Этап 6: UI - Двухпанельный редактор**
|
||
|
||
**Задачи:**
|
||
1. Создать `views/Edit.php` (двухпанельный интерфейс)
|
||
2. Создать `resources/DocTemplate.js` (JS для редактора)
|
||
3. Создать `resources/DocTemplate.css` (стили)
|
||
4. Интегрировать OnlyOffice в iframe
|
||
5. Реализовать вставку переменных (копирование в буфер)
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/views/Edit.php`
|
||
- `modules/DocTemplate/resources/DocTemplate.js`
|
||
- `modules/DocTemplate/resources/DocTemplate.css`
|
||
|
||
---
|
||
|
||
### **Этап 7: Actions (API endpoints)**
|
||
|
||
**Задачи:**
|
||
1. Создать `actions/GenerateDocument.php`
|
||
2. Создать `actions/ListTemplates.php`
|
||
3. Создать `actions/ExtractVariables.php`
|
||
4. Создать `actions/SaveMapping.php`
|
||
5. Создать `actions/GetModuleFields.php`
|
||
6. Создать `actions/SaveTemplateContent.php`
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/actions/GenerateDocument.php`
|
||
- `modules/DocTemplate/actions/ListTemplates.php`
|
||
- `modules/DocTemplate/actions/ExtractVariables.php`
|
||
- `modules/DocTemplate/actions/SaveMapping.php`
|
||
- `modules/DocTemplate/actions/GetModuleFields.php`
|
||
- `modules/DocTemplate/actions/SaveTemplateContent.php`
|
||
|
||
---
|
||
|
||
### **Этап 8: Интеграция с модулями CRM**
|
||
|
||
**Задачи:**
|
||
1. Добавить кнопку "Создать из шаблона" в модули (Project, HelpDesk, Contacts)
|
||
2. Создать JavaScript для диалога выбора шаблона
|
||
3. Реализовать генерацию документа из детального вида
|
||
|
||
**Файлы:**
|
||
- `modules/DocTemplate/DocTemplate.php` (метод `addCustomLinks()`)
|
||
- `modules/DocTemplate/resources/DocTemplate.js` (функция `showTemplateDialog()`)
|
||
|
||
---
|
||
|
||
### **Этап 9: Тестирование**
|
||
|
||
**Задачи:**
|
||
1. Тестирование создания шаблонов
|
||
2. Тестирование редактирования шаблонов
|
||
3. Тестирование генерации документов
|
||
4. Тестирование на разных модулях
|
||
5. Проверка производительности
|
||
6. Обработка ошибок
|
||
|
||
---
|
||
|
||
## 🔑 КЛЮЧЕВЫЕ КОМПОНЕНТЫ
|
||
|
||
### **1. DocTemplate_TemplateGenerator_Model**
|
||
|
||
**Назначение:** Генерация документов из шаблонов
|
||
|
||
**Основные методы:**
|
||
- `generate($module, $recordId, $templateId)` - основная функция генерации
|
||
- `downloadFromNextcloud($filename, $path)` - скачивание шаблона
|
||
- `buildVariables($mapping, $focus, $module)` - построение переменных
|
||
- `replaceVariables($content, $variables)` - замена переменных
|
||
- `saveToS3($content, $module, $recordId, $template)` - сохранение в S3
|
||
|
||
---
|
||
|
||
### **2. DocTemplate_VariableProcessor_Model**
|
||
|
||
**Назначение:** Обработка переменных из маппинга
|
||
|
||
**Основные методы:**
|
||
- `process($config, $focus, $module)` - обработка переменной
|
||
- `getFieldValue($fieldConfig, $focus, $module)` - получение значения поля
|
||
- `getRelatedFieldValue($recordId, $relatedModule, $fieldName)` - связанные модули
|
||
- `callFunction($functionName, $params, $focus, $module)` - вызов функций
|
||
|
||
---
|
||
|
||
### **3. DocTemplate_VariableExtractor_Model**
|
||
|
||
**Назначение:** Извлечение переменных из DOCX
|
||
|
||
**Основные методы:**
|
||
- `extractVariables($docxContent)` - извлечение всех переменных
|
||
- `extractTextFromElement($element)` - извлечение текста из элемента PHPWord
|
||
|
||
---
|
||
|
||
### **4. DocTemplate_NextcloudClient_Helper**
|
||
|
||
**Назначение:** Работа с Nextcloud через WebDAV
|
||
|
||
**Основные методы:**
|
||
- `download($filename, $path)` - скачивание файла
|
||
- `upload($localFile, $filename, $path)` - загрузка файла
|
||
- `exists($filename, $path)` - проверка существования
|
||
- `listFiles($path)` - список файлов в папке
|
||
|
||
---
|
||
|
||
## 📊 ФОРМАТ МАППИНГА
|
||
|
||
### **JSON в поле `mapping`:**
|
||
|
||
```json
|
||
{
|
||
"CLIENT_NAME": "$PROJECT_PROJECTNAME$",
|
||
"DATE": "$PROJECT_CREATEDTIME$",
|
||
"AMOUNT": "$PROJECT_CF_1885$",
|
||
"CONTACT_NAME": "$CONTACTS_LASTNAME$",
|
||
"FULL_DATE": {
|
||
"type": "function",
|
||
"function": "formatDate",
|
||
"params": ["createdtime", "d.m.Y"]
|
||
},
|
||
"COMPANY_NAME": {
|
||
"type": "constant",
|
||
"value": "ООО \"Клиент Право\""
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
|
||
|
||
### **Пример 1: Создание шаблона претензии**
|
||
|
||
1. Создать запись шаблона в CRM:
|
||
- Название: "Претензия"
|
||
- Модуль: Project
|
||
- Файл: pretenziya.docx
|
||
|
||
2. Открыть редактор, написать:
|
||
```
|
||
ПРЕТЕНЗИЯ
|
||
|
||
Кому: УК "Жилищник"
|
||
От: {CLIENT_NAME}
|
||
|
||
Дата: {DATE}
|
||
|
||
Текст: {CLAIM_TEXT}
|
||
|
||
Сумма: {AMOUNT} рублей
|
||
```
|
||
|
||
3. Сохранить → CRM находит переменные
|
||
|
||
4. Настроить маппинг:
|
||
- CLIENT_NAME → $PROJECT_PROJECTNAME$
|
||
- DATE → $PROJECT_CREATEDTIME$
|
||
- CLAIM_TEXT → $PROJECT_DESCRIPTION$
|
||
- AMOUNT → $PROJECT_CF_1885$
|
||
|
||
5. Готово!
|
||
|
||
---
|
||
|
||
### **Пример 2: Генерация документа**
|
||
|
||
1. Открыть проект в CRM (recordId=400264)
|
||
|
||
2. Нажать "Создать из шаблона"
|
||
|
||
3. Выбрать шаблон "Претензия"
|
||
|
||
4. CRM:
|
||
- Скачивает pretenziya.docx из Nextcloud
|
||
- Получает данные проекта 400264
|
||
- Заполняет переменные:
|
||
- {CLIENT_NAME} → "Проект_1"
|
||
- {DATE} → "15.01.2025"
|
||
- {AMOUNT} → "400000"
|
||
- Сохраняет готовый документ в S3
|
||
- Открывает в OnlyOffice
|
||
|
||
---
|
||
|
||
## ⚠️ ОГРАНИЧЕНИЯ И ЗАМЕЧАНИЯ
|
||
|
||
1. **PHPWord работает только с DOCX**
|
||
- Для XLSX и PPTX используется простая замена текста
|
||
- Сложное форматирование может не сохраниться
|
||
|
||
2. **Переменные должны быть в тексте**
|
||
- Не работают в заголовках/колонтитулах (ограничение PHPWord)
|
||
- Не работают в таблицах (частично)
|
||
|
||
3. **Размер шаблона**
|
||
- Большие шаблоны (>10MB) могут загружаться медленно
|
||
|
||
4. **OnlyOffice API**
|
||
- Прямая вставка переменных через API требует настройки OnlyOffice Document Server
|
||
- Начальная реализация использует копирование в буфер обмена
|
||
|
||
---
|
||
|
||
## 🚀 ГОТОВНОСТЬ К РЕАЛИЗАЦИИ
|
||
|
||
**Все компоненты спроектированы:**
|
||
- ✅ Архитектура определена
|
||
- ✅ Структура модуля спроектирована
|
||
- ✅ База данных спроектирована
|
||
- ✅ UI/UX продуман
|
||
- ✅ Интеграция с PDFMaker определена
|
||
- ✅ Процессы описаны
|
||
|
||
**Следующий шаг:** Начать реализацию с Этапа 1 (базовая структура модуля)
|
||
|
||
---
|
||
|
||
## 📚 ССЫЛКИ НА ДОПОЛНИТЕЛЬНЫЕ ДОКУМЕНТЫ
|
||
|
||
- [План создания модуля](DOC_TEMPLATE_MODULE_PLAN.md)
|
||
- [Архитектура Nextcloud + CRM](DOC_TEMPLATE_ARCHITECTURE.md)
|
||
- [UX дизайн](DOC_TEMPLATE_UX_DESIGN.md)
|
||
- [Вставка переменных](DOC_TEMPLATE_VARIABLES_INSERTION.md)
|
||
- [Интерфейс редактора](DOC_TEMPLATE_EDITOR_UI.md)
|
||
- [Анализ PDFMaker](PDFMAKER_ANALYSIS.md)
|
||
|
||
---
|
||
|
||
**Модуль готов к реализации! 🎉**
|