Основные методы работы
Table of Contents
Получение списка полей
Лид это комплексная структура состоящая из нескольких составных частей: основные данные, множественные поля, пользовательские поля.
Получить большую часть полей, можно через php код:
use \Bitrix\Main;
global $USER_FIELD_MANAGER;
if ( \Bitrix\Main\Loader::IncludeModule('crm') )
{
$fieldsInfo = \CCrmLead::GetFieldsInfo();
$typesID = array_keys( \CCrmFieldMulti::GetEntityTypeInfos() );
foreach($typesID as $typeID)
{
$fieldsInfo[$typeID] = [
'TYPE' => 'crm_multifield',
'ATTRIBUTES' => [\CCrmFieldInfoAttr::Multiple]
];
}
foreach ($fieldsInfo as $code => &$field)
{
$field['CAPTION'] = \CCrmLead::GetFieldCaption($code);
}
$userType = new \CCrmUserType(
$USER_FIELD_MANAGER,
\CCrmLead::$sUFEntityID
);
$userType->PrepareFieldsInfo($fieldsInfo);
/**
* Lead fields
* @array
*/
var_dump($fieldsInfo);
}
Однако следует учитывать некоторые разночтения после начала ввода новой архитектуры D7, в систему были добавлены DataManager’ы, которые в свою очередь имеют свой допустимый перечень полей. Можно посмотреть их в \Bitrix\Crm\LeadTable::getMap()
Получение списка лидов
Существует несколько способов получить перечень лидов из системы: старое API и DataManager. Каждый способ имеет свои преимущества и не достатки, что в конечном счете использовать должен выбрать разработчик.
Сравнение | Старое API | DataManager |
---|---|---|
Возможность получить данные из БД | v | v |
Учет прав при получении | v | x |
Простая фильтрация данных | v | v |
Использование под запросов для сложной фильтрации | x | v |
Резюмируя, в случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого api дает возможность использовать проверку прав.
Используя старое API
Для получения лидов используя старое API используется метод CCrmLead::GetListEx
.
Сигнатура метода:
$leadResult = CCrmLead::GetListEx(
$arOrder = array(),
$arFilter = array(),
$arGroupBy = false,
$arNavStartParams = false,
$arSelectFields = array(),
$arOptions = array()
);
Механизм получения данных аналогичен выборке из инфоблоков. По-умолчанию при выборке проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг CHECK_PERMISSIONS
со значением N
.
Пример: необходимо получить названия и ID лидов, которые созданные 1 января 2021 года без учета прав пользователя, отсортированные по источнику (убыванию)
$leadResult = CCrmLead::GetListEx(
[
'SOURCE_ID' => 'DESC'
],
[
'><DATE_CREATE' => [
'01.01.2021 00:00:00',
'01.01.2021 23:59:59'
],
'CHECK_PERMISSIONS' => 'N'
],
false,
false,
[
'ID',
'TITLE'
]
);
while( $lead = $leadResult->fetch() )
{
/**
* [ 'ID' => ..., 'TITLE' => ... ]
* @var array
*/
var_dump($lead);
var_dump($lead['ID']);
}
Отдельно стоит упомянуть наличие дополнительных возможностей фильтра и опций при работе с методом.
Прямое указание LIMIT и OFFSET
При помощи параметра QUERY_OPTIONS
в $arOptions
имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID.
Пример запроса:
$leadResult = CCrmLead::GetListEx(
['ID' => 'DESC'],
[],
false,
false,
[
'ID',
'TITLE'
],
[
'QUERY_OPTIONS' => [
'LIMIT' => 100,
'OFFSET' => 200
]
]
);
Запросы с участием внешних таблиц в фильтре
Иногда бывает необходимость достать только те лиды, для которых есть запись в сторонней таблице. Для этого можно воспользоваться __JOINS
ключом.
/**
* Entity alias. L - lead (default)
* @var string
*/
$entityAlias = 'L';
$leadResult = CCrmLead::GetListEx(
['ID' => 'DESC'],
[
'__JOINS' => [
[
'TYPE' => 'INNER',
'SQL' => 'INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = '.$entityAlias.'.ID'
]
],
],
false,
false,
[
'ID',
'TITLE'
]
);
/**
* Query:
* SELECT
* L.ID as ID, L.TITLE as TITLE
* FROM b_crm_lead L
* INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = L.ID
* ORDER BY L.ID DESC
*/
Но порой возникает необходимость не просто JOIN
к таблице, а полноценные сложные запросы. Для реализации таких запросов в фильтрации существует ключ __CONDITIONS
который добавляет любую строку к SQL запросу.
$leadResult = CCrmLead::GetListEx(
['ID' => 'DESC'],
[
'__CONDITIONS' => [
[
'SQL' => 'SOME_DUMP = 132'
]
],
],
false,
false,
[
'ID',
'TITLE'
]
);
/**
* SQL:
* SELECT
* L.ID as ID, L.TITLE as TITLE
* FROM b_crm_lead L
* WHERE SOME_DUMP = 132
* ORDER BY L.ID DESC
*/
Помните что это опасные операции из-за непроверяемых параметров, они открыты для SQL Injection.
Используя DataManager
Для получения лидов через DataManager используется класс \Bitrix\Crm\LeadTable
который является представлением для таблицы b_crm_lead. Для получения данных используется универсальный метод, который хорошо описан в документации.
Примечание: реализация DataManager архитектурно отличается от старого API, поэтому перечень полей для лидов старого и нового API может разниться. Актуальный список уже доступных полей можно найти получить из метода getMap(), а так же используя класс CCrmUserType (см. “Получение списка полей”).
Рассмотрим пример из старого лида в реализации DataManager.
use \Bitrix\Crm;
$leadResult = Crm\LeadTable::getList([
'select' => [
'ID',
'TITLE'
],
'filter' => [
'><DATE_CREATE' => [
new \Bitrix\Main\Type\DateTime('01.01.2021 00:00:00'),
new \Bitrix\Main\Type\DateTime('01.01.2021 23:59:59')
]
],
'order' => [
'SOURCE_ID' => 'DESC'
]
]);
foreach ($leadResult as $lead)
{
/**
* [ 'ID' => ..., 'TITLE' => ... ]
* @var array
*/
var_dump($lead);
var_dump($lead['ID']);
}
Создание лида
Добавление лида производится нестатическим методом Add класса CCrmLead. Сигнатура метода:
public function Add(array &$arFields, $bUpdateSearch = true, $options = array())
$arFields
- передающийся по ссылке массив полей добавляемого лида.
$bUpdateSearch
- флаг необходимости перерасчета поискового индекса.
$options
- дополнительные опции при добавлении лида.
Общий процесс добавления лида:
- Проверка прав на добавление
- Проверка обязательных полей
- Подготовка технических полей
- Вызов события OnBeforeCrmLeadAdd.
- Запись лида в таблицу
- Расчет прав
- Сохранение связанных сущностей
- Создание сообщения в ленту (по-умолчанию - да)
- Вызов события OnAfterCrmLeadAdd
- При наличии ORIGIN_ID вызов события OnAfterExternalCrmLeadAdd
- Push обновление kanban
Технически, лид не является простой сущностью и состоит из нескольких структур:
- Общие данные
- Множественные поля
- Наблюдатели
- Адреса
- Связанные контакты
Однако на практике, не имеет смысла разделять их между собой. Ниже представлен код иллюстрирующий добавление лида.
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
/**
* Поля добавляемого лида
* @var array
*/
$leadFields = [
// Основные поля
'TITLE' => 'Андрей - Форма обратной связи',
'NAME' => 'Андрей',
"COMMENTS" => "Текст который Андрей ввел в форму обратной связи",
"FM" => [
"PHONE" => [
"n0" => [
"VALUE" => '+78889996644',
"VALUE_TYPE" => "WORK",
],
"n1" => [
"VALUE" => '+7 (495) 888-66-44',
"VALUE_TYPE" => "HOME",
]
],
"EMAIL" => [
"n0" => [
"VALUE" => 'some@email.com',
"VALUE_TYPE" => "WORK",
],
],
],
// Технические поля
"OPENED" => "Y", // "Доступен для всех" = Да
"OBSERVER_IDS" => [
1 // Добавим в наблюдателей - администратора
],
"ASSIGNED_BY_ID" => 123, // По-умолчанию ответственным будет пользователь с ID:123
// Поля для маркетинга
'SOURCE_ID' => 'WEB',
'SOURCE_DESCRIPTION' => 'Пришел с dev.1c-bitrix.ru',
];
$leadEntity = new \CCrmLead( $bCheckRight );
$leadId = $leadEntity->Add(
$leadFields,
$bUpdateSearch = true,
$arOptions = [
/**
* ID пользователя, от лица которого выполняется действие
* в том числе проверка прав
* @var integer
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Устанавливайте флаг, только если сущность проходит
* процедуру восстановления. В случае если флаг есть
* можно заполнять технические поля DATE_CREATE, DATE_MODIFY
* @var boolean
*/
// 'IS_RESTORATION' => true,
/**
* В случае если флаг true при добавлении лида не будут проверяться:
* - Поля обязательные со стадии
* - Валидация пользовательских полей
* @var boolean
*/
'DISABLE_USER_FIELD_CHECK' => false,
/**
* В случае если флаг имеет значение true, а флаг
* DISABLE_USER_FIELD_CHECK не определен или false
* не будет проверять обязательность полей со стадии, но
* не отменяет валидацию пользовательских полей
*/
'DISABLE_REQUIRED_USER_FIELD_CHECK' => false,
]
);
if ( !$leadId )
{
/**
* Произошла ошибка при добавлении лида, посмотреть ее можно
* через любой из способов ниже:
* 1. $leadFields['RESULT_MESSAGE']
* 2. $leadEntity->LAST_ERROR
*/
}
Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить соответствующую статью
Обновление лида
Обновление (изменение) лида производится нестатическим методом Update
класса CCrmLead
.
Сигнатура метода:
public function Update($ID, array &$arFields, $bCompare = true, $bUpdateSearch = true, $options = array())
$ID
- идентификатор изменяемого лида
$arFields
- передающийся по ссылке массив полей изменяемого лида.
$bCompare
- флаг необходимости проведения сравнения с предыдущими значениями для фиксации событий изменения лида.
bUpdateSearch
- флаг необходимости расчета старого поиска.
$options
- дополнительные опции при обновлении лида.
Общий процесс обновления лида:
- Получение текущих данных по лиду
- Проверка обязательных полей
- Проверка прав на добавление
- Вызов события OnBeforeCrmLeadUpdate (при необходимости).
- Подготовка технических полей (наблюдатели, контакты, статусы).
- Проведения сравнения с предыдущими значениями (при необходимости)
- Сброс кеша
- Запись изменений лида в таблицу
- Расчет прав
- Перерасчет привязанных контактов
- Сохранение наблюдателей
- Сохранение адреса (если используется)
- Проверка финальной стадии и завершения дел (при необходимости)
- Запись в статистические таблицы и историю лида
- Запись в контроль дубликатов
- Обработка UTM полей
- Обновление поискового индекса
- Запись сообщения в ленту лида/чат
- Вызов события OnAfterCrmLeadUpdate
- Добавление наблюдателей в канбане
- Отправка данных в ML (при необходимости)
Ниже представлен код иллюстрирующий изменение лида.
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
/**
* Идентификато изменяемого лида
* @var integer
*/
$leadId = 123;
/**
* Поля изменяемого лида
* @var array
*/
$leadFields = [
// Основные поля
'TITLE' => 'Андрей - Форма обратной связи',
'NAME' => 'Андрей',
"COMMENTS" => "Текст который Андрей ввел в форму обратной связи",
"FM" => [
"PHONE" => [
// Телефон с ID 3567 будет изменен
"3567" => [
"VALUE" => '+78889996644',
"VALUE_TYPE" => "WORK",
],
// Телефон в ID 1234 будет удален
"1234" => [
"VALUE" => '',
"VALUE_TYPE" => "HOME",
]
],
],
"ASSIGNED_BY_ID" => 123,
];
$leadEntity = new \CCrmLead( $bCheckRight );
$isUpdateSuccess = $leadEntity->Update(
$leadId
$leadFields,
$bCompare = true,
$bUpdateSearch = true,
$arOptions = [
/**
* ID пользователя, от лица которого выполняется действие
* в том числе проверка прав
* @var integer
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Флаг системного действия. В случае true в лиде не будут
* занесены данные о пользователе который производит действие
* и дата изменения лида не изменится.
* @var boolean
*/
'IS_SYSTEM_ACTION' => false,
/**
* Флаг отвечающий на необходимость обработки событий.
* В случае false события не будут вызваны
* @var boolean
*/
'ENABLE_SYSTEM_EVENTS' => true,
/**
* Флаг синхронизации семантической стадии сделки.
* При false битрикс не будет проверять изменилась ли семантика стадии
*
* Рекомендуется всегда использовать значение по-умолчанию.
* @var boolean
*/
'SYNCHRONIZE_STATUS_SEMANTICS' => true,
/**
* В случае если флаг true битрикс запросит конфигурацию CRM необходимо ли завершать дела при завершении сущности.
* @var boolean
*/
'ENABLE_ACTIVITY_COMPLETION' => true,
/**
* В случае true, битрикс создаст сообщение в ленту о новом лиде
* @var boolean
*/
'REGISTER_SONET_EVENT' => true,
/**
* В случае если флаг true при добавлении лида не будут проверяться:
* - Поля обязательные со стадии
* - Валидация пользовательских полей
* @var boolean
*/
'DISABLE_USER_FIELD_CHECK' => false,
/**
* В случае если флаг имеет значение true, а флаг
* DISABLE_USER_FIELD_CHECK не определен или false
* не будет проверять обязательность полей со стадии, но
* не отменяет валидацию пользовательских полей
*/
'DISABLE_REQUIRED_USER_FIELD_CHECK' => false,
]
);
if ( !$isUpdateSuccess )
{
/**
* Произошла ошибка при обновлении лида, посмотреть ее можно
* через любой из способов ниже:
* 1. $leadFields['RESULT_MESSAGE']
* 2. $leadEntity->LAST_ERROR
*/
}
Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить соответствующую статью
Удаление лида
Удаление лидов в системе осуществляется исключительно по ID.
Общий процесс удаления лида:
- Проверка существования лида
- Вызов события OnBeforeCrmLeadDelete.
- Удаление лида
- Очистка связанных данных
- Вызов события OnAfterCrmLeadDelete
За удаление отвечает нестатический метод Delete класса CCrmLead, который имеет следующую сигнатуру:
public function Delete($ID, $arOptions = array()): bool
Полное описание метода удаления на примере лида с идентификатором 123:
/**
* Идентификатор лида для удаления
* @var integer
*/
$entityId = 123;
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
$leadEntity = new \CCrmLead( $bCheckRight );
$deleteResult = $leadEntity->Delete(
$entityId,
[
/**
* ID пользователя, от лица которого выполняется операция
* Значение по-умолчанию: ID текущего пользователя
* @var int
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Удалить связанные бизнес-процессы
* Значение по-умолчанию: true
* @var boolean
*/
'PROCESS_BIZPROC' => true,
/**
* Включить отложенное удаление
* Значение по-умолчанию хранится в методе \Bitrix\Crm\Settings\LeadSettings::getCurrent()->isDeferredCleaningEnabled()
* @var boolean
*/
'ENABLE_DEFERRED_MODE' => \Bitrix\Crm\Settings\LeadSettings::getCurrent()->isDeferredCleaningEnabled()
/**
* Пометить кеш дубликатов не актуальным
* Значение по-умолчанию: true
* @var boolean
*/
'ENABLE_DUP_INDEX_INVALIDATION' => true,
]
);
if ( !$deleteResult )
{
// Операция не удалась
var_dump($entity->LAST_ERROR);
}
Это излишнее описание с указанием значений по-умолчанию. В большинстве случае достаточно будет использовать упрощенную форму:
/**
* Идентификатор лида для удаления
* @var integer
*/
$entityId = 123;
/**
* Идентификатор пользователя, чье имя нужно занести в историю
* @var integer
*/
$logHistoryUserId = \CCrmSecurityHelper::GetCurrentUserID();
$leadEntity = new \CCrmLead( false );
$deleteResult = $leadEntity->Delete(
$entityId,
[
'CURRENT_USER' => $logHistoryUserId,
]
);
if ( !$deleteResult )
{
// Операция не удалась
var_dump($entity->LAST_ERROR);
}