Files
crm.clientright.ru/attach_documents_to_crm.php
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

282 lines
11 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
/**
* API для привязки документов к проекту/заявке
*
* Использование из n8n:
* POST https://crm.clientright.ru/api_attach_documents.php
*
* Входные данные (JSON массив):
* [
* {
* "contact_id": "320096",
* "project_id": "396868",
* "ticket_id": "396936",
* "filename": "boarding_pass.pdf",
* "file_type": "flight_delay_boarding_or_ticket",
* "file": "/bucket/path/to/file.pdf"
* }
* ]
*/
error_reporting(E_ALL);
ini_set('display_errors', '0');
// Функция для логирования
function log_message($message) {
$timestamp = date('Y-m-d H:i:s');
$line = "[$timestamp] $message\n";
@file_put_contents(__DIR__ . '/logs/api_attach_documents.log', $line, FILE_APPEND | LOCK_EX);
error_log('[api_attach_documents] ' . $message);
}
// Функция для JSON ответа
function json_response($data, $code = 200) {
if (!headers_sent()) {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
}
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
// CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
json_response(['status' => 'ok']);
}
// Только POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
json_response(['success' => false, 'error' => 'Method not allowed'], 405);
}
log_message('=== START API REQUEST ===');
log_message('Host: ' . ($_SERVER['HTTP_HOST'] ?? 'not set'));
log_message('SERVER_NAME: ' . ($_SERVER['SERVER_NAME'] ?? 'not set'));
log_message('REQUEST_URI: ' . ($_SERVER['REQUEST_URI'] ?? 'not set'));
// Проверяем, что запрос идёт на правильный домен
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';
if (!empty($host) && strpos($host, 'crm.clientright.ru') === false && strpos($host, 'aeroflot.clientright.ru') !== false) {
log_message('⚠️ WARNING: Request came to wrong virtual host: ' . $host);
// Не блокируем, но логируем для диагностики
}
// Получаем входные данные
$input = file_get_contents('php://input');
log_message('Raw input: ' . substr($input, 0, 500));
$input = ltrim($input, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
$data = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
log_message('❌ JSON Error: ' . json_last_error_msg());
json_response([
'success' => false,
'error' => 'Invalid JSON: ' . json_last_error_msg()
], 400);
}
// Поддерживаем как массив, так и одиночный объект
$documents_array = is_array($data) && isset($data[0]) ? $data : [$data];
log_message('Processing ' . count($documents_array) . ' document(s)');
// Обрабатываем каждый документ
$processed_documents = [];
$S3_HOST = 'https://s3.twcstorage.ru';
foreach ($documents_array as $idx => $doc) {
$contact_id = $doc['contact_id'] ?? null;
$project_id = $doc['project_id'] ?? null;
$ticket_id = $doc['ticket_id'] ?? null;
// Поддерживаем оба формата: file и file_url
$file_path = $doc['file'] ?? $doc['file_url'] ?? null;
if (!$file_path) {
log_message("❌ Document #{$idx}: missing 'file' or 'file_url'");
continue;
}
// Строим полный S3 URL
if (strpos($file_path, 'http') === 0) {
$file_url = $file_path;
} elseif (strpos($file_path, '/') === 0) {
$file_url = $S3_HOST . $file_path;
} else {
$file_url = $S3_HOST . '/' . $file_path;
}
// Поддерживаем оба формата: filename и file_name
$file_name = $doc['filename'] ?? $doc['file_name'] ?? null;
if (!$file_name) {
log_message("❌ Document #{$idx}: missing 'filename' or 'file_name'");
continue;
}
$file_type = $doc['file_type'] ?? 'Документ';
// Валидация обязательных полей
if (!$contact_id || !$project_id) {
log_message("❌ Document #{$idx}: missing contact_id or project_id");
continue;
}
log_message(" [{$idx}] {$file_name} (type: {$file_type})");
log_message(" Contact: {$contact_id}, Project: {$project_id}, Ticket: " . ($ticket_id ?: 'N/A'));
log_message(" File URL: {$file_url}");
$processed_documents[] = [
'url' => $file_url,
'file_name' => $file_name,
'description' => $file_type,
'projectid' => (int)$project_id,
'ticket_id' => $ticket_id ? (int)$ticket_id : null,
'contactid' => (int)$contact_id,
'pages' => 1
];
}
if (empty($processed_documents)) {
log_message('❌ No valid documents to process');
json_response([
'success' => false,
'error' => 'No valid documents to process'
], 400);
}
log_message('📤 Processing ' . count($processed_documents) . ' documents via upload_documents_to_crm.php');
// ✅ Вызываем upload_documents_to_crm.php напрямую через include (избегаем проблем с HTTP/Nginx)
// Берем общие параметры из первого документа
$first_doc = $processed_documents[0];
// Формируем данные в формате, который ожидает upload_documents_to_crm.php
$upload_data = [
'documents' => $processed_documents,
'projectid' => $first_doc['projectid'],
'ticket_id' => $first_doc['ticket_id'],
'user_id' => 1
];
log_message('Payload: ' . substr(json_encode($upload_data, JSON_UNESCAPED_UNICODE), 0, 500));
// ✅ Вызываем upload_documents_to_crm.php напрямую через include (избегаем проблем с HTTP)
// Загружаем функции из upload_documents_to_crm.php
$upload_script_path = __DIR__ . '/upload_documents_to_crm.php';
// ✅ Перехватываем вывод (на случай, если скрипт что-то выводит)
ob_start();
// ✅ Сохраняем оригинальный REQUEST_METHOD и устанавливаем GET, чтобы предотвратить выполнение основного кода
$original_request_method = $_SERVER['REQUEST_METHOD'] ?? null;
$_SERVER['REQUEST_METHOD'] = 'GET';
// ✅ Загружаем upload_documents_to_crm.php
// Функции будут доступны, но основной код не выполнится, т.к. $IS_POST будет false
try {
require_once $upload_script_path;
// ✅ Восстанавливаем оригинальный REQUEST_METHOD
if ($original_request_method !== null) {
$_SERVER['REQUEST_METHOD'] = $original_request_method;
}
} catch (Throwable $e) {
ob_end_clean();
// ✅ Восстанавливаем оригинальный REQUEST_METHOD даже при ошибке
if ($original_request_method !== null) {
$_SERVER['REQUEST_METHOD'] = $original_request_method;
}
log_message('❌ Fatal error loading upload_documents_to_crm.php: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
json_response([
'success' => false,
'error' => 'Failed to load upload script: ' . $e->getMessage()
], 500);
}
// ✅ Вызываем функцию normalizeInputData для преобразования данных
$filesArray = normalizeInputData($upload_data);
if (!is_array($filesArray) || empty($filesArray)) {
ob_end_clean();
log_message('❌ Error: Failed to normalize input data. Type: ' . gettype($filesArray) . ', Empty: ' . (empty($filesArray) ? 'yes' : 'no'));
json_response([
'success' => false,
'error' => 'Failed to normalize input data'
], 400);
}
// ✅ Вызываем функцию createDocumentsInCRM напрямую
log_message('🚀 Calling createDocumentsInCRM with ' . count($filesArray) . ' files');
$results = createDocumentsInCRM($filesArray);
log_message('🔍 createDocumentsInCRM returned. Type: ' . gettype($results) . ', Is array: ' . (is_array($results) ? 'yes, count: ' . count($results) : 'no'));
// ✅ Очищаем output buffer
ob_end_clean();
// ✅ Проверяем результат
if (isset($results['error'])) {
log_message('❌ Error: ' . $results['error']);
json_response([
'success' => false,
'error' => 'Upload failed: ' . $results['error']
], 500);
}
// ✅ Формируем ответ в формате, который ожидает api_attach_documents.php
// ✅ Проверяем успешность
if (is_array($results) && !empty($results)) {
$results_array = $results;
// Формируем ответ
$processed_results = [];
$errors = [];
foreach ($results_array as $idx => $res) {
$status = $res['status'] ?? 'unknown';
if ($status === 'success') {
$crm_result = $res['crm_result'] ?? [];
$processed_results[] = [
'document_id' => $crm_result['document_id'] ?? null,
'document_numeric_id' => $crm_result['document_numeric_id'] ?? null,
'attached_to' => isset($res['ticket_id']) && $res['ticket_id'] ? 'ticket' : 'project',
'attached_to_id' => $res['ticket_id'] ?? $res['projectid'] ?? null,
'file_name' => $res['file_name'] ?? null,
'file_type' => $res['description'] ?? null,
's3_bucket' => $crm_result['s3_bucket'] ?? null,
's3_key' => $crm_result['s3_key'] ?? null,
'file_size' => $crm_result['file_size'] ?? null,
'message' => $crm_result['message'] ?? null
];
} else {
$error_msg = $res['crm_result']['message'] ?? ($res['error'] ?? 'Unknown error');
$errors[] = [
'file_name' => $res['file_name'] ?? 'Unknown',
'error' => $error_msg
];
}
}
json_response([
'success' => true,
'total_processed' => count($results_array),
'successful' => count($processed_results),
'failed' => count($errors),
'results' => $processed_results,
'errors' => !empty($errors) ? $errors : null
]);
} else {
$error_msg = is_array($results) && isset($results['error']) ? $results['error'] : 'Upload failed';
log_message('❌ Upload failed: ' . (is_string($error_msg) ? $error_msg : json_encode($error_msg)));
json_response([
'success' => false,
'error' => is_string($error_msg) ? $error_msg : 'Upload failed'
], 500);
}