Как перенести дело из одного типа объекта в другой

Scope: crm

Кто может выполнять метод: пользователи с правом на изменение элементов CRM

Выберите инструмент для разработки с AI-агентом:

  • используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
  • используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации

Дела, связанные с элементами CRM, хранятся в таймлайне карточки элемента. Перенос дел может потребоваться между элементами разных типов: лид, сделка, контакт, компания, счет, смарт-процесс. Например, у клиента два электронных адреса, но в карточке компании вашего Битрикс24 сохранен только один. Когда клиент напишет письмо со второго, неизвестного вам, адреса, почта создаст новый лид, а не прикрепит письмо в карточку существующей компании. Для хранения информации о клиенте в одном месте можно перенести дело из лида в карточку компании.

Перенос между разными типами объектов собирается из двух операций: сначала добавляем связь дела с новым объектом, потом удаляем связь со старым. В результате сценария дело появится в таймлайне компании и исчезнет из таймлайна лида.

Метод crm.activity.binding.move здесь не подходит: он переносит дело только между элементами одного типа. Если типы разные, метод вернет ошибку SOURCE_AND_TARGET_ENTITY_TYPES_ARE_NOT_EQUAL_ERROR. Чтобы перенести дело между двумя лидами или двумя сделками, используйте сценарий Как перенести дело между элементами одного типа.

Для переноса дела последовательно выполним четыре метода:

  1. crm.activity.list — получим ID дела

  2. crm.company.list — получим ID компании для переноса дела

  3. crm.activity.binding.add — добавим связь дела с компанией

  4. crm.activity.binding.delete — удалим связь дела с лидом

Порядок шагов 3 и 4 менять нельзя. Если сначала удалить связь с лидом, дело останется без единственной связи и метод вернет ошибку LAST_BINDING_CANNOT_BE_DELETED.

1. Получаем ID дела

Используем метод crm.activity.list с фильтром:

  • OWNER_TYPE_IDтип объекта, укажем 1 для лида,

  • OWNER_ID — ID элемента, из которого будем переносить дело.

В примере переносим дело из лида 1000977. ID лида виден в адресной строке его карточки, например /crm/lead/details/1000977/, или его можно получить методом crm.lead.list.

Без параметра select метод возвращает все поля дела. Чтобы сократить ответ, укажем только те поля, которые нужны сценарию: ID, OWNER_TYPE_ID, OWNER_ID, SUBJECT и DESCRIPTION.

Как использовать примеры в документации

import { B24Hook } from '@bitrix24/b24jssdk'
        
        const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
        // B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
        
        const result = await $b24.actions.v2.call.make({
            method: "crm.activity.list",
            params: {
                filter:
                {
                    "OWNER_TYPE_ID": 1,
                    "OWNER_ID": 1000977
                },
                select: [ "ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION" ]
            }
        });
        
require_once 'vendor/autoload.php';
        
        use Bitrix24\SDK\Services\ServiceBuilderFactory;
        use Symfony\Component\EventDispatcher\EventDispatcher;
        use Monolog\Logger;
        use Monolog\Handler\StreamHandler;
        
        $logger = new Logger('b24');
        $logger->pushHandler(new StreamHandler('php://stdout'));
        
        $serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), $logger))
            ->initFromWebhook(getenv('B24_HOOK'));
        // B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
        
        $activities = $serviceBuilder->getCRMScope()->activity()->list(
            [],
            [
                'OWNER_TYPE_ID' => 1,
                'OWNER_ID' => 1000977,
            ],
            [
                'ID', 'OWNER_TYPE_ID', 'OWNER_ID', 'SUBJECT', 'DESCRIPTION'
            ],
            0
        )->getActivities();
        
import os
        
        from b24pysdk import BitrixWebhook, Client
        
        client = Client(
            BitrixWebhook(
                domain="your-domain.bitrix24.com",
                webhook_token=os.environ["B24_HOOK_TOKEN"],
            )
        )
        # B24_HOOK_TOKEN = 'user_id/webhook_key'
        
        result = client.crm.activity.list(
            filter={
                "OWNER_TYPE_ID": 1,
                "OWNER_ID": 1000977,
            },
            select=["ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION"],
        ).response.result
        

В результате получим все дела, связанные с указанным элементом.

