Files
crm.clientright.ru/DOC_TEMPLATE_ARCHITECTURE.md
Fedor 01c4fe80b5 chore: snapshot current working tree changes
Save all currently accumulated repository changes as a backup snapshot for Gitea so no local work is lost.
2026-03-26 14:19:01 +03:00

399 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔗 АРХИТЕКТУРА: NEXTCLOUD ШАБЛОНЫ + CRM МОДУЛЬ
## 🎯 КОНЦЕПЦИЯ
**Шаблоны хранятся в Nextcloud, метаданные и маппинг - в CRM модуле.**
---
## 📊 СХЕМА РАБОТЫ
```
┌─────────────────────────────────────────────────────────────┐
│ NEXTCLOUD │
│ /Templates/ │
│ ├── pretenziya.docx ← ФАЙЛ ШАБЛОНА │
│ ├── iskovoe_zayavlenie.docx ← ФАЙЛ ШАБЛОНА │
│ └── soglashenie.docx ← ФАЙЛ ШАБЛОНА │
└─────────────────────────────────────────────────────────────┘
│ WebDAV GET
┌─────────────────────────────────────────────────────────────┐
│ CRM MODULE DocTemplate │
│ │
│ vtiger_doctemplate: │
│ ├── templateid: 1 │
│ ├── templatename: "Претензия" │
│ ├── filename: "pretenziya.docx" ← Ссылка на Nextcloud │
│ ├── module: "Project" │
│ └── mapping: { │
│ "CLIENT_NAME": "$PROJECT_PROJECTNAME$", │
│ "DATE": "$PROJECT_CREATEDTIME$", │
│ "AMOUNT": "$PROJECT_CF_1885$" │
│ } │
│ │
│ vtiger_doctemplate_mappings: │
│ (альтернатива JSON в mapping) │
└─────────────────────────────────────────────────────────────┘
│ Использует маппинг
┌─────────────────────────────────────────────────────────────┐
│ ПРОЦЕСС ГЕНЕРАЦИИ │
│ │
│ 1. Пользователь выбирает шаблон в CRM │
│ 2. CRM получает маппинг из БД │
│ 3. CRM скачивает шаблон из Nextcloud (WebDAV) │
│ 4. CRM получает данные записи (CRMEntity) │
│ 5. CRM заполняет переменные по маппингу │
│ 6. CRM сохраняет готовый документ в S3 │
│ 7. CRM открывает документ в OnlyOffice │
└─────────────────────────────────────────────────────────────┘
```
---
## 🔧 КАК ЭТО РАБОТАЕТ
### **1. Хранение шаблонов**
**В Nextcloud:**
- Физические файлы DOCX хранятся в `/Templates/`
- Управление через веб-интерфейс Nextcloud
- Версионирование (если нужно) через Nextcloud
**В CRM:**
- Метаданные шаблона (название, описание)
- Маппинг переменных (какая переменная → какое поле)
- Настройки (для какого модуля, папка сохранения)
---
### **2. Структура таблицы `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" (в Nextcloud)
`module` varchar(100) NOT NULL, -- "Project"
`description` text, -- Описание шаблона
`mapping` longtext, -- JSON маппинг или NULL
`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;
```
**Пример записи:**
```php
[
'templateid' => 1,
'templatename' => 'Претензия',
'filename' => 'pretenziya.docx',
'module' => 'Project',
'description' => 'Шаблон претензии для проектов',
'mapping' => json_encode([
'CLIENT_NAME' => '$PROJECT_PROJECTNAME$',
'DATE' => '$PROJECT_CREATEDTIME$',
'AMOUNT' => '$PROJECT_CF_1885$',
'CONTACT_NAME' => '$CONTACTS_LASTNAME$'
]),
'nextcloud_path' => '/Templates/'
]
```
---
### **3. Процесс генерации документа**
```php
class DocTemplate_TemplateGenerator_Model {
public function generate($module, $recordId, $templateId) {
// 1. Получить метаданные шаблона из CRM БД
$template = DocTemplate_Template_Model::getInstanceById($templateId);
// 2. Скачать шаблон из Nextcloud
$templateContent = $this->downloadFromNextcloud(
$template->getFilename(),
$template->getNextcloudPath()
);
// 3. Получить данные записи (как PDFMaker)
$focus = CRMEntity::getInstance($module);
$focus->retrieve_entity_info($recordId, $module);
$focus->id = $recordId;
// 4. Получить маппинг из CRM БД
$mapping = $template->getMapping();
// 5. Построить переменные по маппингу
$variables = $this->buildVariables($mapping, $focus, $module);
// 6. Заменить переменные в шаблоне
$content = $this->replaceVariables($templateContent, $variables);
// 7. Сохранить готовый документ в S3
$filePath = $this->saveToS3($content, $module, $recordId, $template);
// 8. Вернуть URL для открытия в OnlyOffice
return $this->getOnlyOfficeUrl($filePath);
}
/**
* Скачивание шаблона из Nextcloud
*/
private 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("Шаблон не найден в Nextcloud: {$filename}");
}
return $content;
}
}
```
---
## 🎨 UI: УПРАВЛЕНИЕ ШАБЛОНАМИ
### **Вариант 1: Синхронизация с Nextcloud**
**Кнопка "Синхронизировать с Nextcloud":**
```php
// В DocTemplate/actions/SyncWithNextcloud.php
class DocTemplate_SyncWithNextcloud_Action {
public function process() {
// 1. Получить список файлов из Nextcloud /Templates/
$templates = $this->listNextcloudTemplates();
// 2. Для каждого файла проверить, есть ли запись в CRM
foreach ($templates as $template) {
$existing = $this->findTemplateByFilename($template['name']);
if (!$existing) {
// 3. Создать новую запись в CRM
$this->createTemplateRecord($template);
} else {
// 4. Обновить метаданные (размер, дата изменения)
$this->updateTemplateRecord($existing, $template);
}
}
return ['success' => true, 'synced' => count($templates)];
}
private function listNextcloudTemplates() {
// WebDAV PROPFIND запрос к /Templates/
// Вернуть список файлов
}
}
```
---
### **Вариант 2: Ручное создание записи**
**В интерфейсе CRM:**
1. Пользователь создает запись шаблона
2. Указывает имя файла в Nextcloud (например, `pretenziya.docx`)
3. Выбирает модуль (Project, HelpDesk, etc.)
4. Настраивает маппинг переменных
5. Сохраняет
**При сохранении:**
- Проверяется, существует ли файл в Nextcloud
- Если нет - показывается предупреждение
---
## 🔄 ДВА ПОДХОДА К МАППИНГУ
### **Подход 1: JSON в поле `mapping`**
**Плюсы:**
- ✅ Простота
- ✅ Гибкость
- ✅ Легко редактировать
**Минусы:**
- ❌ Сложно искать по маппингу
- ❌ Нет версионирования отдельных переменных
```php
$mapping = json_decode($template->mapping, true);
// [
// 'CLIENT_NAME' => '$PROJECT_PROJECTNAME$',
// 'DATE' => '$PROJECT_CREATEDTIME$'
// ]
```
---
### **Подход 2: Отдельная таблица `vtiger_doctemplate_mappings`**
**Плюсы:**
- ✅ Легко искать
- ✅ Версионирование
- ✅ Можно редактировать через UI
**Минусы:**
- ❌ Сложнее структура
```sql
CREATE TABLE `vtiger_doctemplate_mappings` (
`mappingid` int(11) NOT NULL AUTO_INCREMENT,
`templateid` int(11) NOT NULL,
`template_variable` varchar(100) NOT NULL, -- CLIENT_NAME
`field_config` varchar(255) NOT NULL, -- $PROJECT_PROJECTNAME$ или JSON
`sequence` int(11) DEFAULT '0',
PRIMARY KEY (`mappingid`),
KEY `templateid` (`templateid`)
) ENGINE=InnoDB;
```
**Рекомендация:** Начать с JSON, потом при необходимости перейти на отдельную таблицу.
---
## 📋 ПРОЦЕСС СОЗДАНИЯ ШАБЛОНА
### **Сценарий 1: Шаблон уже есть в Nextcloud**
1. Пользователь загружает `pretenziya.docx` в Nextcloud `/Templates/`
2. В CRM создает запись шаблона:
- Название: "Претензия"
- Файл: `pretenziya.docx`
- Модуль: Project
3. Настраивает маппинг:
- `CLIENT_NAME``$PROJECT_PROJECTNAME$`
- `DATE``$PROJECT_CREATEDTIME$`
4. Сохраняет
---
### **Сценарий 2: Создание нового шаблона**
1. В CRM создает запись шаблона
2. Указывает имя файла (например, `new_template.docx`)
3. Настраивает маппинг
4. Сохраняет
5. **Опционально:** Кнопка "Создать пустой шаблон в Nextcloud" - создает пустой DOCX файл
---
## 🔍 ПРОВЕРКА СУЩЕСТВОВАНИЯ ШАБЛОНА
```php
class DocTemplate_Template_Model {
/**
* Проверка существования файла в Nextcloud
*/
public function checkNextcloudFile() {
$nextcloudUrl = 'https://office.clientright.ru:8443';
$username = 'admin';
$password = 'office';
$webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' .
$username . $this->getNextcloudPath() .
$this->getFilename();
$ch = curl_init($webdavUrl);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 200;
}
}
```
---
## 🎯 ИТОГОВАЯ АРХИТЕКТУРА
```
┌─────────────────────────────────────────────────────────────┐
│ NEXTCLOUD (/Templates/) │
│ ├── pretenziya.docx ← ФИЗИЧЕСКИЙ ФАЙЛ │
│ ├── iskovoe_zayavlenie.docx ← ФИЗИЧЕСКИЙ ФАЙЛ │
│ └── soglashenie.docx ← ФИЗИЧЕСКИЙ ФАЙЛ │
└─────────────────────────────────────────────────────────────┘
│ WebDAV
┌─────────────────────────────────────────────────────────────┐
│ CRM MODULE DocTemplate │
│ │
│ vtiger_doctemplate: │
│ ┌─────────────────────────────────────┐ │
│ │ templateid: 1 │ │
│ │ templatename: "Претензия" │ │
│ │ filename: "pretenziya.docx" ←──────┼─── Ссылка │
│ │ module: "Project" │ │
│ │ mapping: { │ │
│ │ "CLIENT_NAME": "$PROJECT_..." │ │
│ │ } │ │
│ └─────────────────────────────────────┘ │
│ │
│ ПРОЦЕСС: │
│ 1. Получить метаданные из БД │
│ 2. Скачать файл из Nextcloud │
│ 3. Заполнить переменные │
│ 4. Сохранить в S3 │
└─────────────────────────────────────────────────────────────┘
```
---
## ✅ ПРЕИМУЩЕСТВА ТАКОГО ПОДХОДА
1.**Шаблоны в одном месте** - Nextcloud (удобно редактировать)
2.**Метаданные в CRM** - маппинг, настройки, права доступа
3.**Версионирование** - можно через Nextcloud
4.**Резервное копирование** - шаблоны в Nextcloud/S3
5.**Разделение ответственности** - файлы там, логика здесь
---
## 🚀 ГОТОВ РЕАЛИЗОВАТЬ!
**Вопросы для уточнения:**
1. **Синхронизация:** Нужна ли автоматическая синхронизация с Nextcloud или ручное создание записей?
2. **Маппинг:** JSON в поле или отдельная таблица?
3. **Создание шаблонов:** Можно ли создавать пустые шаблоны из CRM или только в Nextcloud?
**Готов начать реализацию! 🎉**