Как перенести дело между элементами одного типа
Scope:
crmКто может выполнять метод: пользователи с правом на изменение элементов CRM
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
Дела, связанные с элементами CRM, хранятся в таймлайне карточки элемента. Перенос дела из одного элемента в другой может потребоваться, когда в один лид попадает несколько писем или звонков, которые с точки зрения бизнеса относятся к разным лидам. В этом случае можно разделить исходный лид на несколько новых и перенести дела для корректного учета данных.
Метод переносит связь дела, а не копирует ее. В результате сценария дело появится в таймлайне нового лида и исчезнет из таймлайна исходного.
Дело можно перенести только между элементами одного типа: значения sourceEntityTypeId и targetEntityTypeId должны совпадать. Если типы разные, метод вернет ошибку SOURCE_AND_TARGET_ENTITY_TYPES_ARE_NOT_EQUAL_ERROR. Чтобы перенести дело между объектами разных типов, например из лида в компанию, используйте сценарий Как перенести дело из одного типа объекта в другой.
Для переноса дела последовательно выполним три метода:
-
crm.activity.list — получим ID дела,
-
crm.lead.add — создадим элемент, в который перенесем дело, в примере лид,
-
crm.activity.binding.move — выполним перенос дела.
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. По полю 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"
},
{
"ID": "7687",
"OWNER_TYPE_ID": "1",
"OWNER_ID": "1000977",
"SUBJECT": "для лидов",
"DESCRIPTION": "<div>письмо второе</div>\r\n"
}
],
"total": 2
}
Выберем нужное дело из списка полученных и сохраним его ID: 7687. Это значение передадим в параметр activityId на шаге 3.
2. Создаем новый элемент
Для создания нового лида, в который перенесем дело письма, выполним метод crm.lead.add с параметрами:
-
fields[TITLE]— название лида, -
fields[ASSIGNED_BY_ID]— идентификатор ответственного за новый лид, -
params[REGISTER_SONET_EVENT]— параметр для регистрации уведомлений, укажемY, чтобы на новый лид сработали системные уведомления при создании.
В методе должны быть указаны все обязательные поля для лидов вашего Битрикс24, иначе лид создан не будет. Проверить, какие поля обязательные, можно методом crm.lead.fields, он вызывается без параметров.
const result = await $b24.actions.v2.call.make({
method: "crm.lead.add",
params: {
fields:
{
TITLE: "Второй лид",
ASSIGNED_BY_ID: 1,
},
params: {
REGISTER_SONET_EVENT: "Y",
}
}
});
$newLeadId = $serviceBuilder->getCRMScope()->lead()->add(
[
'TITLE' => 'Второй лид',
'ASSIGNED_BY_ID' => 1,
],
[
'REGISTER_SONET_EVENT' => 'Y',
]
)->getId();
result = client.crm.lead.add(
fields={
"TITLE": "Второй лид",
"ASSIGNED_BY_ID": 1,
},
params={
"REGISTER_SONET_EVENT": "Y",
},
).response.result
В результате получим ID созданного лида. Это значение передадим в параметр targetEntityId на шаге 3.
{
"result": 1000979
}
3. Переносим дело между элементами
Для переноса дела используем метод crm.activity.binding.move с параметрами:
-
activityId— ID дела, получили на шаге 1 в методе crm.activity.list, -
sourceEntityTypeId— ID типа объекта, откуда переносим дело, -
sourceEntityId— ID элемента, откуда переносим дело, -
targetEntityTypeId— ID типа объекта, куда переносим дело, -
targetEntityId— ID элемента, куда переносим дело, получили на шаге 2 в методе crm.lead.add.
В примере оба типа объекта равны 1 — дело переносится из лида в лид.
const result = await $b24.actions.v2.call.make({
method: 'crm.activity.binding.move',
params: {
activityId: 7687,
sourceEntityTypeId: 1,
sourceEntityId: 1000977,
targetEntityTypeId: 1,
targetEntityId: 1000979
}
});
// crm.activity.binding.move не имеет типизированной обертки — вызываем через core
$result = $serviceBuilder->core->call(
'crm.activity.binding.move',
[
'activityId' => 7687,
'sourceEntityTypeId' => 1,
'sourceEntityId' => 1000977,
'targetEntityTypeId' => 1,
'targetEntityId' => 1000979
]
);
result = client.crm.activity.binding.move(
activity_id=7687,
source_entity_type_id=1,
source_entity_id=1000977,
target_entity_type_id=1,
target_entity_id=1000979,
).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 transferActivity(firstLeadId, searchPhrase) {
// Шаг 1: Получаем список дел для указанного лида
const activities = await call("crm.activity.list", {
filter: {
"OWNER_TYPE_ID": 1,
"OWNER_ID": firstLeadId
},
select: [ "ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION" ]
});
const targetActivity = activities.find(activity => activity.DESCRIPTION.includes(searchPhrase));
if (!targetActivity) {
console.log(`Дело с описанием, содержащим '${searchPhrase}', не найдено.`);
return;
}
const activityId = targetActivity.ID;
// Шаг 2: Создаем новый лид
const newLeadId = await call("crm.lead.add", {
fields: {
TITLE: "Второй лид",
ASSIGNED_BY_ID: 1,
},
params: {
REGISTER_SONET_EVENT: "Y",
}
});
// Шаг 3: Переносим дело
await call('crm.activity.binding.move', {
activityId: activityId,
sourceEntityTypeId: 1,
sourceEntityId: firstLeadId,
targetEntityTypeId: 1,
targetEntityId: newLeadId
});
console.log("Дело успешно перенесено.");
}
// Запрашиваем ID первого лида и фразу для поиска у пользователя
const rl = createInterface({ input: process.stdin, output: process.stdout });
const firstLeadId = await rl.question("Введите ID первого лида: ");
const searchPhrase = await rl.question("Введите фразу для поиска по телу письма: ");
rl.close();
// Запускаем функцию
try {
await transferActivity(firstLeadId, searchPhrase);
} 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 transferActivity($serviceBuilder, $firstLeadId, $searchPhrase) {
$crm = $serviceBuilder->getCRMScope();
try {
// Шаг 1: Получаем список дел для указанного лида
$activities = $crm->activity()->list(
[],
[
'OWNER_TYPE_ID' => 1,
'OWNER_ID' => $firstLeadId,
],
[
'ID', 'OWNER_TYPE_ID', 'OWNER_ID', 'SUBJECT', 'DESCRIPTION'
],
0
)->getActivities();
$targetActivity = null;
foreach ($activities as $activity) {
if (strpos((string)$activity->DESCRIPTION, $searchPhrase) !== false) {
$targetActivity = $activity;
break;
}
}
if (!$targetActivity) {
echo "Дело с описанием, содержащим '{$searchPhrase}', не найдено.";
return;
}
$activityId = $targetActivity->ID;
// Шаг 2: Создаем новый лид
$newLeadId = $crm->lead()->add(
[
'TITLE' => 'Второй лид',
'ASSIGNED_BY_ID' => 1,
],
[
'REGISTER_SONET_EVENT' => 'Y',
]
)->getId();
// Шаг 3: Переносим дело
// crm.activity.binding.move не имеет типизированной обертки — вызываем через core
$serviceBuilder->core->call(
'crm.activity.binding.move',
[
'activityId' => $activityId,
'sourceEntityTypeId' => 1,
'sourceEntityId' => $firstLeadId,
'targetEntityTypeId' => 1,
'targetEntityId' => $newLeadId
]
);
echo 'Дело успешно перенесено.';
} catch (\Throwable $e) {
echo 'Ошибка: ' . $e->getMessage();
}
}
// Запрашиваем ID первого лида и фразу для поиска у пользователя
$firstLeadId = readline("Введите ID первого лида: ");
$searchPhrase = readline("Введите фразу для поиска по телу письма: ");
// Запускаем функцию
transferActivity($serviceBuilder, $firstLeadId, $searchPhrase);
import os
from b24pysdk import BitrixWebhook, Client
from b24pysdk.errors import BitrixAPIError
def transfer_activity(client, first_lead_id, search_phrase):
try:
activities = client.crm.activity.list(
filter={
"OWNER_TYPE_ID": 1,
"OWNER_ID": first_lead_id,
},
select=["ID", "OWNER_TYPE_ID", "OWNER_ID", "SUBJECT", "DESCRIPTION"],
).response.result
except BitrixAPIError as error:
print(f"Ошибка: {error}")
return
target_activity = None
for activity in activities:
if search_phrase in str(activity.get("DESCRIPTION") or ""):
target_activity = activity
break
if target_activity is None:
print(f"Дело с описанием, содержащим '{search_phrase}', не найдено.")
return
activity_id = int(target_activity["ID"])
try:
new_lead_id = client.crm.lead.add(
fields={
"TITLE": "Второй лид",
"ASSIGNED_BY_ID": 1,
},
params={
"REGISTER_SONET_EVENT": "Y",
},
).response.result
except BitrixAPIError as error:
print(f"Ошибка: {error}")
return
try:
result = client.crm.activity.binding.move(
activity_id=activity_id,
source_entity_type_id=1,
source_entity_id=first_lead_id,
target_entity_type_id=1,
target_entity_id=new_lead_id,
).response.result
except BitrixAPIError as error:
print(f"Ошибка: {error}")
else:
if result:
print("Дело успешно перенесено.")
client = Client(
BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
)
# B24_HOOK_TOKEN = 'user_id/webhook_key'
first_lead_id = int(input("Введите ID первого лида: "))
search_phrase = input("Введите фразу для поиска по телу письма: ")
transfer_activity(client, first_lead_id, search_phrase)
Проверим результат
Откройте карточку нового лида — в таймлайне появится перенесенное дело. В карточке исходного лида этого дела больше не будет: метод переносит связь, а не копирует ее.
Проверить результат через REST можно методом crm.activity.binding.list. Передайте в него activityId перенесенного дела — метод вернет все связи дела. После успешного переноса в ответе останется одна связь: тип объекта 1 и ID нового лида.
{
"result": [
{
"entityTypeId": 1,
"entityId": 1000979
}
]
}
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса.
|
Код |
Причина и действие |
|
|
Значения |
|
|
В |
|
|
Дело не привязано к элементу из |
|
|
Дело уже привязано к элементу, в который вы его переносите |
|
|
Дело или элемент CRM не найдены. Проверьте |
|
|
У пользователя нет прав на изменение элементов CRM |
|
|
Не переданы обязательные параметры. Метод требует все пять: |
Что важно учитывать
- Метод crm.activity.binding.move переносит дело только между элементами одного типа
- Сценарий работает не только для лидов. Чтобы перенести дело между двумя сделками, укажите
2вOWNER_TYPE_IDшага 1 и в обоих параметрах типа объекта шага 3, а целевую сделку создайте методом crm.deal.add. Значения для остальных типов — в справочнике типов объектов - Дело переносится вместе со всей историей: письмо или звонок исчезнет из таймлайна исходного элемента
- Вместе со связью у дела меняются собственные поля
OWNER_TYPE_IDиOWNER_ID— когда связь остается одна, владельцем становится ее элемент. Поэтому crm.activity.list с фильтром по исходному лиду перенесенное дело больше не вернет, ищите его по новому лиду - Метод crm.lead.add требует все обязательные поля лида вашего Битрикс24, состав полей проверяйте методом crm.lead.fields
- Повторный запуск примера создает еще один лид. Уже перенесенное дело в исходном лиде не найдется, и пример завершится сообщением, что дело не найдено