{
            "result": [
                {
                    "ID": "7685",
                    "OWNER_TYPE_ID": "1",
                    "OWNER_ID": "1000977",
                    "SUBJECT": "для лидов",
                    "DESCRIPTION": "<div>письмо первое</div>\r\n"
                }
            ],
            "total": 1
        }
        

Сохраним ID дела: 7685. Это значение передадим в параметр activityId на шагах 3 и 4.

2. Получаем ID компании

Используем метод crm.company.list с фильтром:

  • TITLE — название компании.

Чтобы ограничить возвращаемые поля, добавим параметр select и укажем только поля ID и TITLE.

const result = await $b24.actions.v2.call.make({
            method: "crm.company.list",
            params: {
                filter: { "TITLE": "Название_компании" },
                select: [ "ID", "TITLE" ]
            }
        });
        
$companies = $serviceBuilder->getCRMScope()->company()->list(
            [],
            [
                'TITLE' => 'Название_компании'
            ],
            [
                'ID', 'TITLE'
            ],
            0
        )->getCompanies();
        
result = client.crm.company.list(
            filter={
                "TITLE": "Название_компании",
            },
            select=["ID", "TITLE"],
        ).response.result
        

В результате получим ID компании — ID: 173. Это значение передадим в параметр entityId на шаге 3.

{
            "result": [
                {
                    "ID": "173",
                    "TITLE": "Название_компании"
                }
            ],
            "total": 1
        }
        

3. Добавляем связь дела с компанией

Для связи дела и компании используем метод crm.activity.binding.add с параметрами:

const result = await $b24.actions.v2.call.make({
            method: 'crm.activity.binding.add',
            params: {
                activityId: 7685,
                entityTypeId: 4,
                entityId: 173
            }
        });
        
// crm.activity.binding.add не имеет типизированной обертки — вызываем через core
        $result = $serviceBuilder->core->call(
            'crm.activity.binding.add',
            [
                'activityId' => 7685,
                'entityTypeId' => 4,
                'entityId' => 173
            ]
        );
        
result = client.crm.activity.binding.add(
            activity_id=7685,
            entity_type_id=4,
            entity_id=173,
        ).response.result
        

В результате получим true, добавление связи для дела прошло успешно. Теперь дело привязано к двум элементам сразу — к лиду и к компании.

{
            "result": true
        }
        

4. Удаляем связь дела с лидом

Используем метод crm.activity.binding.delete с параметрами:

const result = await $b24.actions.v2.call.make({
            method: 'crm.activity.binding.delete',
            params: {
                activityId: 7685,
                entityTypeId: 1,
                entityId: 1000977
            }
        });
        
// crm.activity.binding.delete не имеет типизированной обертки — вызываем через core
        $result = $serviceBuilder->core->call(
            'crm.activity.binding.delete',
            [
                'activityId' => 7685,
                'entityTypeId' => 1,
                'entityId' => 1000977
            ]
        );
        
result = client.crm.activity.binding.delete(
            activity_id=7685,
            entity_type_id=1,
            entity_id=1000977,
        ).response.result
        

В результате получим true, удаление связи дела с лидом прошло успешно. Перенос завершен: у дела осталась одна связь — с компанией.

{
            "result": true
        }
        

Пример кода

import { B24Hook } from '@bitrix24/b24jssdk'
        import { createInterface } from 'node:readline/promises'
        
        const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
        // B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
        
        async function call(method, params) {
            const result = await $b24.actions.v2.call.make({ method, params });
            if (!result.isSuccess) {
                throw new Error(result.getErrorMessages().join('; '));
            }
            return result.getData().result;
        }
        
        // Функция для выполнения всех шагов
        async function transferActivityToCompany(leadId, companyName) {
            // Шаг 1: Получаем список дел для указанного лида
            const activities = await call("crm.activity.list", {
                filter: {
                    "OWNER_TYPE_ID": 1,
                    "OWNER_ID": leadId
                },
                select: [ "ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION" ]
            });
            if (activities.length === 0) {
                console.log("Дела для указанного лида не найдены.");
                return;
            }
        
            const activityId = activities[0].ID;
        
            // Шаг 2: Ищем компанию по названию
            const companies = await call("crm.company.list", {
                filter: { "TITLE": companyName },
                select: [ "ID", "TITLE" ]
            });
            if (companies.length === 0) {
                console.log("Компания с указанным названием не найдена.");
                return;
            }
        
            const companyId = companies[0].ID;
        
            // Шаг 3: Создаем связь для найденного дела и компании
            await call('crm.activity.binding.add', {
                activityId: activityId,
                entityTypeId: 4,
                entityId: companyId
            });
        
            console.log("Связь дела с компанией успешно создана.");
        
            // Шаг 4: Удаляем связь дела и лида
            await call('crm.activity.binding.delete', {
                activityId: activityId,
                entityTypeId: 1,
                entityId: leadId
            });
        
            console.log("Связь дела с лидом успешно удалена.");
        }
        
        // Запрашиваем ID лида и название компании у пользователя
        const rl = createInterface({ input: process.stdin, output: process.stdout });
        const leadId = await rl.question("Введите ID лида: ");
        const companyName = await rl.question("Введите название компании: ");
        rl.close();
        
        // Запускаем функцию
        try {
            await transferActivityToCompany(leadId, companyName);
        } catch (error) {
            console.error(error.message);
        }
        
