- court_document_parser.py: парсер судебных документов с извлечением ФИО, номера дела, УИД, суда - court_parser_api.py: API для вызова парсера из n8n - pdf_court_parser.py: парсер PDF документов с извлечением текста - simple_project_updater.php: обновление проектов через CRM API - simple_project_updater_v2.php: обновленная версия с прямыми SQL запросами и S3Client - update_project_from_document.php: альтернативный скрипт обновления - test_input.json: тестовые данные для парсера - README файлы с документацией для всех скриптов Скрипты поддерживают: - Поиск проектов по ФИО, номеру дела, УИД, названию суда - Создание документов в CRM с загрузкой в S3 - Привязку документов к проектам - Логирование всех операций - Работу с n8n через SSH команды
369 lines
13 KiB
PHP
Executable File
369 lines
13 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* Скрипт для обновления проекта CRM на основе данных из судебного документа
|
||
*
|
||
* Использование:
|
||
* php update_project_from_document.php '{"content": {...}, "file": "...", "file_name": "..."}'
|
||
*
|
||
* Или через stdin:
|
||
* echo '{"content": {...}}' | php update_project_from_document.php
|
||
*/
|
||
|
||
// Устанавливаем рабочую директорию
|
||
chdir(__DIR__ . '/..');
|
||
|
||
require_once 'config.inc.php';
|
||
require_once 'include/utils/utils.php';
|
||
require_once 'include/utils/CommonUtils.php';
|
||
require_once 'modules/Vtiger/models/Record.php';
|
||
|
||
class ProjectUpdater {
|
||
private $adb;
|
||
private $current_user;
|
||
|
||
public function __construct() {
|
||
global $adb;
|
||
$this->adb = $adb;
|
||
|
||
// Получаем системного пользователя
|
||
$this->current_user = Users::getActiveAdminUser();
|
||
}
|
||
|
||
/**
|
||
* Поиск проекта по данным из документа
|
||
*/
|
||
public function findProject($content) {
|
||
$plaintiff_fio = $content['plaintiff_fio'] ?? '';
|
||
$case_number = $content['case_number'] ?? '';
|
||
$uid = $content['uid'] ?? '';
|
||
|
||
// Поиск по ФИО истца
|
||
if ($plaintiff_fio) {
|
||
$sql = "SELECT p.projectid, p.projectname, p.project_no, e.description
|
||
FROM vtiger_project p
|
||
JOIN vtiger_crmentity e ON e.crmid = p.projectid AND e.deleted = 0
|
||
WHERE (p.projectname LIKE ? OR e.description LIKE ?)";
|
||
|
||
$params = ["%$plaintiff_fio%", "%$plaintiff_fio%"];
|
||
$result = $this->adb->pquery($sql, $params);
|
||
|
||
if ($this->adb->num_rows($result) > 0) {
|
||
$row = $this->adb->fetchByAssoc($result);
|
||
return $row['projectid'];
|
||
}
|
||
}
|
||
|
||
// Поиск по номеру дела
|
||
if ($case_number) {
|
||
$sql = "SELECT p.projectid, p.projectname, p.project_no, e.description
|
||
FROM vtiger_project p
|
||
JOIN vtiger_crmentity e ON e.crmid = p.projectid AND e.deleted = 0
|
||
WHERE (p.project_no LIKE ? OR e.description LIKE ?)";
|
||
|
||
$params = ["%$case_number%", "%$case_number%"];
|
||
$result = $this->adb->pquery($sql, $params);
|
||
|
||
if ($this->adb->num_rows($result) > 0) {
|
||
$row = $this->adb->fetchByAssoc($result);
|
||
return $row['projectid'];
|
||
}
|
||
}
|
||
|
||
// Поиск по УИД
|
||
if ($uid) {
|
||
$sql = "SELECT p.projectid, p.projectname, p.project_no, e.description
|
||
FROM vtiger_project p
|
||
JOIN vtiger_crmentity e ON e.crmid = p.projectid AND e.deleted = 0
|
||
WHERE e.description LIKE ?";
|
||
|
||
$params = ["%$uid%"];
|
||
$result = $this->adb->pquery($sql, $params);
|
||
|
||
if ($this->adb->num_rows($result) > 0) {
|
||
$row = $this->adb->fetchByAssoc($result);
|
||
return $row['projectid'];
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Обновление проекта
|
||
*/
|
||
public function updateProject($project_id, $content) {
|
||
try {
|
||
// Получаем запись проекта
|
||
$project = Vtiger_Record_Model::getInstanceById($project_id, 'Project');
|
||
|
||
// Обновляем описание с новыми данными
|
||
$current_description = $project->get('description') ?: '';
|
||
$new_info = $this->formatDocumentInfo($content);
|
||
|
||
// Добавляем информацию о документе в описание
|
||
$updated_description = $current_description . "\n\n" . $new_info;
|
||
|
||
// Обновляем поля проекта
|
||
$project->set('description', $updated_description);
|
||
|
||
// Обновляем статус если нужно
|
||
$current_status = $project->get('projectstatus');
|
||
if ($current_status === 'представительство в суде 1й инстанции') {
|
||
$project->set('projectstatus', 'получено определение суда');
|
||
}
|
||
|
||
// Сохраняем изменения
|
||
$project->save();
|
||
|
||
return [
|
||
'success' => true,
|
||
'project_id' => $project_id,
|
||
'message' => 'Проект успешно обновлен'
|
||
];
|
||
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => 'Ошибка обновления проекта: ' . $e->getMessage()
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Загрузка документа в CRM
|
||
*/
|
||
public function uploadDocument($project_id, $file_url, $file_name, $content) {
|
||
try {
|
||
// Скачиваем файл
|
||
$file_content = file_get_contents($file_url);
|
||
if ($file_content === false) {
|
||
throw new Exception('Не удалось скачать файл');
|
||
}
|
||
|
||
// Создаем временный файл
|
||
$temp_file = tempnam(sys_get_temp_dir(), 'crm_doc_');
|
||
file_put_contents($temp_file, $file_content);
|
||
|
||
// Создаем запись документа
|
||
$document = Vtiger_Record_Model::getCleanInstance('Documents');
|
||
|
||
// Формируем название документа
|
||
$document_title = $this->formatDocumentTitle($content);
|
||
|
||
$document->set('notes_title', $document_title);
|
||
$document->set('filename', $file_name);
|
||
$document->set('filetype', 'application/pdf');
|
||
$document->set('filesize', strlen($file_content));
|
||
$document->set('filelocationtype', 'E'); // External
|
||
$document->set('folderid', 3); // Documents folder
|
||
|
||
// Сохраняем документ
|
||
$document->save();
|
||
|
||
// Прикрепляем файл
|
||
$document->uploadAndSaveFile($temp_file, $file_name);
|
||
|
||
// Связываем документ с проектом
|
||
$this->linkDocumentToProject($document->getId(), $project_id);
|
||
|
||
// Удаляем временный файл
|
||
unlink($temp_file);
|
||
|
||
return [
|
||
'success' => true,
|
||
'document_id' => $document->getId(),
|
||
'message' => 'Документ успешно загружен'
|
||
];
|
||
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => 'Ошибка загрузки документа: ' . $e->getMessage()
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Связывание документа с проектом
|
||
*/
|
||
private function linkDocumentToProject($document_id, $project_id) {
|
||
$sql = "INSERT INTO vtiger_senotesrel (crmid, notesid) VALUES (?, ?)";
|
||
$this->adb->pquery($sql, [$project_id, $document_id]);
|
||
}
|
||
|
||
/**
|
||
* Форматирование информации о документе
|
||
*/
|
||
private function formatDocumentInfo($content) {
|
||
$info = "=== СУДЕБНЫЙ ДОКУМЕНТ ===\n";
|
||
$info .= "Дата получения: " . date('d.m.Y H:i:s') . "\n";
|
||
|
||
if (!empty($content['case_number'])) {
|
||
$info .= "Номер дела: " . $content['case_number'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['uid'])) {
|
||
$info .= "УИД: " . $content['uid'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['court'])) {
|
||
$info .= "Суд: " . $content['court'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['plaintiff_fio'])) {
|
||
$info .= "Истец: " . $content['plaintiff_fio'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['defendant_fio'])) {
|
||
$info .= "Ответчик: " . $content['defendant_fio'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['document_title'])) {
|
||
$info .= "Тип документа: " . $content['document_title'] . "\n";
|
||
}
|
||
|
||
if (!empty($content['description'])) {
|
||
$info .= "Описание: " . $content['description'] . "\n";
|
||
}
|
||
|
||
return $info;
|
||
}
|
||
|
||
/**
|
||
* Форматирование названия документа
|
||
*/
|
||
private function formatDocumentTitle($content) {
|
||
$title = "СУДЕБНЫЙ ДОКУМЕНТ";
|
||
|
||
if (!empty($content['document_title'])) {
|
||
$title = $content['document_title'];
|
||
}
|
||
|
||
if (!empty($content['case_number'])) {
|
||
$title .= " по делу " . $content['case_number'];
|
||
}
|
||
|
||
if (!empty($content['plaintiff_fio'])) {
|
||
$title .= " " . $content['plaintiff_fio'];
|
||
}
|
||
|
||
$title .= " " . date('d.m.Y');
|
||
|
||
return $title;
|
||
}
|
||
|
||
/**
|
||
* Логирование действий
|
||
*/
|
||
private function logAction($action, $data) {
|
||
$log_file = __DIR__ . '/logs/project_update.log';
|
||
$log_dir = dirname($log_file);
|
||
|
||
if (!is_dir($log_dir)) {
|
||
mkdir($log_dir, 0755, true);
|
||
}
|
||
|
||
$log_entry = date('Y-m-d H:i:s') . " - $action: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n";
|
||
file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Основная функция
|
||
*/
|
||
function main() {
|
||
try {
|
||
// Получаем входные данные
|
||
$input = '';
|
||
|
||
if (isset($argv[1])) {
|
||
// Данные переданы как аргумент командной строки
|
||
$input = $argv[1];
|
||
} else {
|
||
// Данные переданы через stdin
|
||
$input = stream_get_contents(STDIN);
|
||
}
|
||
|
||
if (empty($input)) {
|
||
throw new Exception('Не указаны входные данные');
|
||
}
|
||
|
||
// Парсим JSON
|
||
$data = json_decode($input, true);
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
throw new Exception('Ошибка парсинга JSON: ' . json_last_error_msg());
|
||
}
|
||
|
||
// Проверяем структуру данных
|
||
if (!isset($data['content']) || !is_array($data['content'])) {
|
||
throw new Exception('Неверная структура данных: отсутствует content');
|
||
}
|
||
|
||
$content = $data['content'];
|
||
$file_url = $data['file'] ?? '';
|
||
$file_name = $data['file_name'] ?? '';
|
||
|
||
// Создаем экземпляр обновлятеля
|
||
$updater = new ProjectUpdater();
|
||
|
||
// Ищем проект
|
||
$project_id = $updater->findProject($content);
|
||
|
||
if (!$project_id) {
|
||
throw new Exception('Проект не найден по указанным данным');
|
||
}
|
||
|
||
// Обновляем проект
|
||
$update_result = $updater->updateProject($project_id, $content);
|
||
|
||
if (!$update_result['success']) {
|
||
throw new Exception($update_result['error']);
|
||
}
|
||
|
||
// Загружаем документ если указан
|
||
$upload_result = null;
|
||
if (!empty($file_url) && !empty($file_name)) {
|
||
$upload_result = $updater->uploadDocument($project_id, $file_url, $file_name, $content);
|
||
}
|
||
|
||
// Формируем результат
|
||
$result = [
|
||
'success' => true,
|
||
'project_id' => $project_id,
|
||
'update_result' => $update_result,
|
||
'upload_result' => $upload_result,
|
||
'message' => 'Проект успешно обновлен'
|
||
];
|
||
|
||
// Логируем действие
|
||
$updater->logAction('PROJECT_UPDATE_SUCCESS', $result);
|
||
|
||
// Выводим результат
|
||
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||
|
||
return 0;
|
||
|
||
} catch (Exception $e) {
|
||
$error_result = [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
'timestamp' => date('Y-m-d H:i:s')
|
||
];
|
||
|
||
// Логируем ошибку
|
||
if (isset($updater)) {
|
||
$updater->logAction('PROJECT_UPDATE_ERROR', $error_result);
|
||
}
|
||
|
||
echo json_encode($error_result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// Запускаем скрипт
|
||
if (php_sapi_name() === 'cli') {
|
||
exit(main());
|
||
}
|
||
?>
|