← Назад к заметкам

Заметки

После удаления лида у чата открытой линии может остаться 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-значения, значит перед повторным созданием лида нужно разбираться именно с этой привязкой.

Источники