Как перенести дело из одного типа объекта в другой
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. Чтобы перенести дело между двумя лидами или двумя сделками, используйте сценарий Как перенести дело между элементами одного типа.
Для переноса дела последовательно выполним четыре метода:
-
crm.activity.list — получим ID дела
-
crm.company.list — получим ID компании для переноса дела
-
crm.activity.binding.add — добавим связь дела с компанией
-
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 с параметрами:
-
activityId— ID дела, получили на шаге 1 в методе crm.activity.list, -
entityTypeId— ID типа объекта, укажем4для компании, -
entityId— ID компании, получили на шаге 2 в методе crm.company.list.
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 с параметрами:
-
activityId— ID дела, получили на шаге 1 в методе crm.activity.list, -
entityTypeId— ID типа объекта, укажем1для лида, -
entityId— ID лида, откуда удаляем дело.
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.
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса.
|
Код |
Причина и действие |
|
|
Вы удаляете единственную связь дела. Сначала выполните шаг 3 и привяжите дело к компании, только потом удаляйте связь с лидом |
|
|
Дело уже привязано к компании. Шаг 3 выполнен, переходите к шагу 4 |
|
|
Дело не привязано к лиду из |
|
|
Дело или элемент CRM не найдены. Проверьте |
|
|
Владелец дела не найден. Проверьте |
|
|
У пользователя нет прав на изменение элементов CRM |
|
|
Не переданы обязательные параметры. Методам |
Что важно учитывать
- Между элементами одного типа дело переносят одним методом 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может вернуть несколько компаний с одинаковым названием, проверяйте, ту ли компанию вы выбрали - Повторный запуск примера на том же лиде уже перенесенное дело не найдет: связи с лидом больше нет, и пример завершится сообщением, что дела не найдены
Продолжите изучение
- Добавить связь дела с элементом CRM crm.activity.binding.add
- Удалить связь дела с элементом CRM crm.activity.binding.delete
- Получить список всех связей дела crm.activity.binding.list
- Получить список дел crm.activity.list
- Как перенести дело между элементами одного типа
- Как перенести запланированное дело на другую дату