Как работать с полем Привязка к справочникам CRM
Scope:
crmКто может выполнять методы: чтобы пройти сценарий целиком, нужно самое строгое из перечисленных прав — административный доступ к разделу CRM
- crm.deal.userfield.add — администратор CRM
- crm.status.entity.types — любой пользователь
- crm.status.entity.items — любой пользователь
- crm.item.update — пользователь с правом «изменения» элементов объекта CRM
- crm.item.get — пользователь с правом «чтения» элементов объекта CRM
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
Поле «Привязка к справочникам CRM» хранит код варианта из системного справочника CRM. В настройках поля указывают идентификатор справочника, например INDUSTRY, а в сделку записывают строковый код выбранного варианта STATUS_ID, например IT.
Разберем поле на примере сделок. Создадим поле «Сфера клиента» с привязкой к справочнику «Сфера деятельности», получим его варианты, сохраним выбранный код в сделке и проверим результат.
Сценарий состоит из четырех шагов.
- Создадим поле методом crm.deal.userfield.add
- Получим варианты справочника методом crm.status.entity.items
- Запишем выбранный
STATUS_IDметодом crm.item.update - Проверим значение методом crm.item.get
В результате в поле UF_CRM_CLIENT_INDUSTRY будет сохранен код IT. В карточке сделки ему соответствует значение «Информационные технологии».
Что нужно до начала
Подготовьте данные сценария:
- Сделка, в которой заполним поле. Понадобится ее
id. У сделокentityTypeIdравен2 - Идентификатор справочника. В примере это
INDUSTRY. Идентификаторы доступных справочников возвращает метод crm.status.entity.types - Доступ к REST. Вебхук или приложение с правом
crm. Создавать пользовательские поля может только администратор CRM
Храните путь вебхука в переменной окружения и не публикуйте его в открытом коде.
В примерах используется сделка с id = 8417. Замените этот идентификатор на идентификатор своей сделки.
Для серверных JS-примеров с B24Hook нужен Node.js 18, 20, 22 или новее, для новых проектов — 22 или новее. B24JsSDK — ES module: сохраните код в файле .mjs или добавьте "type": "module" в package.json.
Для примеров с b24pysdk нужен Python 3.9 или новее.
Как использовать примеры в документации
1. Создадим поле «Сфера клиента»
Метод crm.deal.userfield.add создает пользовательское поле сразу для всех сделок.
Передадим в fields:
FIELD_NAME— код поля. ПрефиксUF_CRM_добавляется автоматически, если передать имя без негоUSER_TYPE_ID— тип поляcrm_statusMULTIPLE— значениеN, поскольку в сделке будет одна сфера клиентаEDIT_FORM_LABEL— название поля в карточке сделкиSETTINGS.ENTITY_TYPE— идентификатор справочникаINDUSTRY
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.com/rest/USER_ID/TOKEN/'
const response = await $b24.actions.v2.call.make({
method: 'crm.deal.userfield.add',
params: {
fields: {
FIELD_NAME: 'CLIENT_INDUSTRY',
USER_TYPE_ID: 'crm_status',
MULTIPLE: 'N',
EDIT_FORM_LABEL: { ru: 'Сфера клиента' },
SETTINGS: { ENTITY_TYPE: 'INDUSTRY' }
}
},
requestId: 'userfield-add-client-industry'
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
const fieldId = response.getData().result
console.log(fieldId)
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
// B24_HOOK = 'https://your-domain.bitrix24.com/rest/USER_ID/TOKEN/'
$fieldId = $serviceBuilder
->core
->call('crm.deal.userfield.add', [
'fields' => [
'FIELD_NAME' => 'CLIENT_INDUSTRY',
'USER_TYPE_ID' => 'crm_status',
'MULTIPLE' => 'N',
'EDIT_FORM_LABEL' => ['ru' => 'Сфера клиента'],
'SETTINGS' => ['ENTITY_TYPE' => 'INDUSTRY'],
],
])
->getResponseData()
->getResult();
print_r($fieldId);
import os
from b24pysdk import BitrixWebhook
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
# B24_HOOK_TOKEN = 'user_id/webhook_key'
response = token.call_method("crm.deal.userfield.add", {
"fields": {
"FIELD_NAME": "CLIENT_INDUSTRY",
"USER_TYPE_ID": "crm_status",
"MULTIPLE": "N",
"EDIT_FORM_LABEL": {"ru": "Сфера клиента"},
"SETTINGS": {"ENTITY_TYPE": "INDUSTRY"},
},
})
field_id = response["result"]
print(field_id)
Метод возвращает идентификатор созданного поля.
{
"result": 6007771
}
Полное имя поля — UF_CRM_CLIENT_INDUSTRY. Дальше передадим useOriginalUfNames: "Y", чтобы методы универсального CRM возвращали и принимали это имя без преобразования в camelCase.
Создавайте поле один раз. При повторном запуске шага используйте другое имя или пропустите создание, если поле уже существует.
2. Получим варианты справочника
Метод crm.status.entity.items возвращает варианты справочника. Передадим в entityId значение INDUSTRY, которое указали в настройках поля.
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
const response = await $b24.actions.v2.call.make({
method: 'crm.status.entity.items',
params: { entityId: 'INDUSTRY' },
requestId: 'status-entity-items-industry'
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
const items = response.getData().result
console.table(items)
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
$items = $serviceBuilder
->core
->call('crm.status.entity.items', ['entityId' => 'INDUSTRY'])
->getResponseData()
->getResult();
print_r($items);
import os
from b24pysdk import BitrixWebhook
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
items = token.call_method(
"crm.status.entity.items",
{"entityId": "INDUSTRY"},
)["result"]
print(items)
Сокращенный ответ:
{
"result": [
{
"NAME": "Информационные технологии",
"SORT": 10,
"STATUS_ID": "IT"
},
{
"NAME": "Телекоммуникации и связь",
"SORT": 20,
"STATUS_ID": "TELECOM"
},
{
"NAME": "Производство",
"SORT": 30,
"STATUS_ID": "MANUFACTURING"
}
]
}
Покажите пользователю значение NAME, а после выбора сохраните соответствующий STATUS_ID. Для варианта «Информационные технологии» это строка IT.
Не передавайте числовой ID записи справочника, ее название или код из другого справочника. Поле ожидает строковый STATUS_ID из ответа crm.status.entity.items для INDUSTRY.
Метод обновления сделки не проверяет принадлежность к справочнику и может сохранить неверное значение без ошибки. Проверяйте выбранный код на своей стороне до записи.
3. Запишем выбранный STATUS_ID в сделку
Метод crm.item.update обновляет сделку. Передадим:
entityTypeId— значение2для сделокid— идентификатор сделкиfields.UF_CRM_CLIENT_INDUSTRY— выбранныйSTATUS_ID, в примереITuseOriginalUfNames— значениеY, чтобы использовать исходное имя пользовательского поля
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
const response = await $b24.actions.v2.call.make({
method: 'crm.item.update',
params: {
entityTypeId: 2,
id: 8417,
useOriginalUfNames: 'Y',
fields: {
UF_CRM_CLIENT_INDUSTRY: 'IT'
}
},
requestId: 'crm-item-update-industry'
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
console.log(response.getData().result.item.UF_CRM_CLIENT_INDUSTRY)
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
$item = $serviceBuilder
->core
->call('crm.item.update', [
'entityTypeId' => 2,
'id' => 8417,
'useOriginalUfNames' => 'Y',
'fields' => [
'UF_CRM_CLIENT_INDUSTRY' => 'IT',
],
])
->getResponseData()
->getResult()['item'];
print_r($item['UF_CRM_CLIENT_INDUSTRY']);
import os
from b24pysdk import BitrixWebhook
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
item = token.call_method("crm.item.update", {
"entityTypeId": 2,
"id": 8417,
"useOriginalUfNames": "Y",
"fields": {
"UF_CRM_CLIENT_INDUSTRY": "IT",
},
})["result"]["item"]
print(item["UF_CRM_CLIENT_INDUSTRY"])
Сокращенный ответ:
{
"result": {
"item": {
"id": 8417,
"title": "Проверка поля Сфера клиента для REST-туториала",
"UF_CRM_CLIENT_INDUSTRY": "IT",
"entityTypeId": 2
}
}
}
4. Проверим сохраненное значение
Метод crm.item.get возвращает сделку. Передадим тот же entityTypeId, id и useOriginalUfNames.
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
const response = await $b24.actions.v2.call.make({
method: 'crm.item.get',
params: {
entityTypeId: 2,
id: 8417,
useOriginalUfNames: 'Y'
},
requestId: 'crm-item-get-industry'
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
const item = response.getData().result.item
console.log(item.UF_CRM_CLIENT_INDUSTRY)
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
$item = $serviceBuilder
->core
->call('crm.item.get', [
'entityTypeId' => 2,
'id' => 8417,
'useOriginalUfNames' => 'Y',
])
->getResponseData()
->getResult()['item'];
print_r($item['UF_CRM_CLIENT_INDUSTRY']);
import os
from b24pysdk import BitrixWebhook
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
item = token.call_method("crm.item.get", {
"entityTypeId": 2,
"id": 8417,
"useOriginalUfNames": "Y",
})["result"]["item"]
print(item["UF_CRM_CLIENT_INDUSTRY"])
Сокращенный ответ:
{
"result": {
"item": {
"id": 8417,
"title": "Проверка поля Сфера клиента для REST-туториала",
"UF_CRM_CLIENT_INDUSTRY": "IT",
"entityTypeId": 2
}
}
}
Метод возвращает код IT, а не название «Информационные технологии». Чтобы показать название в своем интерфейсе, сопоставьте код со значением NAME из ответа crm.status.entity.items.
Проверим результат
Сценарий выполнен успешно, если:
- метод crm.status.entity.items вернул для справочника
INDUSTRYвариант соSTATUS_ID: "IT" - после обновления сделки поле
UF_CRM_CLIENT_INDUSTRYсодержит строкуIT - повторный вызов crm.item.get возвращает то же значение
- в карточке сделки поле «Сфера клиента» показывает вариант «Информационные технологии»
Если код в ответе отличается от выбранного STATUS_ID, не считайте обновление успешным, даже когда crm.item.update вернул HTTP 200.
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса.
|
Код или текст ошибки |
Причина и действие |
|
Пустой код с текстом |
В crm.status.entity.items не передан |
|
Пустой код с текстом |
В |
|
Пустой код с текстом |
В crm.deal.userfield.add не передано имя поля. Передайте |
|
|
В |
|
|
В crm.item.update не передан идентификатор сделки |
|
|
Сделки с таким |
Метод вернул успех, но значение неверное
Поле типа crm_status не проверяет значение по справочнику при записи через REST. В тестовом Битрикс24 crm.item.update вернул HTTP 200 во всех трех случаях, а crm.item.get прочитал сохраненное значение:
- числовой
IDварианта539сохранился как строка"539" - несуществующий код
NOT_A_REAL_INDUSTRYсохранился без изменений - код
CALLиз справочникаSOURCEсохранился в поле, привязанном кINDUSTRY
Так же ведет себя и настройка поля. Если в SETTINGS.ENTITY_TYPE передать идентификатор несуществующего справочника, поле создается без ошибки и привязывается к первому справочнику из списка. Отличить такое поле можно по ответу crm.deal.userfield.list: у правильно настроенного поля ENTITY_TYPE приходит строкой INDUSTRY, а у поля с подменой — объектом с полями ID и NAME того справочника, который подставился.
Это не ошибки метода, поэтому они не входят в таблицу выше. Перед обновлением проверьте, что выбранное значение совпадает с одним из STATUS_ID, полученных для нужного entityId. После обновления прочитайте сделку и сравните сохраненный код с отправленным.
Что важно учитывать
INDUSTRY— идентификатор справочника, аIT— идентификатор его варианта. Эти значения нельзя менять местами- в поле сохраняется
STATUS_ID, а не числовойIDзаписи справочника и неNAME - crm.item.update не проверяет, существует ли код и относится ли он к справочнику из
SETTINGS.ENTITY_TYPE - варианты справочника берутся перед записью, а выбранный код сверяется с актуальным ответом crm.status.entity.items
- с параметром
useOriginalUfNames: "Y"поле называетсяUF_CRM_CLIENT_INDUSTRY, без него универсальные методы возвращают его какufCrmClientIndustry - создание поля выполняется один раз, а получение вариантов и запись значения — при каждом выборе пользователя
Пример кода
Код проходит все четыре шага: создает поле, получает варианты INDUSTRY, выбирает вариант «Информационные технологии», записывает его STATUS_ID в сделку и проверяет результат.
Замените вебхук и идентификатор сделки. Если поле уже существует, удалите из примера вызов crm.deal.userfield.add.
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
const dealId = 8417
async function call(method, params, requestId) {
const response = await $b24.actions.v2.call.make({ method, params, requestId })
if (!response.isSuccess) {
throw new Error(method + ': ' + response.getErrorMessages().join('; '))
}
return response.getData().result
}
// 1. Создаем поле, связанное со справочником INDUSTRY
await call('crm.deal.userfield.add', {
fields: {
FIELD_NAME: 'CLIENT_INDUSTRY',
USER_TYPE_ID: 'crm_status',
MULTIPLE: 'N',
EDIT_FORM_LABEL: { ru: 'Сфера клиента' },
SETTINGS: { ENTITY_TYPE: 'INDUSTRY' }
}
}, 'userfield-add-client-industry')
// 2. Получаем варианты и берем STATUS_ID выбранного варианта
const items = await call(
'crm.status.entity.items',
{ entityId: 'INDUSTRY' },
'status-entity-items-industry'
)
const selected = items.find((item) => item.NAME === 'Информационные технологии')
if (!selected) {
throw new Error('Вариант «Информационные технологии» не найден')
}
// 3. Записываем выбранный STATUS_ID в сделку
await call('crm.item.update', {
entityTypeId: 2,
id: dealId,
useOriginalUfNames: 'Y',
fields: {
UF_CRM_CLIENT_INDUSTRY: selected.STATUS_ID
}
}, 'crm-item-update-industry')
// 4. Читаем сделку и проверяем сохраненный код
const item = (await call('crm.item.get', {
entityTypeId: 2,
id: dealId,
useOriginalUfNames: 'Y'
}, 'crm-item-get-industry')).item
if (item.UF_CRM_CLIENT_INDUSTRY !== selected.STATUS_ID) {
throw new Error('Сохраненное значение не совпадает с выбранным STATUS_ID')
}
console.log(selected.NAME, item.UF_CRM_CLIENT_INDUSTRY)
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
$dealId = 8417;
function callMethod($serviceBuilder, string $method, array $params = []): array
{
return $serviceBuilder
->core
->call($method, $params)
->getResponseData()
->getResult();
}
// 1. Создаем поле, связанное со справочником INDUSTRY
callMethod($serviceBuilder, 'crm.deal.userfield.add', [
'fields' => [
'FIELD_NAME' => 'CLIENT_INDUSTRY',
'USER_TYPE_ID' => 'crm_status',
'MULTIPLE' => 'N',
'EDIT_FORM_LABEL' => ['ru' => 'Сфера клиента'],
'SETTINGS' => ['ENTITY_TYPE' => 'INDUSTRY'],
],
]);
// 2. Получаем варианты и берем STATUS_ID выбранного варианта
$items = callMethod(
$serviceBuilder,
'crm.status.entity.items',
['entityId' => 'INDUSTRY']
);
$selected = null;
foreach ($items as $item) {
if ($item['NAME'] === 'Информационные технологии') {
$selected = $item;
break;
}
}
if ($selected === null) {
throw new RuntimeException('Вариант «Информационные технологии» не найден');
}
// 3. Записываем выбранный STATUS_ID в сделку
callMethod($serviceBuilder, 'crm.item.update', [
'entityTypeId' => 2,
'id' => $dealId,
'useOriginalUfNames' => 'Y',
'fields' => [
'UF_CRM_CLIENT_INDUSTRY' => $selected['STATUS_ID'],
],
]);
// 4. Читаем сделку и проверяем сохраненный код
$item = callMethod($serviceBuilder, 'crm.item.get', [
'entityTypeId' => 2,
'id' => $dealId,
'useOriginalUfNames' => 'Y',
])['item'];
if ($item['UF_CRM_CLIENT_INDUSTRY'] !== $selected['STATUS_ID']) {
throw new RuntimeException('Сохраненное значение не совпадает с выбранным STATUS_ID');
}
echo $selected['NAME'] . ' ' . $item['UF_CRM_CLIENT_INDUSTRY'] . PHP_EOL;
import os
from b24pysdk import BitrixWebhook
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token=os.environ["B24_HOOK_TOKEN"],
)
deal_id = 8417
# 1. Создаем поле, связанное со справочником INDUSTRY
token.call_method("crm.deal.userfield.add", {
"fields": {
"FIELD_NAME": "CLIENT_INDUSTRY",
"USER_TYPE_ID": "crm_status",
"MULTIPLE": "N",
"EDIT_FORM_LABEL": {"ru": "Сфера клиента"},
"SETTINGS": {"ENTITY_TYPE": "INDUSTRY"},
},
})
# 2. Получаем варианты и берем STATUS_ID выбранного варианта
items = token.call_method(
"crm.status.entity.items",
{"entityId": "INDUSTRY"},
)["result"]
selected = next(
(item for item in items if item["NAME"] == "Информационные технологии"),
None,
)
if selected is None:
raise RuntimeError("Вариант «Информационные технологии» не найден")
# 3. Записываем выбранный STATUS_ID в сделку
token.call_method("crm.item.update", {
"entityTypeId": 2,
"id": deal_id,
"useOriginalUfNames": "Y",
"fields": {
"UF_CRM_CLIENT_INDUSTRY": selected["STATUS_ID"],
},
})
# 4. Читаем сделку и проверяем сохраненный код
item = token.call_method("crm.item.get", {
"entityTypeId": 2,
"id": deal_id,
"useOriginalUfNames": "Y",
})["result"]["item"]
if item["UF_CRM_CLIENT_INDUSTRY"] != selected["STATUS_ID"]:
raise RuntimeError("Сохраненное значение не совпадает с выбранным STATUS_ID")
print(selected["NAME"], item["UF_CRM_CLIENT_INDUSTRY"])