- Добавлен флаг JSON_UNESCAPED_UNICODE во все json_encode() - Теперь русские символы в логах отображаются корректно, а не как \uXXXX - Исправлено 5 мест: все ошибки и успешные ответы
247 lines
12 KiB
PHP
247 lines
12 KiB
PHP
<?php
|
||
/*********************************************************************************
|
||
* Endpoint для сохранения AI-диалогов из Telegram в проекты CRM
|
||
* Сохраняет пары вопрос-ответ как два отдельных комментария
|
||
* All Rights Reserved.
|
||
********************************************************************************/
|
||
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', '1');
|
||
include_once 'modules/Users/Users.php';
|
||
include_once 'include/utils/CommonUtils.php';
|
||
include_once 'include/utils/utils.php';
|
||
require_once('include/Webservices/Utils.php');
|
||
require_once 'include/Webservices/Create.php';
|
||
require_once 'includes/Loader.php';
|
||
|
||
vimport ('includes.runtime.Globals');
|
||
vimport ('includes.runtime.BaseModel');
|
||
vimport ('includes.runtime.LanguageHandler');
|
||
|
||
// Получаем входные данные
|
||
$str = file_get_contents('php://input');
|
||
$logstring = date('Y-m-d H:i:s').' Получен запрос: '.$str.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
$data = json_decode($str, true);
|
||
|
||
// Проверяем обязательные поля
|
||
if (!isset($data['tgid']) || !isset($data['question']) || !isset($data['answer'])) {
|
||
$error = array('status' => 'error', 'message' => 'Не переданы обязательные поля: tgid, question, answer');
|
||
$logstring = date('Y-m-d H:i:s').' ОШИБКА: '.json_encode($error, JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
echo json_encode($error, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
$tgid = $data['tgid'];
|
||
$question = $data['question'];
|
||
$answer = $data['answer'];
|
||
$projectid = isset($data['projectid']) ? $data['projectid'] : null;
|
||
$botname = isset($data['botname']) ? $data['botname'] : 'AI Bot';
|
||
|
||
$user = Users::getActiveAdminUser();
|
||
|
||
// Функция для создания уведомления о диалоге с AI ботом
|
||
function createTelegramAINotification($projectId, $contactId, $contactName, $questionPreview) {
|
||
global $adb;
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Создаем уведомление для проекта '.$projectId.' о диалоге с AI ботом'.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
// Получаем ответственного по проекту
|
||
$query = 'SELECT e.smownerid FROM vtiger_crmentity e WHERE e.crmid = ? AND e.deleted = 0';
|
||
$result = $adb->pquery($query, array($projectId));
|
||
|
||
if ($adb->num_rows($result) === 0) {
|
||
$logstring = date('Y-m-d H:i:s').' WARNING: Проект '.$projectId.' не найден или удален'.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
return false;
|
||
}
|
||
|
||
$userId = $adb->query_result($result, 0, 'smownerid');
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Ответственный по проекту: пользователь '.$userId.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
// Формируем текст уведомления
|
||
// Обрезаем вопрос до 80 символов для краткости
|
||
$shortQuestion = mb_strlen($questionPreview) > 80 ? mb_substr($questionPreview, 0, 80) . '...' : $questionPreview;
|
||
$notificationTitle = "Telegram AI: " . $contactName . " - " . $shortQuestion;
|
||
|
||
// Формируем ссылку на проект (VDNotifierPro убирает index.php? из ссылки)
|
||
$projectLink = "module=Project&view=Detail&record=" . $projectId;
|
||
|
||
// Проверяем, нет ли уже непрочитанного уведомления для этого проекта от AI бота
|
||
// Используем modulename='Project' и проверяем title на начало с "Telegram AI:"
|
||
$checkQuery = "SELECT id FROM vtiger_vdnotifierpro WHERE userid = ? AND crmid = ? AND modulename = 'Project' AND title LIKE 'Telegram AI:%' AND status = 5 ORDER BY modifiedtime DESC LIMIT 1";
|
||
$checkResult = $adb->pquery($checkQuery, array($userId, $projectId));
|
||
|
||
if ($adb->num_rows($checkResult) > 0) {
|
||
// Обновляем существующее уведомление - обновляем заголовок и время
|
||
$existingId = $adb->query_result($checkResult, 0, 'id');
|
||
$updateQuery = "UPDATE vtiger_vdnotifierpro SET title = ?, modifiedtime = NOW() WHERE id = ?";
|
||
$adb->pquery($updateQuery, array($notificationTitle, $existingId));
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Обновлено существующее уведомление ID: '.$existingId.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
return $existingId;
|
||
} else {
|
||
// Создаем новое уведомление
|
||
$insertQuery = "INSERT INTO vtiger_vdnotifierpro (userid, modulename, crmid, modiuserid, link, title, action, modifiedtime, status) VALUES (?, 'Project', ?, 0, ?, ?, '', NOW(), 5)";
|
||
$adb->pquery($insertQuery, array($userId, $projectId, $projectLink, $notificationTitle));
|
||
|
||
$notificationId = $adb->getLastInsertID();
|
||
$logstring = date('Y-m-d H:i:s').' ✅ Создано новое уведомление ID: '.$notificationId.' для пользователя '.$userId.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
return $notificationId;
|
||
}
|
||
}
|
||
|
||
// 1. Находим контакт по tgid
|
||
$query = 'select c.contactid, c.firstname, c.lastname, e.smownerid as userid
|
||
from vtiger_contactdetails c
|
||
left join vtiger_crmentity e on e.crmid = c.contactid
|
||
where e.deleted = 0 and c.phone = ?';
|
||
$result = $adb->pquery($query, array($tgid));
|
||
|
||
if ($adb->num_rows($result) == 0) {
|
||
$error = array('status' => 'error', 'message' => 'Контакт с tgid='.$tgid.' не найден');
|
||
$logstring = date('Y-m-d H:i:s').' ОШИБКА: '.json_encode($error, JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
echo json_encode($error, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
$contactid = $adb->query_result($result, 0, 'contactid');
|
||
$userid = $adb->query_result($result, 0, 'userid');
|
||
$firstname = $adb->query_result($result, 0, 'firstname');
|
||
$lastname = $adb->query_result($result, 0, 'lastname');
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Найден контакт: '.$firstname.' '.$lastname.' (ID: '.$contactid.')'.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
// 2. Если projectid не передан - ищем активный проект
|
||
if (empty($projectid)) {
|
||
$query = 'select p.projectid
|
||
from vtiger_project p
|
||
left join vtiger_crmentity e on e.crmid = p.projectid
|
||
where e.deleted = 0 and p.linktoaccountscontacts = ? and p.projectstatus <> "completed"
|
||
order by e.modifiedtime desc
|
||
limit 1';
|
||
$result = $adb->pquery($query, array($contactid));
|
||
|
||
if ($adb->num_rows($result) == 0) {
|
||
$error = array('status' => 'error', 'message' => 'Не найден активный проект для контакта ID='.$contactid);
|
||
$logstring = date('Y-m-d H:i:s').' ОШИБКА: '.json_encode($error, JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
echo json_encode($error, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
$projectid = $adb->query_result($result, 0, 'projectid');
|
||
$logstring = date('Y-m-d H:i:s').' Найден активный проект: '.$projectid.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
} else {
|
||
// 3. Если projectid передан - проверяем что он существует и связан с контактом
|
||
$query = 'select p.projectid
|
||
from vtiger_project p
|
||
left join vtiger_crmentity e on e.crmid = p.projectid
|
||
where e.deleted = 0 and p.projectid = ? and p.linktoaccountscontacts = ?';
|
||
$result = $adb->pquery($query, array($projectid, $contactid));
|
||
|
||
if ($adb->num_rows($result) == 0) {
|
||
$error = array('status' => 'error', 'message' => 'Проект ID='.$projectid.' не найден или не связан с контактом');
|
||
$logstring = date('Y-m-d H:i:s').' ОШИБКА: '.json_encode($error, JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
echo json_encode($error, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Проверен проект: '.$projectid.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
}
|
||
|
||
// Получаем ответственного за проект
|
||
$query = 'select smownerid from vtiger_crmentity where crmid = ?';
|
||
$result = $adb->pquery($query, array($projectid));
|
||
$ownerid = $adb->query_result($result, 0, 'smownerid');
|
||
|
||
// ID пользователя AI Bot
|
||
$ai_bot_userid = 23;
|
||
|
||
// Используем просто ID проекта (как в обычных комментариях)
|
||
|
||
$date_var = date('Y-m-d H:i:s');
|
||
|
||
// 4. Создаём комментарий с ВОПРОСОМ (напрямую через SQL)
|
||
$question_commentid = $adb->getUniqueID("vtiger_crmentity");
|
||
|
||
// Вставляем в crmentity
|
||
$sql = "insert into vtiger_crmentity (crmid, smcreatorid, smownerid, setype, description, createdtime, modifiedtime, presence, deleted)
|
||
values(?, ?, ?, 'ModComments', '', ?, ?, 1, 0)";
|
||
$params = array($question_commentid, $ownerid, $ownerid, $adb->formatDate($date_var, true), $adb->formatDate($date_var, true));
|
||
$adb->pquery($sql, $params);
|
||
|
||
// Вставляем в modcomments
|
||
$sql = "insert into vtiger_modcomments (modcommentsid, commentcontent, related_to, customer, userid, reasontoedit, channel, parent_comments)
|
||
values(?, ?, ?, ?, 0, '', 'Telegram AI', 0)";
|
||
$params = array($question_commentid, $question, $projectid, $contactid);
|
||
$adb->pquery($sql, $params);
|
||
|
||
// Вставляем в modcommentsrel
|
||
// $sql = "insert into vtiger_modcommentsrel (modcommentsid, related_to) values(?, ?)";
|
||
// $adb->pquery($sql, array($question_commentid, $projectid));
|
||
|
||
$logstring = date('Y-m-d H:i:s').' ✅ Создан комментарий с ВОПРОСОМ: '.$question_commentid.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
// Задержка 1 секунда, чтобы ответ был позже вопроса
|
||
sleep(1);
|
||
$date_var_answer = date('Y-m-d H:i:s');
|
||
|
||
// 5. Создаём комментарий с ОТВЕТОМ (напрямую через SQL)
|
||
$answer_commentid = $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($answer_commentid, $ai_bot_userid, $ai_bot_userid, $adb->formatDate($date_var_answer, true), $adb->formatDate($date_var_answer, true));
|
||
$adb->pquery($sql, $params);
|
||
|
||
// Вставляем в modcomments (от AI Bot, поэтому customer = 0, userid = AI Bot)
|
||
$sql = "insert into vtiger_modcomments (modcommentsid, commentcontent, related_to, customer, userid, reasontoedit, channel, parent_comments)
|
||
values(?, ?, ?, 0, ?, '', 'Telegram AI Bot', 0)";
|
||
$params = array($answer_commentid, $answer, $projectid, $ai_bot_userid);
|
||
$adb->pquery($sql, $params);
|
||
|
||
// Вставляем в modcommentsrel
|
||
// $sql = "insert into vtiger_modcommentsrel (modcommentsid, related_to) values(?, ?)";
|
||
// $adb->pquery($sql, array($answer_commentid, $projectid));
|
||
|
||
$logstring = date('Y-m-d H:i:s').' ✅ Создан комментарий с ОТВЕТОМ: '.$answer_commentid.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
// 6. Создаем уведомление для ответственного по проекту
|
||
$contactName = $firstname . ' ' . $lastname;
|
||
$notificationId = createTelegramAINotification($projectid, $contactid, $contactName, $question);
|
||
|
||
// 7. Возвращаем успех
|
||
$response = array(
|
||
'status' => 'success',
|
||
'contact_id' => $contactid,
|
||
'project_id' => $projectid,
|
||
'question_comment_id' => $question_commentid,
|
||
'answer_comment_id' => $answer_commentid,
|
||
'notification_id' => $notificationId,
|
||
'botname' => $botname
|
||
);
|
||
|
||
$logstring = date('Y-m-d H:i:s').' ✅ SUCCESS: '.json_encode($response, JSON_UNESCAPED_UNICODE).PHP_EOL.PHP_EOL;
|
||
file_put_contents('logs/tg_ai_qa.log', $logstring, FILE_APPEND);
|
||
|
||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||
?>
|
||
|