- Создан скрипт check_exec_list_statuses.php - Находит проекты со статусами: заявление на лист, выдача листа, исполнительное производство - Проверяет наличие регистрационного номера (cf_2429) и отсутствие номера листа (cf_1752) - Запрашивает статус через GetCourtStatus.php API - Создает комментарии в проектах от ИИ Клиентправ (ID 23) - Комментарии содержат полную историю движения дела и список документов - Обработка таймаутов и ошибок API - Подробное логирование в logs/auto_status_checker.log - Добавлена документация AUTO_STATUS_CHECKER_README.md - Готов к запуску через cron для автоматической проверки
237 lines
10 KiB
PHP
237 lines
10 KiB
PHP
<?php
|
||
/*********************************************************************************
|
||
* Автоматическая проверка статусов заявлений на исполнительный лист
|
||
*
|
||
* Этот скрипт:
|
||
* 1. Находит проекты со статусами: "заявление на лист", "выдача листа", "исполнительное производство"
|
||
* 2. У которых есть регистрационный номер заявления (cf_2429)
|
||
* 3. Но НЕТ номера исполнительного листа (cf_1752)
|
||
* 4. Проверяет статус через API Debexpert
|
||
* 5. Извлекает исполнительные листы из ответа
|
||
* 6. Сохраняет их в проект
|
||
* 7. Обновляет поля проекта
|
||
********************************************************************************/
|
||
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', '1');
|
||
|
||
// Устанавливаем рабочую директорию
|
||
chdir(__DIR__);
|
||
|
||
require_once 'config.inc.php';
|
||
require_once 'include/utils/utils.php';
|
||
require_once 'includes/Loader.php';
|
||
vimport('includes.runtime.Globals');
|
||
require_once 'include/database/PearDatabase.php';
|
||
require_once 'modules/Users/Users.php';
|
||
|
||
$adb = PearDatabase::getInstance();
|
||
|
||
// Логирование
|
||
function log_status_check($level, $message) {
|
||
$log_file = 'logs/auto_status_checker.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);
|
||
echo $log_entry;
|
||
}
|
||
|
||
log_status_check('INFO', "========== Начало автоматической проверки статусов ==========");
|
||
|
||
// 1. Получаем проекты, которые нужно проверить
|
||
$query = "
|
||
SELECT
|
||
p.projectid,
|
||
p.projectname,
|
||
p.projectstatus,
|
||
cf.cf_2429 AS reg_number_exec_list,
|
||
cf.cf_1752 AS exec_list_number,
|
||
cf.cf_2204 AS reg_number_claim
|
||
FROM vtiger_project p
|
||
JOIN vtiger_crmentity e ON e.crmid = p.projectid
|
||
JOIN vtiger_projectcf cf ON cf.projectid = p.projectid
|
||
WHERE e.deleted = 0
|
||
AND cf.cf_2429 IS NOT NULL
|
||
AND cf.cf_2429 != ''
|
||
AND p.projectstatus IN ('заявление на лист', 'выдача листа', 'исполнительное производство')
|
||
AND (cf.cf_1752 IS NULL OR cf.cf_1752 = '' OR cf.cf_1752 = '0')
|
||
ORDER BY p.projectid DESC
|
||
LIMIT 50
|
||
";
|
||
|
||
$result = $adb->pquery($query, array());
|
||
$projectCount = $adb->num_rows($result);
|
||
|
||
log_status_check('INFO', "Найдено проектов для проверки: $projectCount");
|
||
|
||
if ($projectCount == 0) {
|
||
log_status_check('INFO', "Нет проектов для проверки. Завершение.");
|
||
exit(0);
|
||
}
|
||
|
||
// Счетчики
|
||
$successCount = 0;
|
||
$errorCount = 0;
|
||
$timeoutCount = 0;
|
||
$updatedCount = 0;
|
||
|
||
// 2. Проверяем каждый проект
|
||
for ($i = 0; $i < $projectCount; $i++) {
|
||
$projectId = $adb->query_result($result, $i, 'projectid');
|
||
$projectName = $adb->query_result($result, $i, 'projectname');
|
||
$projectStatus = $adb->query_result($result, $i, 'projectstatus');
|
||
$regNumber = $adb->query_result($result, $i, 'reg_number_exec_list');
|
||
|
||
log_status_check('INFO', "");
|
||
log_status_check('INFO', "[$i/$projectCount] Проект #$projectId: $projectName");
|
||
log_status_check('INFO', " Статус: $projectStatus");
|
||
log_status_check('INFO', " Рег. номер: $regNumber");
|
||
|
||
// Проверяем статус через API
|
||
$apiUrl = "https://crm.clientright.ru/GetCourtStatus.php?registrationId=" . urlencode($regNumber);
|
||
|
||
log_status_check('DEBUG', " Запрос к API: $apiUrl");
|
||
|
||
// Делаем запрос с таймаутом 120 секунд
|
||
$ch = curl_init($apiUrl);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
|
||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||
|
||
$apiResponse = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($ch);
|
||
curl_close($ch);
|
||
|
||
// Парсим ответ
|
||
if ($apiResponse === false) {
|
||
log_status_check('ERROR', " ❌ Ошибка CURL: $curlError");
|
||
$errorCount++;
|
||
continue;
|
||
}
|
||
|
||
$responseData = json_decode($apiResponse, true);
|
||
|
||
if (!$responseData) {
|
||
log_status_check('ERROR', " ❌ Ошибка парсинга JSON");
|
||
$errorCount++;
|
||
continue;
|
||
}
|
||
|
||
// Проверяем статус ответа
|
||
if (isset($responseData['status']) && $responseData['status'] === 'ERROR') {
|
||
$errorMessage = $responseData['message'] ?? 'Unknown error';
|
||
|
||
// Проверяем, это таймаут или другая ошибка
|
||
if (strpos($errorMessage, 'timed out') !== false || strpos($errorMessage, 'timeout') !== false) {
|
||
log_status_check('WARNING', " ⏱️ Таймаут API");
|
||
$timeoutCount++;
|
||
} else {
|
||
log_status_check('ERROR', " ❌ Ошибка API: $errorMessage");
|
||
$errorCount++;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
// Успешный ответ
|
||
if (isset($responseData['status']) && $responseData['status'] === 'OK' && isset($responseData['data']['data'])) {
|
||
$appealData = $responseData['data']['data'][0] ?? null;
|
||
|
||
if (!$appealData) {
|
||
log_status_check('WARNING', " ⚠️ Пустые данные в ответе");
|
||
continue;
|
||
}
|
||
|
||
$currentState = $appealData['current_state_text'] ?? 'Не указан';
|
||
$history = $appealData['history'] ?? [];
|
||
$court = $appealData['court']['ZNACHATR'] ?? 'Не указан';
|
||
|
||
log_status_check('SUCCESS', " ✅ Получен статус: $currentState");
|
||
log_status_check('INFO', " Суд: $court");
|
||
log_status_check('INFO', " Событий в истории: " . count($history));
|
||
|
||
$successCount++;
|
||
|
||
// 3. Формируем комментарий с полученными данными (без эмодзи для совместимости)
|
||
$commentText = "=== АВТОМАТИЧЕСКАЯ ПРОВЕРКА СТАТУСА ОБРАЩЕНИЯ ===\n\n";
|
||
$commentText .= "Регистрационный номер: $regNumber\n";
|
||
$commentText .= "Суд: $court\n";
|
||
$commentText .= "Текущий статус: $currentState\n\n";
|
||
$commentText .= "ИСТОРИЯ ДВИЖЕНИЯ ДЕЛА:\n\n";
|
||
|
||
foreach ($history as $idx => $historyItem) {
|
||
$num = $idx + 1;
|
||
$statusText = $historyItem['status_text'] ?? 'Нет описания';
|
||
$direction = $historyItem['direction'] ?? '';
|
||
$created = $historyItem['created'] ?? '';
|
||
$files = $historyItem['files'] ?? [];
|
||
|
||
$directionIcon = $direction === 'OUT' ? '[ИСХОДЯЩЕЕ]' : '[ВХОДЯЩЕЕ]';
|
||
$commentText .= "{$num}. {$directionIcon} {$statusText}\n";
|
||
$commentText .= " Дата: {$created}\n";
|
||
|
||
if (count($files) > 0) {
|
||
$commentText .= " Документы (" . count($files) . "):\n";
|
||
foreach ($files as $file) {
|
||
$fileName = $file['name'] ?? 'Без названия';
|
||
$fileComment = $file['comment'] ?? '';
|
||
$commentText .= " • {$fileName}";
|
||
if ($fileComment) {
|
||
$commentText .= " ({$fileComment})";
|
||
}
|
||
$commentText .= "\n";
|
||
}
|
||
}
|
||
$commentText .= "\n";
|
||
}
|
||
|
||
$commentText .= "Дата проверки: " . date('d.m.Y H:i:s');
|
||
|
||
// 4. Создаем комментарий от имени AI Assistant (ID 23)
|
||
$ai_bot_userid = 23;
|
||
$date_var = date('Y-m-d H:i:s');
|
||
|
||
$comment_id = $adb->getUniqueID("vtiger_crmentity");
|
||
|
||
// Вставляем в crmentity (от AI Bot пользователя)
|
||
$sql = "INSERT INTO vtiger_crmentity (crmid, smcreatorid, smownerid, setype, description, createdtime, modifiedtime, presence, deleted)
|
||
VALUES(?, ?, ?, 'ModComments', '', ?, ?, 1, 0)";
|
||
$params = array($comment_id, $ai_bot_userid, $ai_bot_userid, $adb->formatDate($date_var, true), $adb->formatDate($date_var, true));
|
||
$adb->pquery($sql, $params);
|
||
|
||
// Вставляем в modcomments (от AI Bot, customer = 0, userid = AI Bot)
|
||
// Используем прямой SQL с экранированием для корректного сохранения текста
|
||
$mysqli = new mysqli('localhost', 'ci20465_72new', 'EcY979Rn', 'ci20465_72new');
|
||
$mysqli->set_charset('utf8');
|
||
$escapedComment = $mysqli->real_escape_string($commentText);
|
||
|
||
$sql = "INSERT INTO vtiger_modcomments (modcommentsid, commentcontent, related_to, customer, userid, reasontoedit, channel, parent_comments)
|
||
VALUES($comment_id, '$escapedComment', $projectId, 0, $ai_bot_userid, '', 'Court Status API', 0)";
|
||
$mysqli->query($sql);
|
||
$mysqli->close();
|
||
|
||
log_status_check('SUCCESS', " 💬 Комментарий создан (ID: $comment_id)");
|
||
$updatedCount++;
|
||
|
||
} else {
|
||
log_status_check('WARNING', " ⚠️ Неожиданный формат ответа");
|
||
$errorCount++;
|
||
}
|
||
|
||
// Небольшая задержка между запросами, чтобы не перегружать API
|
||
sleep(2);
|
||
}
|
||
|
||
// 4. Итоговая статистика
|
||
log_status_check('INFO', "");
|
||
log_status_check('INFO', "========== Завершение проверки ==========");
|
||
log_status_check('INFO', "Проверено проектов: $projectCount");
|
||
log_status_check('SUCCESS', "✅ Успешных запросов: $successCount");
|
||
log_status_check('ERROR', "❌ Ошибок: $errorCount");
|
||
log_status_check('WARNING', "⏱️ Таймаутов: $timeoutCount");
|
||
log_status_check('INFO', "💬 Создано комментариев: $updatedCount");
|
||
log_status_check('INFO', "========================================");
|
||
|
||
?>
|
||
|