feat: Интеграция уведомлений для событий судов

- Добавлена поддержка project_id в parscourt.php для создания уведомлений
- Создана система парсеров судов (BaseCourtParser, MoscowCourtParser, RegionalCourtParser)
- Интегрирован Browserless для парсинга московских судов (mos-sud.ru, mos-gorsud.ru)
- Добавлены уведомления VDNotifierPro при обнаружении новых событий судов
- Создан ParseAndCreateEvent.php для интеграции с CRM workflow
- Создан CreateCourtEvent_v2.php для прямого создания событий в календаре CRM
- Поддержка проверки дубликатов событий (можно отключить для тестирования)
- Автоматическое определение типа суда и выбор подходящего парсера

Функции:
- Парсинг региональных судов (*.sudrf.ru) через HTML
- Парсинг московских судов через Browserless API
- Создание событий в CRM календаре с привязкой к проектам
- Уведомления ответственных пользователей о новых событиях
- Сохранение событий в таблицу subject для истории
This commit is contained in:
Fedor
2025-10-17 19:45:11 +03:00
parent 4721a04114
commit 3db9d06c86
7 changed files with 1450 additions and 89 deletions

305
CreateCourtEvent_v2.php Normal file
View File

@@ -0,0 +1,305 @@
<?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 {
log_event('INFO', '=== НАЧАЛО ОБРАБОТКИ ЗАПРОСА ===');
// Получаем данные из stdin
$input = file_get_contents('php://stdin');
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 {
// Если stdin пустой, используем $_POST
$data = $_POST;
log_event('DEBUG', "Используем \$_POST: " . json_encode($data, JSON_UNESCAPED_UNICODE));
}
// Проверяем обязательные параметры
if (empty($data['project_id'])) {
throw new Exception('Параметр project_id обязателен');
}
$projectId = intval($data['project_id']);
// Извлекаем данные события
$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'] ?? '';
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('Дата события обязательна');
}
// Подключаемся к базе данных
$mysqli = new mysqli('localhost', 'ci20465_72new', 'EcY979Rn', 'ci20465_72new');
if ($mysqli->connect_error) {
throw new Exception('Не удалось подключиться к БД: ' . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
// Получаем данные проекта
$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' => 'Событие успешно создано и привязано к проекту'
];
log_event('SUCCESS', "=== ОБРАБОТКА ЗАВЕРШЕНА УСПЕШНО ===");
log_event('SUCCESS', "Событие создано: 4x$eventId");
header('Content-Type: application/json; charset=utf-8');
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
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')
];
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit(1);
}
?>