<?php
        require_once 'vendor/autoload.php';
        
        use Bitrix24\SDK\Services\ServiceBuilderFactory;
        use Symfony\Component\EventDispatcher\EventDispatcher;
        use Monolog\Logger;
        use Monolog\Handler\StreamHandler;
        
        $logger = new Logger('b24');
        $logger->pushHandler(new StreamHandler('php://stdout'));
        
        $serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), $logger))
            ->initFromWebhook(getenv('B24_HOOK'));
        // B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
        
        // Функция для выполнения всех шагов
        function transferActivityToCompany($serviceBuilder, $leadId, $companyName) {
            $crm = $serviceBuilder->getCRMScope();
        
            try {
                // Шаг 1: Получаем список дел для указанного лида
                $activities = $crm->activity()->list(
                    [],
                    [
                        'OWNER_TYPE_ID' => 1,
                        'OWNER_ID' => $leadId
                    ],
                    [
                        'ID', 'OWNER_TYPE_ID', 'OWNER_ID', 'SUBJECT', 'DESCRIPTION'
                    ],
                    0
                )->getActivities();
        
                if (empty($activities)) {
                    echo "Дела для указанного лида не найдены.";
                    return;
                }
        
                $activityId = $activities[0]->ID;
        
                // Шаг 2: Ищем компанию по названию
                $companies = $crm->company()->list(
                    [],
                    ['TITLE' => $companyName],
                    ['ID', 'TITLE'],
                    0
                )->getCompanies();
        
                if (empty($companies)) {
                    echo "Компания с указанным названием не найдена.";
                    return;
                }
        
                $companyId = $companies[0]->ID;
        
                // Шаг 3: Создаем связь для найденного дела и компании
                // crm.activity.binding.add не имеет типизированной обертки — вызываем через core
                $serviceBuilder->core->call(
                    'crm.activity.binding.add',
                    [
                        'activityId' => $activityId,
                        'entityTypeId' => 4,
                        'entityId' => $companyId
                    ]
                );
        
                echo "Связь дела с компанией успешно создана.";
        
                // Шаг 4: Удаляем связь дела и лида
                // crm.activity.binding.delete не имеет типизированной обертки — вызываем через core
                $serviceBuilder->core->call(
                    'crm.activity.binding.delete',
                    [
                        'activityId' => $activityId,
                        'entityTypeId' => 1,
                        'entityId' => $leadId
                    ]
                );
        
                echo "Связь дела с лидом успешно удалена.";
            } catch (\Throwable $e) {
                echo 'Ошибка: ' . $e->getMessage();
            }
        }
        
        // Запрашиваем ID лида и название компании у пользователя
        $leadId = readline("Введите ID лида: ");
        $companyName = readline("Введите название компании: ");
        
        // Запускаем функцию
        transferActivityToCompany($serviceBuilder, $leadId, $companyName);
        
