Files
crm.clientright.ru/crm_extensions/update_project_from_document.php
Fedor dabcd43a00 Добавлены скрипты для парсинга судебных документов и обновления проектов в CRM
- 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 команды
2025-09-30 19:54:37 +03:00

369 lines
13 KiB
PHP
Executable File
Raw Permalink 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 на основе данных из судебного документа
*
* Использование:
* 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());
}
?>