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

17 KiB
Raw Blame History

🔗 АРХИТЕКТУРА: 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

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;

Пример записи:

[
    '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. Процесс генерации документа

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":

// В 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

Плюсы:

  • Простота
  • Гибкость
  • Легко редактировать

Минусы:

  • Сложно искать по маппингу
  • Нет версионирования отдельных переменных
$mapping = json_decode($template->mapping, true);
// [
//     'CLIENT_NAME' => '$PROJECT_PROJECTNAME$',
//     'DATE' => '$PROJECT_CREATEDTIME$'
// ]

Подход 2: Отдельная таблица vtiger_doctemplate_mappings

Плюсы:

  • Легко искать
  • Версионирование
  • Можно редактировать через UI

Минусы:

  • Сложнее структура
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 файл

🔍 ПРОВЕРКА СУЩЕСТВОВАНИЯ ШАБЛОНА

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?

Готов начать реализацию! 🎉