Заметки
После удаления лида у чата открытой линии может остаться CRM-привязка
Ситуация, когда лид из открытой линии удалён, но техническая связь диалога с CRM остаётся и мешает повторному созданию лида.
В открытых линиях удаление лида не всегда означает, что диалог полностью потерял CRM-контекст. Перед повторным созданием лида по тому же чату стоит проверить старые привязки.
Суть проблемы
Лид, созданный из чата открытой линии, можно удалить из CRM, но у самого диалога при этом может остаться техническая связь с удалённым лидом или связанным делом.
Коротко
Метод imopenlines.crm.lead.create создаёт лид на основании диалога открытой линии.
Но если у этого диалога уже осталась CRM-привязка от старого лида, повторное создание может
сработать не так, как ожидается.
Типовая цепочка выглядит так:
- по чату открытой линии был создан лид;
- у чата появилась CRM-привязка к лиду и связанному делу;
- лид удалили из CRM;
- часть технических связей диалога могла остаться;
- повторный вызов
imopenlines.crm.lead.createне создаёт новый лид ожидаемым образом; - перед повторным созданием приходится сначала разбирать старую CRM-привязку.
Это лучше воспринимать не как ошибку самого удаления лида, а как особенность связей между CRM, делами и диалогами открытых линий.
Где встречается
Ситуация обычно проявляется в коробочном Bitrix24 при доработках открытых линий:
- при повторном создании лида по старому чату;
- при ручном удалении лида, который был создан из открытой линии;
- при автоматической очистке тестовых или ошибочных лидов;
- при переносе диалога на новую CRM-сущность;
- при попытке заново связать диалог с CRM после удаления старой карточки.
Если смотреть только на список лидов, может казаться, что связи уже нет. Но сам чат и дело CRM могут продолжать хранить старый контекст.
Что остаётся после удаления
Удаление CRM-сущности не всегда равно полной очистке всех связанных объектов, если эти объекты привязаны ещё к чему-то.
CRM-привязка диалога
У диалога открытой линии может быть отдельная CRM-привязка. Она нужна, чтобы по CRM-сущности находить связанные чаты и продолжать работу с историей общения.
В коробке это важно проверять не только по самому лиду. Следы связи могут быть в нескольких местах:
- в сессии открытой линии;
- в данных чата;
- в деле CRM, созданном для диалога;
- в привязках дела к CRM-сущностям;
- в технических таблицах связей.
Точные таблицы и поля лучше проверять на конкретной версии портала, потому что внутренняя схема может отличаться.
Почему лид не создаётся повторно
Если для чата уже есть CRM-контекст, повторное создание лида через
imopenlines.crm.lead.create может не дать нового чистого лида.
Причина обычно не в том, что удалённый лид физически существует, а в том, что диалог всё ещё считается связанным с CRM через оставшиеся технические записи.
Поэтому перед повторным созданием лида нужно сначала понять, где именно осталась старая связь: в чате, сессии, деле или привязках дела.
Решение
В моём случае помогла предварительная очистка CRM-контекста у сессии открытой линии и у чата.
Очистка старой связи
Смысл решения такой:
- сбросить CRM-флаги у сессии открытой линии;
- очистить ID CRM-дела у сессии;
- получить чат по
CHAT_ID; - очистить CRM-данные в полях чата.
Это решение относится к коробочному Bitrix24 и затрагивает внутренние таблицы. Перед применением нужно проверить его на тестовом портале и сделать резервную копию.
Пример кода
Ниже пример общей логики. Он не создаёт новый лид, а только очищает старую CRM-привязку у сессии открытой линии и у чата. После такой очистки повторное создание лида можно делать отдельно, уже своим рабочим способом.
<?php
use Bitrix\Main\Loader;
use Bitrix\Im\Model\ChatTable;
use Bitrix\ImOpenLines\Model\SessionTable;
const IM_MODULE_ID = 'im';
const IMOPENLINES_MODULE_ID = 'imopenlines';
Loader::includeModule(IM_MODULE_ID);
Loader::includeModule(IMOPENLINES_MODULE_ID);
/**
* Очищает старую CRM-привязку у сессии и чата открытой линии.
*/
function clearOpenLineCrmBinding(array $session): void
{
$session_id = (int)($session['ID'] ?? 0);
$chat_id = (int)($session['CHAT_ID'] ?? 0);
if ($session_id <= 0 || $chat_id <= 0) {
return;
}
clearSessionCrmContext($session_id);
$chat = fetchChatById($chat_id);
if ($chat === null) {
return;
}
clearChatCrmContext($chat);
}
/**
* Сбрасывает CRM-контекст сессии открытой линии.
*/
function clearSessionCrmContext(int $session_id): void
{
SessionTable::update($session_id, [
'CRM' => 'N',
'CRM_CREATE' => 'N',
'CRM_CREATE_LEAD' => 'N',
'CRM_CREATE_COMPANY' => 'N',
'CRM_CREATE_CONTACT' => 'N',
'CRM_CREATE_DEAL' => 'N',
'CRM_ACTIVITY_ID' => '',
]);
}
/**
* Получает чат по ID.
*/
function fetchChatById(int $chat_id): ?array
{
$chat_result = ChatTable::getList([
'select' => [
'ID',
'ENTITY_DATA_1',
'ENTITY_DATA_2',
],
'filter' => [
'=ID' => $chat_id,
],
'limit' => 1,
]);
$chat = $chat_result->fetch();
return is_array($chat) ? $chat : null;
}
/**
* Очищает CRM-контекст в данных чата.
*/
function clearChatCrmContext(array $chat): void
{
$chat_id = (int)($chat['ID'] ?? 0);
if ($chat_id <= 0) {
return;
}
$entity_data_1 = resetChatEntityData((string)($chat['ENTITY_DATA_1'] ?? ''));
ChatTable::update($chat_id, [
'ENTITY_DATA_1' => $entity_data_1,
'ENTITY_DATA_2' => '',
]);
}
/**
* Очищает CRM-часть ENTITY_DATA_1.
*/
function resetChatEntityData(string $entity_data_1): string
{
if ($entity_data_1 === '') {
return '';
}
return '';
}
Функция resetChatEntityData оставлена отдельной специально. На конкретном портале
формат ENTITY_DATA_1 нужно сначала посмотреть и только потом решить, очищать поле
полностью или удалять из него только CRM-часть.
Что проверить
Не стоит сразу удалять записи из таблиц. Сначала лучше собрать картину: какой чат, какая сессия, какой лид и какое дело связаны между собой.
Перед повторным созданием лида
- проверить
CHAT_IDоткрытой линии; - найти активную или последнюю сессию по этому чату;
- посмотреть CRM-поля сессии;
- проверить данные чата и его CRM-контекст;
- найти дело CRM, связанное с диалогом;
- проверить привязки дела к удалённому лиду;
- очищать связь только после резервной копии и проверки на тестовом портале.
В рабочем коде очистку лучше делать отдельным административным скриптом, а не в обработчике события и не в публичном ajax-действии.
Пример проверки
Ниже пример не очищает данные. Он только показывает общий подход: найти сессию открытой линии по чату и вывести CRM-поля, которые нужно проверить перед повторным созданием лида.
<?php
use Bitrix\Main\Loader;
use Bitrix\ImOpenLines\Model\SessionTable;
const IMOPENLINES_MODULE_ID = 'imopenlines';
const CHAT_ID = 0;
Loader::includeModule(IMOPENLINES_MODULE_ID);
$session_data = fetchLastOpenLineSession(CHAT_ID);
if ($session_data === null) {
echo 'Сессия открытой линии не найдена';
return;
}
printSessionCrmContext($session_data);
/**
* Получает последнюю сессию открытой линии по чату.
*/
function fetchLastOpenLineSession(int $chat_id): ?array
{
if ($chat_id <= 0) {
return null;
}
$session_result = SessionTable::getList([
'select' => [
'ID',
'CHAT_ID',
'CRM',
'CRM_ENTITY_TYPE',
'CRM_ENTITY_ID',
'CRM_ACTIVITY_ID',
],
'filter' => [
'=CHAT_ID' => $chat_id,
],
'order' => [
'ID' => 'DESC',
],
'limit' => 1,
]);
$session_data = $session_result->fetch();
return is_array($session_data) ? $session_data : null;
}
/**
* Выводит CRM-контекст сессии.
*/
function printSessionCrmContext(array $session_data): void
{
$context_data = [
'SESSION_ID' => $session_data['ID'] ?? null,
'CHAT_ID' => $session_data['CHAT_ID'] ?? null,
'CRM' => $session_data['CRM'] ?? null,
'CRM_ENTITY_TYPE' => $session_data['CRM_ENTITY_TYPE'] ?? null,
'CRM_ENTITY_ID' => $session_data['CRM_ENTITY_ID'] ?? null,
'CRM_ACTIVITY_ID' => $session_data['CRM_ACTIVITY_ID'] ?? null,
];
echo '<pre>';
print_r($context_data);
echo '</pre>';
} Если после удаления лида в сессии или связанных объектах всё ещё видны старые CRM-значения, значит перед повторным созданием лида нужно разбираться именно с этой привязкой.