import os
        
        from b24pysdk import BitrixWebhook, Client
        from b24pysdk.errors import BitrixAPIError
        
        
        def transfer_activity_to_company(client, lead_id, company_name):
            try:
                activity_result = client.crm.activity.list(
                    filter={
                        "OWNER_TYPE_ID": 1,
                        "OWNER_ID": lead_id,
                    },
                    select=["ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION"],
                ).response.result
            except BitrixAPIError as error:
                print(f"Ошибка: {error}")
                return
        
            if not activity_result:
                print("Дела для указанного лида не найдены.")
                return
        
            activity_id = activity_result[0]["ID"]
        
            try:
                company_result = client.crm.company.list(
                    filter={"TITLE": company_name},
                    select=["ID", "TITLE"],
                ).response.result
            except BitrixAPIError as error:
                print(f"Ошибка: {error}")
                return
        
            if not company_result:
                print("Компания с указанным названием не найдена.")
                return
        
            company_id = company_result[0]["ID"]
        
            try:
                add_result = client.crm.activity.binding.add(
                    activity_id=activity_id,
                    entity_type_id=4,
                    entity_id=company_id,
                ).response.result
            except BitrixAPIError as error:
                print(f"Ошибка: {error}")
                return
        
            if not add_result:
                return
        
            print("Связь дела с компанией успешно создана.")
        
            try:
                delete_result = client.crm.activity.binding.delete(
                    activity_id=activity_id,
                    entity_type_id=1,
                    entity_id=lead_id,
                ).response.result
            except BitrixAPIError as error:
                print(f"Ошибка: {error}")
            else:
                if delete_result:
                    print("Связь дела с лидом успешно удалена.")
        
        
        client = Client(
            BitrixWebhook(
                domain="your-domain.bitrix24.com",
                webhook_token=os.environ["B24_HOOK_TOKEN"],
            )
        )
        # B24_HOOK_TOKEN = 'user_id/webhook_key'
        
        lead_id = int(input("Введите ID лида: "))
        company_name = input("Введите название компании: ")
        
        transfer_activity_to_company(client, lead_id, company_name)
        

Проверим результат

Откройте карточку компании — в таймлайне появится перенесенное письмо. В карточке лида этого дела больше не будет: сценарий переносит связь, а не копирует ее.

Проверить результат через REST можно методом crm.activity.binding.list. Передайте в него activityId перенесенного дела — метод вернет все связи дела. После успешного переноса в ответе останется одна связь: тип объекта 4 и ID компании. Связи с лидом, тип объекта 1, в ответе быть не должно.

{
            "result": [
                {
                    "entityTypeId": 4,
                    "entityId": 173
                }
            ]
        }
        

Если в ответе остались обе связи, шаг 4 не выполнился — повторите его. Если связь с компанией не появилась, вернитесь к шагу 3.

Ошибки и диагностика

Если метод вернул ошибку, проверьте данные запроса.

Код

Причина и действие

LAST_BINDING_CANNOT_BE_DELETED

Вы удаляете единственную связь дела. Сначала выполните шаг 3 и привяжите дело к компании, только потом удаляйте связь с лидом

ACTIVITY_IS_ALREADY_BOUND

Дело уже привязано к компании. Шаг 3 выполнен, переходите к шагу 4

BINDING_NOT_FOUND

Дело не привязано к лиду из entityId. Проверьте, из какого элемента переносите дело

NOT_FOUND

Дело или элемент CRM не найдены. Проверьте activityId и entityId

OWNER_NOT_FOUND

Владелец дела не найден. Проверьте entityTypeId и entityId

ACCESS_DENIED

У пользователя нет прав на изменение элементов CRM

100

Не переданы обязательные параметры. Методам binding.add и binding.delete нужны все три: activityId, entityTypeId и entityId

Что важно учитывать

  • Между элементами одного типа дело переносят одним методом crm.activity.binding.move, сценарий из двух шагов для этого не нужен
  • Порядок шагов 3 и 4 менять нельзя: у дела всегда должна оставаться хотя бы одна связь
  • Между шагами 3 и 4 дело видно в таймлайне обоих элементов — и лида, и компании
  • Собственные поля дела OWNER_TYPE_ID и OWNER_ID переключаются на компанию только после шага 4, когда у дела остается одна связь. Пока связей две, владельцем остается лид. После шага 4 crm.activity.list с фильтром по лиду перенесенное дело больше не вернет, ищите его по компании с OWNER_TYPE_ID равным 4
  • Компания в сценарии — только пример целевого объекта. Чтобы перенести дело в сделку, найдите ее методом crm.deal.list и передайте 2 в entityTypeId шага 3. Значения для остальных типов — в справочнике типов объектов
  • Метод crm.company.list по фильтру TITLE может вернуть несколько компаний с одинаковым названием, проверяйте, ту ли компанию вы выбрали
  • Повторный запуск примера на том же лиде уже перенесенное дело не найдет: связи с лидом больше нет, и пример завершится сообщением, что дела не найдены

Продолжите изучение