Изменения в upload_documents_to_crm.php: ✅ Добавлена логика привязки к HelpDesk (заявке) если указан ticket_id ✅ Если ticket_id не указан - привязываем к Project (старая логика) ✅ Обновлена функция normalizeInputData для передачи ticket_id ✅ Добавлено логирование привязки к HelpDesk/Project Использование: - Передать ticket_id в payload → документ привязывается к HelpDesk - Не передавать ticket_id → документ привязывается к Project
644 lines
27 KiB
PHP
644 lines
27 KiB
PHP
<?php
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', '1');
|
||
|
||
// Для POST запросов отключаем вывод ошибок в HTML
|
||
$IS_POST = ($_SERVER['REQUEST_METHOD'] === 'POST');
|
||
if ($IS_POST) {
|
||
ini_set('display_errors', '0');
|
||
ini_set('display_startup_errors', '0');
|
||
}
|
||
|
||
// Функция для записи в лог
|
||
function writeLog($message) {
|
||
$timestamp = date('Y-m-d H:i:s');
|
||
$line = "[$timestamp] $message\n";
|
||
// Пробуем писать в основной лог
|
||
@file_put_contents(__DIR__ . '/logs/upload_documents.log', $line, FILE_APPEND | LOCK_EX);
|
||
// И в /tmp как запасной вариант
|
||
@file_put_contents('/tmp/upload_documents.log', $line, FILE_APPEND | LOCK_EX);
|
||
// И в системный лог
|
||
error_log('[upload_documents] ' . $message);
|
||
}
|
||
|
||
// Функция для JSON ответа
|
||
function json_response($data, $code = 200) {
|
||
if (!headers_sent()) {
|
||
http_response_code($code);
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
}
|
||
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
// Быстрый ping
|
||
if (isset($_GET['ping'])) {
|
||
header('Content-Type: text/plain; charset=utf-8');
|
||
echo 'pong';
|
||
exit;
|
||
}
|
||
|
||
// Для POST запросов регистрируем обработчик фатальных ошибок
|
||
if ($IS_POST) {
|
||
register_shutdown_function(function() {
|
||
$error = error_get_last();
|
||
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
|
||
writeLog('FATAL: ' . $error['message'] . ' in ' . $error['file'] . ':' . $error['line']);
|
||
json_response([
|
||
'success' => false,
|
||
'error' => [
|
||
'type' => 'fatal',
|
||
'message' => 'Internal error'
|
||
]
|
||
], 500);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Инициализация CRM
|
||
require_once 'config.inc.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';
|
||
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';
|
||
$adb = PearDatabase::getInstance();
|
||
|
||
// Вспомогательные функции из test_ws_documents.php
|
||
function getUserWsPrefix() {
|
||
global $adb;
|
||
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['Users']);
|
||
return ($rs && $adb->num_rows($rs) > 0) ? $adb->query_result($rs, 0, 'id') : 19;
|
||
}
|
||
|
||
function getProjectWsIdFromDB($projectId) {
|
||
global $adb;
|
||
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['Project']);
|
||
return ($rs && $adb->num_rows($rs) > 0) ? $adb->query_result($rs, 0, 'id') . 'x' . (int)$projectId : null;
|
||
}
|
||
|
||
function getDocumentFoldersWsPrefix() {
|
||
global $adb;
|
||
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['DocumentFolders']);
|
||
return ($rs && $adb->num_rows($rs) > 0) ? (int)$adb->query_result($rs, 0, 'id') : 22;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* Извлекает S3 метаданные из URL
|
||
*/
|
||
function parseS3Url($fileUrl) {
|
||
$parsed = parse_url($fileUrl);
|
||
if (!$parsed || !isset($parsed['host']) || !isset($parsed['path'])) {
|
||
return null;
|
||
}
|
||
|
||
$path = ltrim($parsed['path'], '/');
|
||
$pathParts = explode('/', $path, 2);
|
||
|
||
if (count($pathParts) < 2) {
|
||
return null;
|
||
}
|
||
|
||
return [
|
||
'bucket' => $pathParts[0],
|
||
'key' => $pathParts[1],
|
||
'host' => $parsed['host']
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Получает размер файла из S3
|
||
*/
|
||
function getS3FileSize($fileUrl) {
|
||
try {
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $fileUrl);
|
||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode === 200 && $response) {
|
||
if (preg_match('/Content-Length:\s*(\d+)/i', $response, $matches)) {
|
||
return (int)$matches[1];
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
} catch (Exception $e) {
|
||
writeLog("Ошибка получения размера файла: " . $e->getMessage());
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обновляет документ в базе данных напрямую с S3 метаданными
|
||
*/
|
||
function updateDocumentS3Metadata($documentId, $s3Info, $fileSize, $originalFileName) {
|
||
global $adb;
|
||
|
||
try {
|
||
writeLog("Обновляем S3 метаданные для документа $documentId");
|
||
writeLog("S3 Bucket: {$s3Info['bucket']}, Key: {$s3Info['key']}, Size: $fileSize");
|
||
|
||
$updateQuery = "
|
||
UPDATE vtiger_notes
|
||
SET
|
||
filename = ?,
|
||
filelocationtype = 'E',
|
||
filesize = ?,
|
||
s3_bucket = ?,
|
||
s3_key = ?,
|
||
s3_etag = ''
|
||
WHERE notesid = ?
|
||
";
|
||
|
||
// Создаем полный S3 URL для отображения в CRM
|
||
$s3Url = "https://s3.twcstorage.ru/{$s3Info['bucket']}/{$s3Info['key']}";
|
||
|
||
// Очищаем URL от HTML тегов (защита от <br> и других тегов)
|
||
$s3Url = strip_tags(trim($s3Url));
|
||
|
||
$params = [
|
||
$s3Url, // Используем полный S3 URL вместо оригинального имени файла
|
||
$fileSize,
|
||
$s3Info['bucket'],
|
||
$s3Info['key'],
|
||
$documentId
|
||
];
|
||
|
||
writeLog("SQL: $updateQuery");
|
||
writeLog("Params: " . json_encode($params));
|
||
|
||
$result = $adb->pquery($updateQuery, $params);
|
||
|
||
if ($result) {
|
||
writeLog("✅ S3 метаданные успешно обновлены для документа $documentId");
|
||
return true;
|
||
} else {
|
||
writeLog("❌ Ошибка обновления S3 метаданных: " . $adb->database->errorMsg());
|
||
return false;
|
||
}
|
||
|
||
} catch (Exception $e) {
|
||
writeLog("❌ Исключение при обновлении S3 метаданных: " . $e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Функция нормализации входных данных
|
||
function normalizeInputData($data) {
|
||
writeLog('🔍 Нормализация входных данных...');
|
||
|
||
// Новый формат: {"documents": [...], "projectid": "..."}
|
||
if (isset($data['documents']) && isset($data['projectid'])) {
|
||
writeLog('📋 Обнаружен новый формат с массивом documents');
|
||
$filesArray = [];
|
||
foreach ($data['documents'] as $doc) {
|
||
// Определяем projectid - приоритет: projectid, group_session_token, 0
|
||
$projectid = null;
|
||
if (!empty($data['projectid'])) {
|
||
$projectid = (int)$data['projectid'];
|
||
} elseif (!empty($data['group_session_token']) && is_numeric($data['group_session_token'])) {
|
||
$projectid = (int)$data['group_session_token'];
|
||
} elseif (!empty($doc['projectid'])) {
|
||
$projectid = (int)$doc['projectid'];
|
||
} elseif (!empty($doc['group_session_token']) && is_numeric($doc['group_session_token'])) {
|
||
$projectid = (int)$doc['group_session_token'];
|
||
}
|
||
|
||
$normalizedFile = [
|
||
'url' => $doc['file_url'] ?? $doc['url'] ?? '',
|
||
'file_name' => $doc['file_name'] ?? $doc['original_file_name'] ?? '',
|
||
'description' => $doc['upload_description'] ?? $doc['description'] ?? '',
|
||
'projectid' => $projectid,
|
||
'ticket_id' => $data['ticket_id'] ?? $doc['ticket_id'] ?? null, // ✅ Поддержка привязки к заявке
|
||
'user_id' => $data['user_id'] ?? $doc['user_id'] ?? 1,
|
||
'contactid' => $doc['contactid'] ?? $data['contactid'] ?? 0,
|
||
'pages' => $doc['pages'] ?? 0,
|
||
'folder' => $doc['folder'] ?? '',
|
||
'newfile' => $doc['newfile'] ?? '',
|
||
'field_name' => $doc['field_name'] ?? '',
|
||
'prefix' => $doc['prefix'] ?? ''
|
||
];
|
||
$filesArray[] = $normalizedFile;
|
||
writeLog("✅ Нормализован файл: {$normalizedFile['file_name']} (projectid: {$projectid})");
|
||
}
|
||
return $filesArray;
|
||
}
|
||
|
||
// Старый формат: массив файлов напрямую
|
||
if (is_array($data)) {
|
||
writeLog('📋 Обнаружен массив данных');
|
||
|
||
// Проверяем, что это не объект с ключами как поля
|
||
if (isset($data['url']) || isset($data['projectid'])) {
|
||
writeLog('⚠️ Обнаружен объект с ключами полей, преобразуем в массив');
|
||
return [$data];
|
||
}
|
||
|
||
// Проверяем первый элемент массива на наличие projectid или group_session_token
|
||
if (!empty($data) && is_array($data[0])) {
|
||
$firstItem = $data[0];
|
||
|
||
// Если projectid равен null, но есть group_session_token - используем его
|
||
if ((!isset($firstItem['projectid']) || $firstItem['projectid'] === null) &&
|
||
!empty($firstItem['group_session_token']) && is_numeric($firstItem['group_session_token'])) {
|
||
|
||
writeLog('🔄 Обнаружен projectid=null, используем group_session_token как projectid');
|
||
|
||
// Нормализуем каждый элемент массива
|
||
$normalizedArray = [];
|
||
foreach ($data as $item) {
|
||
$normalizedItem = $item;
|
||
$normalizedItem['projectid'] = (int)$item['group_session_token'];
|
||
$normalizedArray[] = $normalizedItem;
|
||
writeLog("✅ Нормализован файл: {$item['file_name']} (projectid: {$normalizedItem['projectid']})");
|
||
}
|
||
return $normalizedArray;
|
||
}
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
// Одиночный объект
|
||
if (is_object($data)) {
|
||
writeLog('📋 Обнаружен одиночный объект файла');
|
||
return [$data];
|
||
}
|
||
|
||
writeLog('❌ Неизвестный формат данных');
|
||
return [];
|
||
}
|
||
|
||
// Основная функция для создания документов
|
||
function createDocumentsInCRM($filesArray, $userName = 'api') {
|
||
global $adb, $current_user;
|
||
|
||
writeLog('🚀 Начинаем создание документов...');
|
||
|
||
// 1. Получаем access key пользователя
|
||
$rs = $adb->pquery('SELECT id, accesskey FROM vtiger_users WHERE user_name=?', [$userName]);
|
||
if (!$rs || $adb->num_rows($rs) == 0) {
|
||
writeLog("❌ Пользователь $userName не найден");
|
||
return ['error' => "Пользователь $userName не найден"];
|
||
}
|
||
$userId = $adb->query_result($rs, 0, 'id');
|
||
$accessKey = $adb->query_result($rs, 0, 'accesskey');
|
||
|
||
// 2. Получаем challenge token
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
|
||
$endpointUrl = 'https://crm.clientright.ru/webservice.php';
|
||
|
||
// getchallenge
|
||
curl_setopt($ch, CURLOPT_URL, $endpointUrl . '?operation=getchallenge&username=' . urlencode($userName));
|
||
$resp = curl_exec($ch);
|
||
if ($resp === false) {
|
||
writeLog('❌ CURL error: ' . curl_error($ch));
|
||
return ['error' => 'Network error'];
|
||
}
|
||
|
||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$challenge = json_decode($resp, true);
|
||
if (!$challenge || empty($challenge['result']['token'])) {
|
||
writeLog('❌ Invalid challenge response: ' . substr($resp, 0, 100));
|
||
return ['error' => 'Authentication failed'];
|
||
}
|
||
$token = $challenge['result']['token'];
|
||
|
||
// 3. Логинимся
|
||
$key = md5($token . $accessKey);
|
||
curl_setopt($ch, CURLOPT_URL, $endpointUrl);
|
||
curl_setopt($ch, CURLOPT_POST, 1);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'operation' => 'login',
|
||
'username' => $userName,
|
||
'accessKey' => $key,
|
||
]);
|
||
$resp = curl_exec($ch);
|
||
if ($resp === false) {
|
||
writeLog('❌ CURL error: ' . curl_error($ch));
|
||
return ['error' => 'Network error'];
|
||
}
|
||
|
||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$login = json_decode($resp, true);
|
||
if (!$login || empty($login['result']['sessionName'])) {
|
||
writeLog('❌ Login failed: ' . substr($resp, 0, 100));
|
||
return ['error' => 'Authentication failed'];
|
||
}
|
||
$sessionId = $login['result']['sessionName'];
|
||
|
||
// 4. Устанавливаем current_user для CRMEntity
|
||
$current_user = new Users();
|
||
$current_user->retrieveCurrentUserInfoFromFile((int)$userId);
|
||
|
||
// 5. Создаём документы
|
||
$results = [];
|
||
foreach ($filesArray as $i => $f) {
|
||
writeLog("📄 Обрабатываем файл #{$i}: " . ($f['file_name'] ?? 'Unknown'));
|
||
|
||
try {
|
||
// Валидация обязательных полей
|
||
if (empty($f['url'])) {
|
||
throw new Exception("Отсутствует URL файла");
|
||
}
|
||
if (empty($f['file_name'])) {
|
||
throw new Exception("Отсутствует имя файла");
|
||
}
|
||
if (empty($f['projectid'])) {
|
||
throw new Exception("Отсутствует ID проекта");
|
||
}
|
||
if (empty($f['description'])) {
|
||
$f['description'] = $f['file_name']; // Используем имя файла как описание
|
||
writeLog("⚠️ Отсутствует описание, используем имя файла");
|
||
}
|
||
|
||
// Получаем WS ID проекта
|
||
$projectWsId = getProjectWsIdFromDB((int)$f['projectid']);
|
||
if (!$projectWsId) {
|
||
throw new Exception("Не найден Project ID {$f['projectid']}");
|
||
}
|
||
|
||
// WS ID пользователя
|
||
$usersPrefix = getUserWsPrefix();
|
||
$assignedUserWsId = $usersPrefix . 'x' . (int)$f['user_id'];
|
||
|
||
// Папка (сначала Суд, потом Default)
|
||
$folderWsId = getFolderWsIdByName('Суд');
|
||
if (!$folderWsId) {
|
||
$folderWsId = '22x1';
|
||
writeLog("⚠️ Папка 'Суд' не найдена, используем Default");
|
||
}
|
||
|
||
// Парсим S3 URL для получения метаданных
|
||
$s3Info = parseS3Url($f['url']);
|
||
if (!$s3Info) {
|
||
throw new Exception("Не удалось распарсить S3 URL: " . $f['url']);
|
||
}
|
||
|
||
writeLog("🔍 S3 Bucket: {$s3Info['bucket']}, Key: {$s3Info['key']}");
|
||
|
||
// Получаем размер файла из S3
|
||
$fileSize = getS3FileSize($f['url']);
|
||
writeLog("📏 Размер файла: " . number_format($fileSize) . " байт");
|
||
|
||
// Создаём документ (webservice не поддерживает S3 метаданные напрямую)
|
||
$docElement = [
|
||
'notes_title' => $f['description'] ?: $f['file_name'],
|
||
'filename' => $f['file_name'], // Оригинальное имя файла
|
||
'assigned_user_id' => $assignedUserWsId,
|
||
'notecontent' => 'Авто из S3. Контакт: ' . ($f['contactid'] ?? '') . ' | URL: ' . $f['url'],
|
||
'filetype' => 'application/pdf',
|
||
'filesize' => (string)$fileSize,
|
||
'filelocationtype' => 'E', // External URL
|
||
'fileversion' => '1.0',
|
||
'filestatus' => '1', // Active
|
||
'folderid' => $folderWsId,
|
||
];
|
||
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'operation' => 'create',
|
||
'sessionName' => $sessionId,
|
||
'elementType' => 'Documents',
|
||
'element' => json_encode($docElement, JSON_UNESCAPED_UNICODE),
|
||
]);
|
||
$resp = curl_exec($ch);
|
||
if ($resp === false) {
|
||
throw new Exception('CURL error: ' . curl_error($ch));
|
||
}
|
||
|
||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$doc = json_decode($resp, true);
|
||
if (!$doc || empty($doc['result']['id'])) {
|
||
throw new Exception('Failed to create document: ' . substr($resp, 0, 100));
|
||
}
|
||
$documentWsId = $doc['result']['id'];
|
||
list(, $docNumericId) = explode('x', $documentWsId, 2);
|
||
|
||
writeLog("✅ Документ создан: $documentWsId (numeric: $docNumericId)");
|
||
|
||
// ВАЖНО: Обновляем S3 метаданные напрямую в базе данных
|
||
$s3UpdateSuccess = updateDocumentS3Metadata($docNumericId, $s3Info, $fileSize, $f['file_name']);
|
||
|
||
// Определяем к чему привязываем: к HelpDesk (заявке) или к Project (проекту)
|
||
$ticketId = isset($f['ticket_id']) ? (int)$f['ticket_id'] : null;
|
||
|
||
if ($ticketId) {
|
||
// Привязываем к HelpDesk (заявке)
|
||
writeLog("📎 Привязываем к HelpDesk ticket_id: $ticketId");
|
||
|
||
// Получаем WS ID для HelpDesk
|
||
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['HelpDesk']);
|
||
$helpdeskPrefix = ($rs && $adb->num_rows($rs) > 0) ? $adb->query_result($rs, 0, 'id') : 17;
|
||
$ticketWsId = $helpdeskPrefix . 'x' . $ticketId;
|
||
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'operation' => 'AddRelated',
|
||
'sessionName' => $sessionId,
|
||
'sourceRecordId' => $ticketWsId,
|
||
'relatedRecordId' => $documentWsId,
|
||
]);
|
||
$resp = curl_exec($ch);
|
||
|
||
// Проверяем успех AddRelated
|
||
$ok = false;
|
||
if ($resp !== false) {
|
||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$rel = json_decode($resp, true);
|
||
$ok = isset($rel['result']['message']) && $rel['result']['message'] === 'successfull';
|
||
}
|
||
|
||
// Если webservice не сработал - используем прямую привязку
|
||
if (!$ok) {
|
||
writeLog("⚠️ AddRelated к HelpDesk не сработал, используем прямую привязку");
|
||
require_once 'data/CRMEntity.php';
|
||
require_once 'modules/Vtiger/CRMEntity.php';
|
||
$focus = CRMEntity::getInstance('HelpDesk');
|
||
relateEntities($focus, 'HelpDesk', $ticketId, 'Documents', (int)$docNumericId);
|
||
}
|
||
|
||
writeLog("✅ Документ привязан к HelpDesk #$ticketId");
|
||
} else {
|
||
// Привязываем к проекту (старая логика)
|
||
writeLog("📎 Привязываем к Project project_id: {$f['projectid']}");
|
||
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'operation' => 'AddRelated',
|
||
'sessionName' => $sessionId,
|
||
'sourceRecordId' => $projectWsId,
|
||
'relatedRecordId' => $documentWsId,
|
||
]);
|
||
$resp = curl_exec($ch);
|
||
|
||
// Проверяем успех AddRelated
|
||
$ok = false;
|
||
if ($resp !== false) {
|
||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$rel = json_decode($resp, true);
|
||
$ok = isset($rel['result']['message']) && $rel['result']['message'] === 'successfull';
|
||
}
|
||
|
||
// Если webservice не сработал - используем прямую привязку
|
||
if (!$ok) {
|
||
writeLog("⚠️ AddRelated не сработал, используем прямую привязку");
|
||
require_once 'data/CRMEntity.php';
|
||
require_once 'modules/Vtiger/CRMEntity.php';
|
||
list(, $docNumericId) = explode('x', $documentWsId, 2);
|
||
$focus = CRMEntity::getInstance('Project');
|
||
relateEntities($focus, 'Project', (int)$f['projectid'], 'Documents', (int)$docNumericId);
|
||
}
|
||
|
||
writeLog("✅ Документ привязан к Project #{$f['projectid']}");
|
||
}
|
||
|
||
// Возвращаем все входные данные + результат
|
||
$result = array_merge($f, [
|
||
'status' => 'success',
|
||
'crm_result' => [
|
||
'document_id' => $documentWsId,
|
||
'document_numeric_id' => $docNumericId,
|
||
'project_id' => $f['projectid'],
|
||
'folder_id' => $folderWsId,
|
||
's3_bucket' => $s3Info['bucket'],
|
||
's3_key' => $s3Info['key'],
|
||
'file_size' => $fileSize,
|
||
's3_metadata_updated' => $s3UpdateSuccess,
|
||
'message' => 'Документ создан с правильными S3 метаданными и привязан к проекту' . (!$ok ? ' (прямая привязка)' : '')
|
||
]
|
||
]);
|
||
|
||
$results[] = $result;
|
||
writeLog("✅ Документ {$f['file_name']} успешно создан и привязан");
|
||
|
||
} catch (Exception $e) {
|
||
writeLog("❌ Ошибка для файла {$f['file_name']}: " . $e->getMessage());
|
||
// В случае ошибки тоже возвращаем все входные данные
|
||
$results[] = array_merge($f, [
|
||
'status' => 'error',
|
||
'crm_result' => [
|
||
'message' => $e->getMessage()
|
||
]
|
||
]);
|
||
}
|
||
}
|
||
|
||
curl_close($ch);
|
||
return $results;
|
||
}
|
||
|
||
// Обработка запроса
|
||
if ($IS_POST) {
|
||
writeLog('=== START POST REQUEST ===');
|
||
writeLog('Headers: ' . json_encode(getallheaders(), JSON_UNESCAPED_UNICODE));
|
||
|
||
// Получаем и проверяем входные данные
|
||
$input = file_get_contents('php://input');
|
||
writeLog('Raw input: ' . substr($input, 0, 1000) . (strlen($input) > 1000 ? '...(truncated)' : ''));
|
||
|
||
$input = ltrim($input, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||
$data = 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);
|
||
}
|
||
|
||
writeLog('Parsed data: ' . json_encode($data, JSON_UNESCAPED_UNICODE));
|
||
|
||
// Нормализуем формат данных
|
||
$filesArray = normalizeInputData($data);
|
||
|
||
// Проверяем массив
|
||
if (!is_array($filesArray)) {
|
||
writeLog('❌ Error: Input is not an array');
|
||
json_response([
|
||
'success' => false,
|
||
'error' => ['message' => 'Input must be an array of files']
|
||
], 400);
|
||
}
|
||
|
||
writeLog('Processing ' . count($filesArray) . ' files...');
|
||
|
||
// Создаём документы
|
||
$results = createDocumentsInCRM($filesArray);
|
||
|
||
// Проверяем результат
|
||
if (isset($results['error'])) {
|
||
writeLog('❌ Error: ' . $results['error']);
|
||
json_response([
|
||
'success' => false,
|
||
'error' => ['message' => $results['error']]
|
||
], 500);
|
||
}
|
||
|
||
// Успешный ответ
|
||
writeLog('✅ Success: processed ' . count($results) . ' files');
|
||
json_response([
|
||
'success' => true,
|
||
'total_processed' => count($filesArray),
|
||
'results' => $results
|
||
]);
|
||
|
||
} else {
|
||
// GET запрос - тестовый режим
|
||
$testData = [
|
||
[
|
||
'session_token' => 'sess_test',
|
||
'group_session_token' => 'token_test',
|
||
'user_id' => 1,
|
||
'group' => 'group_0',
|
||
'contactid' => 120374,
|
||
'files_count' => 2,
|
||
'group_index_num' => 0,
|
||
'description' => 'Иск',
|
||
'projectid' => 354918,
|
||
'telegram_id' => 295410106,
|
||
'unified_id' => 'usr_test',
|
||
'pages' => 2,
|
||
'url' => 'https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/120374/1757346451126.pdf',
|
||
'file_name' => '1757346451126.pdf',
|
||
'field_name' => '120374',
|
||
'folder' => 'clientright/120374',
|
||
'newfile' => 'clientright/120374/1757346451126.pdf'
|
||
]
|
||
];
|
||
|
||
$results = createDocumentsInCRM($testData);
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
echo json_encode([
|
||
'success' => true,
|
||
'total_processed' => count($testData),
|
||
'results' => $results
|
||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||
}
|
||
?>
|