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

392 lines
18 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
/**
* Создание события в календаре CRM для судебного заседания (версия 2 - через SQL)
*
* Принимает POST запрос с данными:
* - project_id: ID проекта (обязательно)
* - event_name: Название события
* - event_date: Дата события (формат DD.MM.YYYY)
* - event_time: Время события (формат HH:MM)
* - location: Место проведения
* - result: Результат события
* - basis: Основание
* - note: Примечание
* - publication_date: Дата размещения
*/
// Устанавливаем рабочую директорию
chdir(__DIR__);
// Логирование
function log_event($level, $message) {
$log_file = 'logs/create_court_event.log';
$timestamp = date('Y-m-d H:i:s');
$log_entry = "{$timestamp} - {$level}: {$message}\n";
file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
}
// Функция для форматирования даты в формат CRM (YYYY-MM-DD)
function formatDateForCRM($dateString) {
if (empty($dateString)) {
return '';
}
// Если формат DD.MM.YYYY
if (preg_match('/^(\d{2})\.(\d{2})\.(\d{4})$/', $dateString, $matches)) {
return $matches[3] . '-' . $matches[2] . '-' . $matches[1];
}
// Если уже в формате YYYY-MM-DD
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateString)) {
return $dateString;
}
return $dateString;
}
// Функция для форматирования времени в формат CRM (HH:MM:SS)
function formatTimeForCRM($timeString) {
if (empty($timeString)) {
return '10:00:00'; // Время по умолчанию
}
// Если формат HH:MM
if (preg_match('/^(\d{1,2}):(\d{2})$/', $timeString, $matches)) {
return sprintf('%02d:%02d:00', $matches[1], $matches[2]);
}
// Если уже в формате HH:MM:SS
if (preg_match('/^\d{2}:\d{2}:\d{2}$/', $timeString)) {
return $timeString;
}
return '10:00:00';
}
try {
$scriptStartTime = microtime(true);
log_event('INFO', '=== НАЧАЛО ОБРАБОТКИ ЗАПРОСА ===');
$timePoint = microtime(true);
// Получаем данные из stdin (для CLI вызова)
$input = file_get_contents('php://stdin');
$timeAfterStdin = microtime(true);
if ($timeAfterStdin - $timePoint > 0.1) {
log_event('DEBUG', "Чтение stdin заняло: " . round(($timeAfterStdin - $timePoint) * 1000, 2) . " мс");
}
if (!empty($input)) {
log_event('DEBUG', "Входные данные из stdin: " . $input);
$data = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('Ошибка декодирования JSON: ' . json_last_error_msg());
}
} else {
// Для HTTP запросов: сначала пробуем php://input (для JSON)
$timeBeforeInput = microtime(true);
$rawInput = file_get_contents('php://input');
$timeAfterInput = microtime(true);
$inputReadTime = ($timeAfterInput - $timeBeforeInput) * 1000;
log_event('DEBUG', "Чтение php://input заняло: " . round($inputReadTime, 2) . " мс");
if (!empty($rawInput)) {
log_event('DEBUG', "Входные данные из php://input (первые 200 символов): " . substr($rawInput, 0, 200));
$timeBeforeJson = microtime(true);
$data = json_decode($rawInput, true);
$timeAfterJson = microtime(true);
$jsonDecodeTime = ($timeAfterJson - $timeBeforeJson) * 1000;
log_event('DEBUG', "Декодирование JSON заняло: " . round($jsonDecodeTime, 2) . " мс");
if (json_last_error() !== JSON_ERROR_NONE) {
// Если не JSON, пробуем как обычный POST
parse_str($rawInput, $data);
log_event('DEBUG', "Данные распарсены как form-data");
} else {
log_event('DEBUG', "Данные распарсены как JSON");
}
} else {
// Если php://input пустой, используем $_POST (для form-data)
$data = $_POST;
log_event('DEBUG', "Используем \$_POST: " . json_encode($data, JSON_UNESCAPED_UNICODE));
}
}
$timeAfterParsing = microtime(true);
log_event('DEBUG', "Время до парсинга данных: " . round(($timeAfterParsing - $scriptStartTime) * 1000, 2) . " мс");
// Распаковываем данные из last_event, если они там есть (для совместимости с n8n)
if (isset($data['last_event']) && is_array($data['last_event'])) {
log_event('DEBUG', "Обнаружен объект last_event, распаковываем данные");
$lastEvent = $data['last_event'];
// Извлекаем данные события из last_event (приоритет)
$eventName = $lastEvent['event_name'] ?? $lastEvent['Наименование'] ?? $data['event_name'] ?? 'Судебное заседание';
$eventDate = $lastEvent['event_date'] ?? $lastEvent['Дата'] ?? $data['event_date'] ?? '';
$eventTime = $lastEvent['event_time'] ?? $lastEvent['Время'] ?? $data['event_time'] ?? '';
$location = $lastEvent['location'] ?? $lastEvent['Место'] ?? $data['location'] ?? '';
$result = $lastEvent['event_result'] ?? $lastEvent['Результат'] ?? $data['result'] ?? '';
$basis = $lastEvent['event_basis'] ?? $lastEvent['Основание'] ?? $data['basis'] ?? '';
$note = $lastEvent['note'] ?? $lastEvent['Примечание'] ?? $data['note'] ?? '';
$publicationDate = $lastEvent['publication_date'] ?? $lastEvent['Дата размещения'] ?? $data['publication_date'] ?? '';
log_event('DEBUG', "Данные распакованы из last_event: event_name='$eventName', event_date='$eventDate'");
} else {
// Данные уже в корне (обычный формат)
$eventName = $data['event_name'] ?? 'Судебное заседание';
$eventDate = $data['event_date'] ?? '';
$eventTime = $data['event_time'] ?? '';
$location = $data['location'] ?? '';
$result = $data['result'] ?? '';
$basis = $data['basis'] ?? '';
$note = $data['note'] ?? '';
$publicationDate = $data['publication_date'] ?? '';
}
// Проверяем обязательные параметры
if (empty($data['project_id'])) {
throw new Exception('Параметр project_id обязателен');
}
$projectId = intval($data['project_id']);
log_event('INFO', "Создаем событие для проекта: $projectId");
log_event('DEBUG', "Название: '$eventName', Дата: '$eventDate', Время: '$eventTime'");
log_event('DEBUG', "Полные входные данные: " . json_encode($data, JSON_UNESCAPED_UNICODE));
// Проверяем что дата не пустая
if (empty($eventDate)) {
throw new Exception('Дата события обязательна');
}
// Подключаемся к базе данных
$timeBeforeDb = microtime(true);
// Устанавливаем таймауты для быстрого подключения
ini_set('default_socket_timeout', 5); // Таймаут подключения 5 секунд
$mysqli = new mysqli('localhost', 'ci20465_72new', 'EcY979Rn', 'ci20465_72new');
$timeAfterDbConnect = microtime(true);
$dbConnectTime = ($timeAfterDbConnect - $timeBeforeDb) * 1000;
log_event('DEBUG', "Подключение к БД заняло: " . round($dbConnectTime, 2) . " мс");
if ($mysqli->connect_error) {
throw new Exception('Не удалось подключиться к БД: ' . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5); // Таймаут подключения 5 секунд
$mysqli->options(MYSQLI_OPT_READ_TIMEOUT, 10); // Таймаут чтения 10 секунд
// Получаем данные проекта
$query = "SELECT e.smownerid, p.projectname, p.linktoaccountscontacts FROM vtiger_crmentity e
JOIN vtiger_project p ON p.projectid = e.crmid
WHERE e.crmid = ? AND e.deleted = 0";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i', $projectId);
$stmt->execute();
$result_query = $stmt->get_result();
if ($result_query->num_rows === 0) {
throw new Exception("Проект $projectId не найден");
}
$row = $result_query->fetch_assoc();
$ownerId = $row['smownerid'];
$projectName = $row['projectname'];
$contactId = $row['linktoaccountscontacts'] ?? null;
log_event('DEBUG', "Владелец проекта: $ownerId, Название: $projectName, Контакт: " . ($contactId ?? 'нет'));
// Форматируем дату и время для CRM
$formattedDate = formatDateForCRM($eventDate);
$formattedTime = formatTimeForCRM($eventTime);
$formattedDateTime = $formattedDate . ' ' . $formattedTime;
// Вычисляем время окончания (+1 час)
$endDateTime = date('Y-m-d H:i:s', strtotime($formattedDateTime) + 3600);
log_event('DEBUG', "Дата начала: $formattedDateTime, Дата окончания: $endDateTime");
// Определяем тип события и статус - используем настройки как в workflow 3 (блок 18)
$activityType = 'судебное заседание';
$eventstatus = 'Planned'; // Запланировано (как в workflow)
log_event('DEBUG', "Установлен тип 'судебное заседание' и статус 'Planned' (как в workflow 3)");
// Формируем тему события с названием проекта
$eventSubject = $eventName;
if (!empty($projectName)) {
$eventSubject = "[$projectName] $eventName";
}
log_event('DEBUG', "Тип события: $activityType, Статус: $eventstatus, Тема: $eventSubject");
// Формируем описание события
$description = "Автоматически созданное событие из судебного дела\n\n";
if (!empty($location)) {
$description .= "Место: $location\n";
}
if (!empty($result)) {
$description .= "Результат: $result\n";
}
if (!empty($basis)) {
$description .= "Основание: $basis\n";
}
if (!empty($note)) {
$description .= "Примечание: $note\n";
}
if (!empty($publicationDate)) {
$description .= "Дата размещения: $publicationDate\n";
}
// Получаем следующий ID
$result_id = $mysqli->query("SELECT MAX(crmid) as max_id FROM vtiger_crmentity");
$row_id = $result_id->fetch_assoc();
$eventId = ($row_id['max_id'] ?? 0) + 1;
log_event('DEBUG', "Новый ID события: $eventId");
$created_time = date('Y-m-d H:i:s');
// Создаем запись в vtiger_crmentity
$sql = "INSERT INTO vtiger_crmentity (crmid, smcreatorid, smownerid, modifiedby, setype, description, createdtime, modifiedtime, presence, deleted, label)
VALUES (?, ?, ?, ?, 'Calendar', ?, ?, ?, 1, 0, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('iiiissss', $eventId, $ownerId, $ownerId, $ownerId, $description, $created_time, $created_time, $eventSubject);
$stmt->execute();
log_event('DEBUG', "Запись в vtiger_crmentity создана");
// Создаем запись в vtiger_activity
$visibility = 'Public';
$endTime = date('H:i:s', strtotime($formattedDateTime) + 3600);
$sql = "INSERT INTO vtiger_activity (activityid, subject, activitytype, date_start, time_start, due_date, time_end, location, visibility, eventstatus)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('isssssssss', $eventId, $eventSubject, $activityType, $formattedDate, $formattedTime, $formattedDate,
$endTime, $location, $visibility, $eventstatus);
$stmt->execute();
log_event('DEBUG', "Запись в vtiger_activity создана");
// Связываем событие с проектом (vtiger_seactivityrel)
$sql = "INSERT INTO vtiger_seactivityrel (crmid, activityid) VALUES (?, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ii', $projectId, $eventId);
$stmt->execute();
log_event('SUCCESS', "Событие привязано к проекту в vtiger_seactivityrel");
// Связываем событие с проектом через общую таблицу связей (vtiger_crmentityrel)
// Это ключевая связь для отображения события в интерфейсе проекта!
$sql = "INSERT INTO vtiger_crmentityrel (crmid, module, relcrmid, relmodule) VALUES (?, 'Project', ?, 'Calendar')";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ii', $projectId, $eventId);
$stmt->execute();
log_event('SUCCESS', "Событие привязано к проекту в vtiger_crmentityrel (для отображения в UI)");
// Связываем событие с контактом (если контакт указан в проекте)
if (!empty($contactId) && $contactId > 0) {
$sql = "INSERT INTO vtiger_cntactivityrel (contactid, activityid) VALUES (?, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ii', $contactId, $eventId);
$stmt->execute();
log_event('SUCCESS', "Событие привязано к контакту: $contactId");
} else {
log_event('DEBUG', "Контакт не указан в проекте, пропускаем связывание");
}
// Обновляем поля проекта с информацией о последнем событии
try {
// Формируем описание для cf_2496
$cf2496Description = $eventSubject;
if (!empty($result) && trim($result) !== '') {
// Очищаем результат от лишних пробелов и дефисов
$cleanResult = trim($result);
$cf2496Description .= " - $cleanResult";
}
$sql = "UPDATE vtiger_projectcf SET cf_1682 = ?, cf_1684 = ?, cf_2496 = ? WHERE projectid = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('sssi', $formattedDate, $formattedTime, $cf2496Description, $projectId);
$stmt->execute();
log_event('SUCCESS', "Поля проекта обновлены (cf_1682, cf_1684, cf_2496)");
log_event('DEBUG', "cf_2496 установлен: $cf2496Description");
} catch (Exception $e) {
log_event('WARNING', "Не удалось обновить поля проекта: " . $e->getMessage());
}
// Обновляем последовательность
$mysqli->query("UPDATE vtiger_crmentity_seq SET id = $eventId");
$mysqli->close();
// Формируем успешный ответ
$response = [
'success' => true,
'event_id' => '4x' . $eventId,
'event_numeric_id' => $eventId,
'event_name' => $eventName,
'event_date' => $formattedDate,
'event_time' => $formattedTime,
'project_id' => $projectId,
'message' => 'Событие успешно создано и привязано к проекту'
];
$totalTime = (microtime(true) - $scriptStartTime) * 1000;
log_event('SUCCESS', "=== ОБРАБОТКА ЗАВЕРШЕНА УСПЕШНО ===");
log_event('SUCCESS', "Событие создано: 4x$eventId");
log_event('INFO', "Общее время выполнения: " . round($totalTime, 2) . " мс");
// Отключаем буферизацию для немедленной отправки ответа
if (ob_get_level()) {
ob_end_clean();
}
header('Content-Type: application/json; charset=utf-8');
$timeBeforeOutput = microtime(true);
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
$timeAfterOutput = microtime(true);
log_event('DEBUG', "Отправка ответа заняла: " . round(($timeAfterOutput - $timeBeforeOutput) * 1000, 2) . " мс");
// Принудительно отправляем ответ и завершаем выполнение
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
exit(0);
} catch (Exception $e) {
$error_message = $e->getMessage();
log_event('ERROR', "Ошибка: $error_message");
$response = [
'success' => false,
'error' => $error_message,
'timestamp' => date('Y-m-d H:i:s')
];
// Отключаем буферизацию для немедленной отправки ответа
if (ob_get_level()) {
ob_end_clean();
}
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// Принудительно отправляем ответ и завершаем выполнение
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
exit(1);
}
?>