feat: добавлен telegram_replay.php для публикации ответов поддержки в CRM
Новый endpoint для записи ответов поддержки как комментариев в CRM: - Принимает JSON с полями: answer, contact_id, project_id (опц.), support_user_id (опц.), channel (опц.) - Использует прямые INSERT запросы в vtiger_crmentity, vtiger_modcomments, vtiger_modcommentscf - Обязательно создаёт запись в vtiger_modcommentscf (иначе комментарий не отображается) - Устанавливает deleted=0 (иначе фильтруется при выборке) - Полная проверка ошибок БД с детальным логированием - Логи: logs/tg_replay_inbound.log Исправлены проблемы: - vtws_create падал без выброса исключения — заменён на прямой SQL - Убраны несуществующие колонки (from_mailconverter, customer_email, from_mailroom) - Добавлена обязательная запись в vtiger_modcommentscf
This commit is contained in:
186
telegram_replay.php
Normal file
186
telegram_replay.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/*********************************************************************************
|
||||
* telegram_replay.php — публикация в CRM ответов поддержки на вопросы пользователя
|
||||
*
|
||||
* Вход (POST JSON):
|
||||
* answer — текст ответа поддержки (обязательно)
|
||||
* contact_id — ID контакта в CRM, кому отвечаем (обязательно)
|
||||
* project_id — ID проекта (необязательно; для ответственного и уведомлений)
|
||||
* support_user_id — ID сотрудника CRM, кто ответил (необязательно; иначе админ/ответственный по проекту)
|
||||
* channel — канал, например 'Support' или 'Telegram' (необязательно, по умолчанию 'Support')
|
||||
*
|
||||
* Логи: logs/tg_replay_inbound.log
|
||||
********************************************************************************/
|
||||
|
||||
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 'include/Webservices/Revise.php';
|
||||
require_once 'include/utils/WhatsApp.php';
|
||||
require_once 'includes/Loader.php';
|
||||
|
||||
vimport('includes.runtime.Globals');
|
||||
vimport('includes.runtime.BaseModel');
|
||||
vimport('includes.runtime.LanguageHandler');
|
||||
|
||||
$logFile = 'logs/tg_replay_inbound.log';
|
||||
|
||||
$str = file_get_contents('php://input');
|
||||
$logstring = date('Y-m-d H:i:s') . ' ' . $str . PHP_EOL;
|
||||
file_put_contents($logFile, $logstring, FILE_APPEND);
|
||||
|
||||
$data = json_decode($str, true);
|
||||
if (!is_array($data)) {
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' Ошибка: невалидный JSON' . PHP_EOL, FILE_APPEND);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid JSON']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$answer = isset($data['answer']) ? trim($data['answer']) : (isset($data['message']) ? trim($data['message']) : '');
|
||||
$contact_id = isset($data['contact_id']) ? (int) $data['contact_id'] : 0;
|
||||
$project_id = isset($data['project_id']) ? (int) $data['project_id'] : 0;
|
||||
$support_user_id = isset($data['support_user_id']) ? $data['support_user_id'] : null; // может быть "19x123"
|
||||
$channel = isset($data['channel']) ? trim($data['channel']) : 'Support';
|
||||
|
||||
if (empty($answer)) {
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' Ошибка: не передан answer/message' . PHP_EOL, FILE_APPEND);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['success' => false, 'error' => 'Missing answer or message']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($contact_id <= 0) {
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' Ошибка: не передан или неверный contact_id' . PHP_EOL, FILE_APPEND);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['success' => false, 'error' => 'Missing or invalid contact_id']);
|
||||
exit;
|
||||
}
|
||||
|
||||
global $adb;
|
||||
if (empty($adb)) {
|
||||
$adb = PearDatabase::getInstance();
|
||||
}
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' $adb ok' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Проверяем, что контакт существует
|
||||
$check = $adb->pquery(
|
||||
'SELECT c.contactid, e.smownerid FROM vtiger_contactdetails c
|
||||
INNER JOIN vtiger_crmentity e ON e.crmid = c.contactid
|
||||
WHERE e.deleted = 0 AND c.contactid = ?',
|
||||
array($contact_id)
|
||||
);
|
||||
if ($adb->num_rows($check) === 0) {
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' Ошибка: контакт с ID ' . $contact_id . ' не найден' . PHP_EOL, FILE_APPEND);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['success' => false, 'error' => 'Contact not found']);
|
||||
exit;
|
||||
}
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' Контакт ' . $contact_id . ' найден' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
$owner_id = $adb->query_result($check, 0, 'smownerid');
|
||||
$crmid = '12x' . $contact_id;
|
||||
$setype = 'Contacts';
|
||||
|
||||
// Кто создаёт комментарий: переданный support_user_id, иначе ответственный по проекту, иначе по контакту, иначе админ
|
||||
$user = null;
|
||||
if (!empty($support_user_id)) {
|
||||
$user = (strpos($support_user_id, 'x') !== false) ? $support_user_id : ('19x' . $support_user_id);
|
||||
} elseif ($project_id > 0) {
|
||||
$proj = $adb->pquery(
|
||||
'SELECT e.smownerid FROM vtiger_project p INNER JOIN vtiger_crmentity e ON e.crmid = p.projectid
|
||||
WHERE e.deleted = 0 AND p.projectid = ? AND p.linktoaccountscontacts = ?',
|
||||
array($project_id, $contact_id)
|
||||
);
|
||||
if ($adb->num_rows($proj) > 0) {
|
||||
$uid = $adb->query_result($proj, 0, 'smownerid');
|
||||
$user = '19x' . $uid;
|
||||
}
|
||||
}
|
||||
if (empty($user)) {
|
||||
$user = '19x' . $owner_id;
|
||||
}
|
||||
if (empty($user) || $user === '19x') {
|
||||
$user = Users::getActiveAdminUser();
|
||||
}
|
||||
$owner_id_num = (strpos($user, 'x') !== false) ? (int) substr($user, strpos($user, 'x') + 1) : (int) $user;
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' user=' . (string)$user . ' (owner_id_num=' . $owner_id_num . ')' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Запись комментария напрямую в БД (без vtws_create — тот падает внутри без выброса исключения)
|
||||
$commentCrmId = $adb->getUniqueID('vtiger_crmentity');
|
||||
$date_var = date('Y-m-d H:i:s');
|
||||
|
||||
// deleted=0 обязательно — иначе запись не попадёт в выборку (WHERE vtiger_crmentity.deleted = 0)
|
||||
$sql_crmentity = "INSERT INTO vtiger_crmentity (crmid, smcreatorid, smownerid, smgroupid, setype, description, modifiedby, createdtime, modifiedtime, source, deleted) VALUES (?, ?, ?, 0, 'ModComments', '', ?, ?, ?, 'CRM', 0)";
|
||||
$result1 = $adb->pquery($sql_crmentity, array($commentCrmId, $owner_id_num, $owner_id_num, $owner_id_num, $date_var, $date_var));
|
||||
if (!$result1) {
|
||||
$error = $adb->database->ErrorMsg();
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ❌ Ошибка INSERT vtiger_crmentity: ' . $error . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['success' => false, 'error' => 'DB error: crmentity - ' . $error]);
|
||||
exit;
|
||||
}
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ✅ vtiger_crmentity OK' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
$sql_modcomments = "INSERT INTO vtiger_modcomments (modcommentsid, commentcontent, related_to, parent_comments, customer, userid, reasontoedit, is_private, filename, related_email_id, channel, messageid) VALUES (?, ?, ?, '', 0, 0, NULL, 0, NULL, NULL, ?, NULL)";
|
||||
$result2 = $adb->pquery($sql_modcomments, array($commentCrmId, $answer, $contact_id, $channel));
|
||||
if (!$result2) {
|
||||
$error = $adb->database->ErrorMsg();
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ❌ Ошибка INSERT vtiger_modcomments: ' . $error . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['success' => false, 'error' => 'DB error: modcomments - ' . $error]);
|
||||
exit;
|
||||
}
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ✅ vtiger_modcomments OK' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Без строки в vtiger_modcommentscf комментарий не попадёт в список (INNER JOIN в getListQuery)
|
||||
$result3 = $adb->pquery('INSERT INTO vtiger_modcommentscf (modcommentsid) VALUES (?)', array($commentCrmId));
|
||||
if (!$result3) {
|
||||
$error = $adb->database->ErrorMsg();
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ❌ Ошибка INSERT vtiger_modcommentscf: ' . $error . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['success' => false, 'error' => 'DB error: modcommentscf - ' . $error]);
|
||||
exit;
|
||||
}
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ✅ vtiger_modcommentscf OK' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ✅ Создан комментарий ID ' . $commentCrmId . ' для контакта ' . $contact_id . PHP_EOL, FILE_APPEND);
|
||||
|
||||
$comment_id_ws = '20x' . $commentCrmId; // ModComments в vtiger обычно 20x
|
||||
|
||||
// Уведомление ответственного (всплывашка)
|
||||
$notify_user_id = $owner_id;
|
||||
if ($project_id > 0) {
|
||||
$proj = $adb->pquery(
|
||||
'SELECT e.smownerid FROM vtiger_project p INNER JOIN vtiger_crmentity e ON e.crmid = p.projectid
|
||||
WHERE e.deleted = 0 AND p.projectid = ? AND p.linktoaccountscontacts = ? AND p.projectstatus <> ?',
|
||||
array($project_id, $contact_id, 'completed')
|
||||
);
|
||||
if ($adb->num_rows($proj) === 1) {
|
||||
$notify_user_id = $adb->query_result($proj, 0, 'smownerid');
|
||||
}
|
||||
}
|
||||
|
||||
$link = 'module=Contacts&view=Detail&record=' . $contact_id . '&app=MARKETING';
|
||||
$title = 'Ответ поддержки добавлен';
|
||||
$exist = $adb->pquery(
|
||||
'SELECT id FROM vtiger_vdnotifierpro WHERE userid = ? AND crmid = ? AND title = ? AND status = 5',
|
||||
array($notify_user_id, $contact_id, $title)
|
||||
);
|
||||
if ($adb->num_rows($exist) > 0) {
|
||||
$id = $adb->query_result($exist, 0, 'id');
|
||||
$adb->pquery('UPDATE vtiger_vdnotifierpro SET modifiedtime = ? WHERE id = ?', array($date_var, $id));
|
||||
} else {
|
||||
$adb->pquery(
|
||||
'INSERT INTO vtiger_vdnotifierpro (userid, modulename, crmid, modiuserid, link, title, action, modifiedtime, status) VALUES (?, ?, ?, 0, ?, ?, "", ?, 5)',
|
||||
array($notify_user_id, $setype, $contact_id, $link, $title, $date_var)
|
||||
);
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'comment_id' => $comment_id_ws,
|
||||
'contact_id' => $contact_id
|
||||
]);
|
||||
Reference in New Issue
Block a user