Методы для работы с Сделками в модуле CRM Битрикс24
Сделка это комплексная структура состоящая из нескольких составных частей:
- Основные данные
- Регулярность
- Пользовательские поля
Получение списка полей
Получить большую часть полей, можно через php код:
\Bitrix\Main\Loader::IncludeModule('crm');
global $USER_FIELD_MANAGER;
if ( \Bitrix\Main\Loader::IncludeModule('crm') )
{
$fieldsInfo = \CCrmDeal::GetFieldsInfo();
foreach ($fieldsInfo as $code => &$field)
{
$field['CAPTION'] = \CCrmDeal::GetFieldCaption($code);
}
$userType = new \CCrmUserType(
$USER_FIELD_MANAGER,
\CCrmDeal::$sUFEntityID
);
$userType->PrepareFieldsInfo($fieldsInfo);
var_dump($fieldsInfo);
}
Однако следует учитывать некоторые разночтения после начала ввода новой архитектуры D7, в систему были добавлены DataManager'ы, которые в свою очередь имеют свой допустимый перечень полей. Можно посмотреть их в \Bitrix\Crm\DealTable::getMap()
Получение списка
Существует несколько способов получить перечень лидов из системы:
| Сравнение | Старое API | DataManager |
|---|---|---|
| Возможность получить данные из БД | v | v |
| Учет прав при получении | v | x |
| Простая фильтрация данных | v | v |
| Использование под запросов для сложной фильтрации | x | v |
В случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого API дает возможность использовать проверку прав.
Используя старое API
Для получения контактов используя метод CCrmContact::GetListEx.
Сигнатура метода:
$entityResult = \CCrmDeal::GetListEx(
$arOrder = array(),
$arFilter = array(),
$arGroupBy = false,
$arNavStartParams = false,
$arSelectFields = array(),
$arOptions = array()
);
Механизм получения данных аналогичен выборке из инфоблоков. По-умолчанию при выборке данных проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг CHECK_PERMISSIONS со значением N.
Необходимо получить Название и ID сделок, которые созданы 1 января 2021 года без учета прав пользователя, отсортированные по источнику убыванию.
\Bitrix\Main\Loader::IncludeModule('crm');
$entityResult = \CCrmDeal::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 ($entity = $entityResult->fetch()) {
var_dump($entity);
var_dump($entity['ID']);
}
Отдельно стоит упомянуть наличие дополнительных возможностей фильтра и опций при работе с методом.
Прямое указание LIMIT и OFFSET
При помощи параметра QUERY_OPTIONS в $arOptions имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID.
Пример запроса:
\Bitrix\Main\Loader::IncludeModule('crm');
$entityResult = \CCrmDeal::GetListEx(
['ID' => 'DESC'],
[],
false,
false,
[
'ID',
'TITLE'
],
[
'QUERY_OPTIONS' => [
'LIMIT' => 100,
'OFFSET' => 200
]
]
);
Запросы с участием внешних таблиц в фильтре
Иногда бывает необходимость достать только те элементы, для которых есть запись в сторонней таблице. Для этого можно воспользоваться __JOINS ключом.
$entityAlias = 'D';
$entityResult = \CCrmDeal::GetListEx(
['ID' => 'DESC'],
[
'__JOINS' => [
[
'TYPE' => 'INNER',
'SQL' => 'INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = '.$entityAlias.'.ID'
]
],
],
false,
false,
[
'ID',
'TITLE'
]
);
Пример запроса:
SELECT
D.ID as ID, D.TITLE as TITLE
FROM b_crm_deal D
INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = D.ID
ORDER BY D.ID DESC
Но порой возникает необходимость не просто JOIN к таблице, а полноценные сложные запросы. Для реализации таких запросов в фильтрации существует ключ __CONDITIONS который добавляет любую строку к SQL запросу.
$entityResult = \CCrmDeal::GetListEx(
['ID' => 'DESC'],
[
'__CONDITIONS' => [
[
'SQL' => 'SOME_DUMP = 132'
]
],
],
false,
false,
[
'ID',
'TITLE'
]
);
Пример запроса:
SELECT
D.ID as ID, D.TITLE as TITLE
FROM b_crm_deal D
WHERE SOME_DUMP = 132
ORDER BY D.ID DESC
Помните что это опасные операции из-за непроверяемых параметров, они открыты для SQL Injection.
Используя DataManager
Для получения сделок через DataManager используется класс \Bitrix\Crm\DealTable который является представлением для таблицы b_crm_deal. Для получения данных используется универсальный метод, который хорошо описан в документации.
Реализация DataManager архитектурно отличается от старого API, поэтому перечень полей для контакта старого и нового API может разниться. Актуальный список уже доступных полей можно найти получить из метода getMap(), а так же используя класс CCrmUserType.
Рассмотрим пример из старой сделки в реализации DataManager.
\Bitrix\Main\Loader::IncludeModule('crm');
$entityResult = \Bitrix\Crm\DealTable::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' => [
'ID' => 'DESC'
]
]);
foreach ($entityResult as $entity) {
var_dump($entity);
var_dump($entity['ID']);
}
Создание сделки
Добавление сделки производится нестатическим методом Add класса CCrmDeal.
Сигнатура метода:
public function Add(
array &$arFields,
$bUpdateSearch = true,
$options = array()
)
$arFields — передающийся по ссылке массив полей добавляемого элемента. $bUpdateSearch — флаг необходимости перерасчета поискового индекса. $options — дополнительные опции при добавлении элемента.
Общий процесс добавления сделки:
- Проверка прав на добавление
- Проверка обязательных полей
- Подготовка технических полей
- Вызов события
OnBeforeCrmDealAdd. - Запись в таблицу
- Сохранение пользовательских полей
- Расчет прав
- Сохранение Наблюдателей
- Классификация сделки (Повторное обращение, Повторная сделка)
- Расчет статистических данных
- Запись в timline
- Расчет цепочки для сквозной аналитики
- Индексация для поиска
- Регистрация сообщения соц. сети
- Нотификация о создании элемента
- Вызов события
OnAfterCrmDealAdd - При наличии ORIGIN_ID вызов события
OnAfterExternalCrmDealAdd - Отправка push-сообщений для обновления канбана и визуализации добавления элемента
Ниже представлен код иллюстрирующий создание:
\Bitrix\Main\Loader::IncludeModule('crm');
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
/**
* Добавляемая сущность
* @var array
*/
$entityFields = [
'TITLE' => 'Сделка года',
'STAGE_ID' => 'NEW',
'PROBABILITY' => '100',
'CURRENCY_ID' => 'RUB',
'OPPORTUNITY' => 1000000.00,
'COMPANY_ID' => 1,
'CONTACT_IDS' => [
1,
2,
],
'BEGINDATE' => '01.01.2021',
'CLOSEDATE' => '31.12.2022',
'OPENED' => 'Y',
'COMMENTS' => "Some comment! Yeah!",
'ASSIGNED_BY_ID' => 1,
'SOURCE_ID' => 'OTHER',
'SOURCE_DESCRIPTION' => 'Мой контакт',
];
$entityObject = new \CCrmDeal($bCheckRight);
$entityId = $entityObject->Add(
$entityFields,
$bUpdateSearch = true,
$arOptions = [
/**
* ID пользователя, от лица которого выполняется действие
* в том числе проверка прав
* @var integer
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Устанавливайте флаг, только если сущность проходит
* процедуру восстановления. В случае если флаг есть
* можно заполнять технические поля DATE_CREATE, DATE_MODIFY
* @var boolean
*/
// 'IS_RESTORATION' => true,
/**
* Флаг жестко определяющий поведение с полем "Дата завершения"
* При установке в true указывает что при переводе сделку в
* финальный статус нужно обновить значение поля "Дата завершения"
* @var boolean
*/
//'ENABLE_CLOSE_DATE_SYNC' => true,
/**
* Флаг обозначающий запрет на создании записи в timeline элемента
* о создании.
* @var char
*/
//'DISABLE_TIMELINE_CREATION' => 'Y'
/**
* В случае true, битрикс создаст сообщение в ленту о создании
* @var boolean
*/
//'REGISTER_SONET_EVENT' => true,
/**
* В случае если флаг true не будут проверяться:
* - Пользовательские обязательные поля
* - Валидация пользовательских полей
* @var boolean
*/
'DISABLE_USER_FIELD_CHECK' => false,
/**
* В случае если флаг true, не будет проверки
* обязательности заполнения пользовательских полей
*
* Если флаг 'DISABLE_USER_FIELD_CHECK' установлен в true,
* данный флаг игнорируется - проверок не будет
*
* Флаг не отменяет необходимость корректного заполнения
* переданных полей.
* @var boolean
*/
'DISABLE_REQUIRED_USER_FIELD_CHECK' => false,
]
);
if (!$entityId) {
/**
* Произошла ошибка при добавлении сущности, посмотреть ее можно
* через любой из способов ниже:
* 1. $entityFields['RESULT_MESSAGE']
* 2. $entityObject->LAST_ERROR
*/
}
Обновление сделки
Обновление (изменение) сделки производится нестатическим методом Update класса CCrmDeal.
Сигнатура метода:
public function Update(
$ID,
array &$arFields,
$bCompare = true,
$bUpdateSearch = true,
$options = array()
)
$ID — идентификатор изменяемого элемента. $arFields — передающийся по ссылке массив полей изменяемого элемента. $bCompare — флаг необходимости проведения сравнения с предыдущими значениями для фиксации события изменений. bUpdateSearch — флаг необходимости расчета старого поиска. $options — дополнительные опции при обновлении элемента.
Общий процесс обновления:
- Получение текущих данных
- Проверка обязательных полей
- Проверка прав на изменение
- Вызов события
OnBeforeCrmDealUpdate, если опцияENABLE_SYSTEM_EVENTSне определена в false - Подготовка технических полей (стадий, дат обновлений, реляций).
- Проведения сравнения с предыдущими значениями (при необходимости)
- Запись изменений в таблицу
- Сохранение пользовательских полей
- Расчет прав
- Перепривязка контактов
- Сохранение наблюдателей
- Классификация сделки
- Завершение дел, при закрытии сделки
- Запись в статистические таблицы и историю
- Обновление UTM полей
- Обновление поискового индекса
- Запись изменений в timeline
- Запись сообщения в ленту сделки/чат
- Вызов события
OnAfterCrmDealUpdate, если опцияENABLE_SYSTEM_EVENTSне определена в false - Если доступно ML (Machine learning) и это не системное действие отправка в ML
- Отправка push-сообщений для обновления канбана и визуализации добавления элемента
Ниже представлен код иллюстрирующий изменение элемента.
\Bitrix\Main\Loader::IncludeModule('crm');
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
/**
* Идентификатор изменяемого элемента
* @var integer
*/
$entityId = 123;
/**
* Поля изменяемого элемента
* @var array
*/
$entityFields = [
// Отметим сделку выполненной
'STAGE_ID' => 'WON',
];
$entityObject = new \CCrmDeal($bCheckRight);
$isUpdateSuccess = $entityObject->Update(
$entityId,
$entityFields,
$bCompare = true,
$bUpdateSearch = true,
$arOptions = [
/**
* ID пользователя, от лица которого выполняется действие
* в том числе проверка прав
* @var integer
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Флаг системного действия. В случае true у элемента не будут
* занесены данные о пользователе который производит действие
* и дата изменения элемента не изменится.
* @var boolean
*/
'IS_SYSTEM_ACTION' => false,
/**
* В случае true, битрикс создаст сообщение в ленту о изменении
* @var boolean
*/
'REGISTER_SONET_EVENT' => true,
/**
* Флаг жестко определяющий поведение с полем "Дата завершения"
* При установке в true указывает что при переводе сделку в
* финальный статус нужно обновить значение поля "Дата завершения"
* @var boolean
*/
//'ENABLE_CLOSE_DATE_SYNC' => true,
/**
* Флаг обозначающий запрет на создании записи в timeline элемента
* о создании.
* @var char
*/
//'DISABLE_TIMELINE_CREATION' => 'Y'
//
/**
* Флаг для вызова системных событий.
* При установке в false не будут срабатывать событие
* @var boolean
*/
'ENABLE_SYSTEM_EVENTS' => true,
/**
* Необходимо ли перерасчитывать семантическую стадию сделки
* @var boolean
*/
'SYNCHRONIZE_STAGE_SEMANTICS' => true,
/**
* В случае если флаг true не будут проверяться:
* - Пользовательские обязательные поля
* - Валидация пользовательских полей
* @var boolean
*/
'DISABLE_USER_FIELD_CHECK' => false,
/**
* В случае если флаг true, не будет проверки
* обязательности заполнения пользовательских полей
*
* Если флаг `DISABLE_USER_FIELD_CHECK` установлен в true,
* данный флаг игнорируется - проверок не будет
*
* Флаг не отменяет необходимость корректного заполнения
* переданных полей.
* @var boolean
*/
'DISABLE_REQUIRED_USER_FIELD_CHECK' => false,
]
);
if (!$isUpdateSuccess) {
/**
* Произошла ошибка при обновлении элемента, посмотреть ее можно
* через любой из способов ниже:
* 1. $entityFields['RESULT_MESSAGE']
* 2. $entityObject->LAST_ERROR
*/
}
Удаление сделки
Удаление в системе осуществляется исключительно по ID.
Общий процесс удаления:
- Проверка существования элемента и прав на него
- Вызов события
OnBeforeCrmDealDelete. - Удаление элемента
- Очистка связанных данных
- Вызов события
OnAfterCrmDealDelete
За удаление отвечает нестатический метод Delete класса CCrmDeal, который имеет следующую сигнатуру:
public function Delete(
$ID,
$arOptions = array()
): bool
Полное описание метода удаления на примере элемента с идентификатором 123:
\Bitrix\Main\Loader::IncludeModule('crm');
/**
* Идентификатор для удаления
* @var integer
*/
$entityId = 123;
/**
* true, если нужно проверять права текущего пользователя.
* Текущий пользователь определяется ID в ключе CURRENT_USER
* $arOptions
* @var boolean
*/
$bCheckRight = true;
$entityObject = new \CCrmDeal($bCheckRight);
$deleteResult = $entityObject->Delete(
$entityId,
[
/**
* ID пользователя, от лица которого выполняется операция
* Значение по-умолчанию: ID текущего пользователя
* @var int
*/
'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),
/**
* Удалить связанные бизнес-процессы
* Значение по-умолчанию: true
* @var boolean
*/
'PROCESS_BIZPROC' => true,
/**
* Включить отложенное удаление
* Значение по-умолчанию хранится в методе \Bitrix\Crm\Settings\DealSettings::getCurrent()->isDeferredCleaningEnabled()
* @var boolean
*/
'ENABLE_DEFERRED_MODE' => \Bitrix\Crm\Settings\DealSettings::getCurrent()->isDeferredCleaningEnabled(),
/**
* Удалить данные сделки из статистических отчетов
* Значение по-умолчанию: true
* @var boolean
*/
'REGISTER_STATISTICS' => true,
]
);
if (!$deleteResult) {
// Операция не удалась
var_dump($entityObject->LAST_ERROR);
}
Это излишнее описание с указанием значений по-умолчанию. В большинстве случае достаточно будет использовать упрощенную форму:
\Bitrix\Main\Loader::IncludeModule('crm');
/**
* Идентификатор для удаления
* @var integer
*/
$entityId = 123;
/**
* Идентификатор пользователя, чье имя нужно занести в историю
* @var integer
*/
$logHistoryUserId = \CCrmSecurityHelper::GetCurrentUserID();
$entityObject = new \CCrmDeal(false);
$deleteResult = $entityObject->Delete(
$entityId,
[
'CURRENT_USER' => $logHistoryUserId,
]
);
if (!$deleteResult) {
// Операция не удалась
var_dump($entityObject->LAST_ERROR);
}