Files
crm.clientright.ru/upload_file_n8n.php
Fedor ac7467f0b4 Major CRM updates: AI Assistant, Court Status API, S3 integration improvements, and extensive file storage system
- Added comprehensive AI Assistant system (aiassist/ directory):
  * Vector search and embedding capabilities
  * Typebot proxy integration
  * Elastic search functionality
  * Message classification and chat history
  * MCP proxy for external integrations

- Implemented Court Status API (GetCourtStatus.php):
  * Real-time court document status checking
  * Integration with external court systems
  * Comprehensive error handling and logging

- Enhanced S3 integration:
  * Improved file backup system with metadata
  * Batch processing capabilities
  * Enhanced error logging and recovery
  * Copy operations with URL fixing

- Added Telegram contact creation API
- Improved error logging across all modules
- Enhanced callback system for AI responses
- Extensive backup file storage with timestamps
- Updated documentation and README files

- File storage improvements:
  * Thousands of backup files with proper metadata
  * Fix operations for broken file references
  * Project-specific backup and recovery systems
  * Comprehensive file integrity checking

Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
2025-10-16 11:17:21 +03:00

403 lines
17 KiB
PHP
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.

<?php
// upload_documents_to_crm.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Быстрый ping для проверки доступности скрипта из браузера/HTTP-клиента
if (isset($_GET['ping'])) {
header('Content-Type: text/plain; charset=utf-8');
echo 'pong';
exit;
}
// Подключение к CRM
require_once('config.inc.php');
require_once('include/Webservices/Utils.php');
require_once('include/Webservices/Create.php');
require_once('include/Webservices/Login.php');
require_once('include/Webservices/AuthToken.php');
require_once('include/Webservices/AddRelated.php');
require_once('include/utils/utils.php');
require_once('includes/Loader.php');
vimport('includes.runtime.Globals');
require_once('include/database/PearDatabase.php');
require_once('modules/Users/Users.php');
// Инициализируем подключение к БД явно
$adb = PearDatabase::getInstance();
// Управление вербозностью: для POST по умолчанию тихий режим (чистый JSON)
$__IS_POST__ = (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST');
$__VERBOSE__ = (!$__IS_POST__) || (isset($_GET['verbose']) && $_GET['verbose'] == '1');
if ($__IS_POST__) {
// В API-режиме скрываем любые варнинги/эхо и возвращаем только JSON
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
}
// Глобальный логгер для этого эндпоинта
if (!function_exists('writeLog')) {
function writeLog($message) {
$logFile = '/logs/upload_documents.log';
$timestamp = date('Y-m-d H:i:s');
file_put_contents($logFile, "[$timestamp] $message\n", FILE_APPEND | LOCK_EX);
}
}
// Унифицированный JSON-ответ и обработка фатальных ошибок для POST
function json_response($payload, $code = 200) {
if (!headers_sent()) {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
}
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
}
if ($__IS_POST__) {
register_shutdown_function(function () {
$e = error_get_last();
if ($e && in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
writeLog('FATAL: '.$e['message'].' in '.$e['file'].':'.$e['line']);
json_response([
'success' => false,
'error' => [
'type' => 'fatal',
'message' => 'Internal error',
]
], 500);
}
});
}
/**
* Функция для получения entity ID по имени модуля
*/
function vtws_getEntityId($entityName) {
global $adb;
$wsrs = $adb->pquery('select id from vtiger_ws_entity where name=?', array($entityName));
if ($wsrs && $adb->num_rows($wsrs) == 1) {
$wsid = $adb->query_result($wsrs, 0, 0);
} else {
$wsid = 0;
}
return $wsid;
}
/**
* Функция для получения webservice ID пользователя
*/
function getWebserviceUserId($userId) {
global $adb;
$entityId = vtws_getEntityId('Users');
return $entityId . 'x' . $userId;
}
/**
* Функция для получения webservice ID проекта
*/
function getWebserviceProjectId($projectId) {
global $adb;
$entityId = vtws_getEntityId('Project');
return $entityId . 'x' . $projectId;
}
/**
* Префикс WS для папок документов
*/
function getDocumentFoldersWsPrefix() {
global $adb;
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['DocumentFolders']);
if ($rs && $adb->num_rows($rs) > 0) {
return (int)$adb->query_result($rs, 0, 'id');
}
return 22;
}
/**
* Получить WS ID папки по имени, иначе null
*/
function getFolderWsIdByName($folderName) {
global $adb;
$rs = $adb->pquery('SELECT folderid FROM vtiger_attachmentsfolder WHERE foldername = ? LIMIT 1', [$folderName]);
if ($rs && $adb->num_rows($rs) > 0) {
$folderId = (int)$adb->query_result($rs, 0, 'folderid');
$prefix = getDocumentFoldersWsPrefix();
return $prefix . 'x' . $folderId;
}
return null;
}
/**
* Безопасная аутентификация через challenge/response
*/
function authenticateWithCRM($username) {
// 1) Получаем challenge токен
$challenge = vtws_getchallenge($username);
if (empty($challenge['token'])) {
throw new Exception('Не удалось получить challenge token');
}
// 2) Берем accesskey пользователя
$user = new Users();
$userId = $user->retrieve_user_id($username);
if (!$userId) {
throw new Exception("Пользователь {$username} не найден");
}
$accessKey = vtws_getUserAccessKey($userId);
if (!$accessKey) {
throw new Exception('Access key пользователя не найден');
}
// 3) Логинимся
$generatedKey = md5($challenge['token'] . $accessKey);
$loggedUser = vtws_login($username, $generatedKey);
// Для отладки можно писать в лог
// error_log("WS login ok for $username, token={$challenge['token']} md5=$generatedKey");
// Установим $current_user для операций CRMEntity
global $current_user;
$current_user = new Users();
$current_user->retrieveCurrentUserInfoFromFile((int)$userId);
return $loggedUser;
}
/**
* Функция для получения ID папки по умолчанию
*/
function getDefaultFolderId() {
global $adb;
$result = $adb->pquery('SELECT folderid FROM vtiger_attachmentsfolder WHERE foldername = ? LIMIT 1', array('Default'));
if ($result && $adb->num_rows($result) > 0) {
$folderId = $adb->query_result($result, 0, 'folderid');
$entityId = vtws_getEntityId('DocumentFolders');
return $entityId . 'x' . $folderId;
}
return '22x1'; // Fallback ID
}
/**
* Основная функция для создания документов в CRM
*/
function createDocumentsInCRM($filesArray, $adminUsername = 'api') {
global $adb;
writeLog("🚀 Начинаем создание документов для пользователя: $adminUsername");
try {
writeLog("🔐 Попытка аутентификации...");
// Проверяем существование пользователя
$user = new Users();
$userId = $user->retrieve_user_id($adminUsername);
if (!$userId) {
throw new Exception("Пользователь '$adminUsername' не найден");
}
writeLog("✅ Пользователь найден, ID: $userId");
// Безопасная аутентификация
$authenticatedUser = authenticateWithCRM($adminUsername);
writeLog("✅ Аутентификация успешна");
$results = [];
foreach ($filesArray as $index => $fileData) {
writeLog("📄 Обрабатываем файл #$index: " . ($fileData['file_name'] ?? 'Unknown'));
try {
// Получаем webservice ID пользователя и проекта
$assignedUserId = getWebserviceUserId($fileData['user_id']);
$projectId = getWebserviceProjectId($fileData['projectid']);
// Папка: сначала пробуем 'Суд', иначе Default
$folderId = getFolderWsIdByName('Суд');
if (!$folderId) {
$folderId = getDefaultFolderId();
writeLog("⚠️ Папка 'Суд' не найдена, используем по умолчанию: $folderId");
} else {
writeLog("📁 Используем папку 'Суд': $folderId");
}
writeLog("🔗 WebService IDs - User: $assignedUserId, Project: $projectId, Folder: $folderId");
// Формируем данные документа
$documentData = [
'notes_title' => $fileData['description'] ?: $fileData['file_name'],
'filename' => $fileData['url'],
'assigned_user_id' => $assignedUserId,
'notecontent' => 'Автоматически загружен из S3. Контакт: ' . $fileData['contactid'],
'filetype' => 'application/pdf',
'filesize' => '0',
'filelocationtype' => 'E',
'fileversion' => '1.0',
'filestatus' => '1',
'filedownloadcount' => '0',
'folderid' => $folderId,
'created_user_id' => $assignedUserId,
'starred' => '0',
'tags' => 'S3,автозагрузка'
];
writeLog("📋 Данные документа подготовлены: " . json_encode($documentData, JSON_UNESCAPED_UNICODE));
// Создаем документ
$document = vtws_create('Documents', $documentData, $authenticatedUser);
if ($document && isset($document['id'])) {
writeLog("✅ Документ создан с ID: " . $document['id']);
// Привязываем документ к проекту
try {
vtws_add_related($projectId, $document['id'], false, $authenticatedUser);
writeLog("✅ Документ привязан к проекту");
$results[] = [
'status' => 'success',
'file_name' => $fileData['file_name'],
'document_id' => $document['id'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Документ успешно создан и привязан к проекту'
];
} catch (Exception $e) {
// Fallback: привязываем напрямую через CRMEntity
writeLog("⚠️ Webservice AddRelated не сработал: " . $e->getMessage() . ". Пытаемся привязать напрямую...");
require_once 'data/CRMEntity.php';
require_once 'modules/Vtiger/CRMEntity.php';
$docIds = vtws_getIdComponents($document['id']);
$docNumericId = (int)$docIds[1];
$focus = CRMEntity::getInstance('Project');
relateEntities($focus, 'Project', (int)$fileData['projectid'], 'Documents', $docNumericId);
writeLog("✅ Привязка выполнена напрямую (Project {$fileData['projectid']} -> Document {$docNumericId})");
$results[] = [
'status' => 'success',
'file_name' => $fileData['file_name'],
'document_id' => $document['id'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Документ создан и привязан к проекту (fallback)'
];
}
} else {
writeLog("❌ Ошибка создания документа");
$results[] = [
'status' => 'error',
'file_name' => $fileData['file_name'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Ошибка создания документа'
];
}
} catch (Exception $e) {
writeLog("❌ Критическая ошибка для файла: " . $e->getMessage());
$results[] = [
'status' => 'error',
'file_name' => $fileData['file_name'] ?? 'Unknown',
'project_id' => $fileData['projectid'] ?? 'Unknown',
'url' => $fileData['url'] ?? 'Unknown',
'message' => 'Ошибка: ' . $e->getMessage()
];
}
}
writeLog("🏁 Обработка завершена. Всего файлов: " . count($filesArray));
return $results;
} catch (Exception $e) {
writeLog("💥 Критическая ошибка: " . $e->getMessage());
return [
'status' => 'critical_error',
'message' => 'Ошибка аутентификации в CRM: ' . $e->getMessage()
];
}
}
/**
* Получение access key пользователя
*/
function vtws_getUserAccessKey($userId) {
global $adb;
$sql = "SELECT accesskey FROM vtiger_users WHERE id = ?";
$result = $adb->pquery($sql, array($userId));
if ($result && $adb->num_rows($result) > 0) {
return $adb->query_result($result, 0, 'accesskey');
}
return null;
}
// Пример использования:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Получаем JSON данные (без BOM) и пробуем распознать формат
writeLog('POST '.$_SERVER['REQUEST_URI'].' CT='.(isset($_SERVER['CONTENT_TYPE'])?$_SERVER['CONTENT_TYPE']:'').', CL='.(isset($_SERVER['CONTENT_LENGTH'])?$_SERVER['CONTENT_LENGTH']:'').' UA='.(isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'').', IP='.(isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'') );
$input = file_get_contents('php://input');
writeLog('RAW BODY: '.substr($input,0,2048).(strlen($input)>2048?'...<truncated>':''));
$input = ltrim($input, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
$filesArray = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
writeLog('JSON ERROR: '.json_last_error_msg());
json_response(['success' => false, 'error' => ['message' => 'Invalid JSON: '.json_last_error_msg()]], 400);
exit;
}
// Авто-распаковка n8n-форматов:
// 1) [{"data":[...]}]
if (is_array($filesArray) && count($filesArray) === 1 && isset($filesArray[0]['data']) && is_array($filesArray[0]['data'])) {
$filesArray = $filesArray[0]['data'];
}
// 2) {"data":[...]}
if (is_array($filesArray) && isset($filesArray['data']) && is_array($filesArray['data'])) {
$filesArray = $filesArray['data'];
}
if (!is_array($filesArray)) {
writeLog('BAD FORMAT: not an array after normalization');
json_response(['success' => false, 'error' => ['message' => 'JSON must be an array of file items']], 400);
exit;
}
writeLog('ITEMS: '.count($filesArray));
// Создаем документы
$results = createDocumentsInCRM($filesArray);
writeLog('DONE: processed='.count($filesArray));
// Возвращаем результат
json_response([
'success' => true,
'results' => $results,
'total_processed' => count($filesArray)
]);
} else {
// Тестовый запуск с вашими данными
$testData = [
[
"session_token" => "sess_dedc540e-f60d-491b-b6bb-ef7f7d04a366",
"user_id" => 1,
"contactid" => 120374,
"description" => "Иск",
"projectid" => 354918,
"pages" => 2,
"url" => "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/120374/1757346451126.pdf",
"file_name" => "1757346451126.pdf"
],
[
"session_token" => "sess_dedc540e-f60d-491b-b6bb-ef7f7d04a366",
"user_id" => 1,
"contactid" => 120374,
"description" => "доказательство направления претензии",
"projectid" => 354918,
"pages" => 4,
"url" => "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/120374/1757346454717.pdf",
"file_name" => "1757346454717.pdf"
]
];
$results = createDocumentsInCRM($testData);
header('Content-Type: application/json');
echo json_encode([
'success' => true,
'results' => $results,
'total_processed' => count($testData)
], JSON_UNESCAPED_UNICODE);
}
?>