CRM
Смарт-процессы
Работа со смарт-процессами CRM через PHP и фабрики: entityTypeId, получение, добавление, изменение, удаление, поля, стадии, связи и действия операций.
Смарт-процесс — это пользовательский тип CRM. Для PHP-кода главный идентификатор —
entityTypeId. Именно его передают в getFactory().
Общее понимание
Со смарт-процессами удобнее всего работать через универсальное CRM API: контейнер, фабрику, элемент и операции.
Что такое entityTypeId
Для стандартных сущностей есть константы: CCrmOwnerType::Deal,
CCrmOwnerType::Company, CCrmOwnerType::Contact. Для
смарт-процесса используется его числовой entityTypeId.
| Сущность | Тип |
|---|---|
| Лид | CCrmOwnerType::Lead |
| Сделка | CCrmOwnerType::Deal |
| Контакт | CCrmOwnerType::Contact |
| Компания | CCrmOwnerType::Company |
| Смарт-процесс | Числовой entityTypeId, например 1044. |
Получить фабрику
Если фабрика вернула null, значит тип не найден или для него нельзя
получить фабрику.
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Получает фабрику смарт-процесса.
*/
function fetchSmartProcessFactory(int $entity_type_id)
{
$container = Service\Container::getInstance();
return $container->getFactory($entity_type_id);
}
$factory = fetchSmartProcessFactory(SMART_PROCESS_ENTITY_TYPE_ID);
if ($factory === null) {
echo 'Фабрика смарт-процесса не найдена';
} Основные операции
Получение, добавление, изменение и удаление элементов смарт-процесса.
Получить элемент
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Получает элемент смарт-процесса.
*/
function fetchSmartProcessItem(int $entity_type_id, int $item_id)
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return null;
}
return $factory->getItem($item_id);
}
$item = fetchSmartProcessItem(SMART_PROCESS_ENTITY_TYPE_ID, $item_id);
if ($item !== null) {
$item_data = $item->toArray();
$title = $item->getTitle();
print_r($item_data);
} Получить список элементов
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
const SMART_PROCESS_LIMIT = 100;
Loader::includeModule('crm');
/**
* Получает элементы смарт-процесса по фильтру.
*/
function fetchSmartProcessItems(int $entity_type_id, array $filter): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [];
}
return $factory->getItems([
'select' => [
'ID',
'TITLE',
'STAGE_ID',
'ASSIGNED_BY_ID',
'CREATED_TIME',
],
'filter' => $filter,
'order' => [
'ID' => 'ASC',
],
'limit' => SMART_PROCESS_LIMIT,
]);
}
$items = fetchSmartProcessItems(
SMART_PROCESS_ENTITY_TYPE_ID,
[
'>ID' => 0,
]
);
foreach ($items as $item) {
print_r($item->toArray());
} Добавить элемент
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Добавляет элемент смарт-процесса.
*/
function addSmartProcessItem(int $entity_type_id, array $item_fields): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [
'is_success' => false,
'item_id' => 0,
'error_messages' => ['Фабрика смарт-процесса не найдена'],
];
}
$item = $factory->createItem($item_fields);
$operation = $factory->getAddOperation($item);
$operation_result = $operation->launch();
return [
'is_success' => $operation_result->isSuccess(),
'item_id' => (int) $item->getId(),
'error_messages' => $operation_result->getErrorMessages(),
];
}
$item_fields = [
'TITLE' => $title,
'ASSIGNED_BY_ID' => $assigned_by_id,
'STAGE_ID' => $stage_id,
'UF_CRM_8_1234567890' => $custom_value,
];
$add_result = addSmartProcessItem(SMART_PROCESS_ENTITY_TYPE_ID, $item_fields);
print_r($add_result); Изменить элемент
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Изменяет поля элемента смарт-процесса.
*/
function updateSmartProcessItem(int $entity_type_id, int $item_id, array $item_fields): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [
'is_success' => false,
'error_messages' => ['Фабрика смарт-процесса не найдена'],
];
}
$item = $factory->getItem($item_id);
if ($item === null) {
return [
'is_success' => false,
'error_messages' => ['Элемент смарт-процесса не найден'],
];
}
foreach ($item_fields as $field_id => $field_value) {
$item->set($field_id, $field_value);
}
$operation = $factory->getUpdateOperation($item);
$operation_result = $operation->launch();
return [
'is_success' => $operation_result->isSuccess(),
'error_messages' => $operation_result->getErrorMessages(),
];
}
$update_result = updateSmartProcessItem(
SMART_PROCESS_ENTITY_TYPE_ID,
$item_id,
[
'TITLE' => $title,
'STAGE_ID' => $stage_id,
'UF_CRM_8_1234567890' => $custom_value,
]
);
print_r($update_result); Удалить элемент
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Удаляет элемент смарт-процесса.
*/
function deleteSmartProcessItem(int $entity_type_id, int $item_id): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [
'is_success' => false,
'error_messages' => ['Фабрика смарт-процесса не найдена'],
];
}
$item = $factory->getItem($item_id);
if ($item === null) {
return [
'is_success' => false,
'error_messages' => ['Элемент смарт-процесса не найден'],
];
}
$operation = $factory->getDeleteOperation($item);
$operation_result = $operation->launch();
return [
'is_success' => $operation_result->isSuccess(),
'error_messages' => $operation_result->getErrorMessages(),
];
}
$delete_result = deleteSmartProcessItem(SMART_PROCESS_ENTITY_TYPE_ID, $item_id);
print_r($delete_result); Поля и настройки
У каждого смарт-процесса свой набор полей, стадий, направлений и настроек.
Получить поля
Перед работой с незнакомым смарт-процессом полезно вывести описание обычных и пользовательских полей.
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Получает описание полей смарт-процесса.
*/
function fetchSmartProcessFieldsInfo(int $entity_type_id): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [];
}
return [
'fields' => $factory->getFieldsInfo(),
'user_fields' => $factory->getUserFieldsInfo(),
];
}
$fields_info = fetchSmartProcessFieldsInfo(SMART_PROCESS_ENTITY_TYPE_ID);
print_r($fields_info); Стадии и воронки
Если у смарт-процесса включены направления и стадии, их можно получить через фабрику.
<?php
use Bitrix\Main\Loader;
use Bitrix\Crm\Service;
const SMART_PROCESS_ENTITY_TYPE_ID = 1044;
Loader::includeModule('crm');
/**
* Получает стадии смарт-процесса.
*/
function fetchSmartProcessStages(int $entity_type_id, ?int $category_id = null): array
{
$factory = Service\Container::getInstance()->getFactory($entity_type_id);
if ($factory === null) {
return [];
}
if (!$factory->isStagesEnabled()) {
return [];
}
$stages = [];
$stage_collection = $factory->getStages($category_id);
foreach ($stage_collection as $stage) {
$stages[] = $stage->collectValues();
}
return $stages;
}
$stages = fetchSmartProcessStages(SMART_PROCESS_ENTITY_TYPE_ID, $category_id);
print_r($stages); Родительские связи
Смарт-процесс может быть связан со сделкой, контактом, компанией или другим элементом
CRM. Коды полей связи зависят от настроек типа. Перед использованием лучше вывести
toArray() конкретного элемента и описание полей через
getFieldsInfo().
На практике часто встречаются поля вида PARENT_ID_2 для связи со сделкой
или похожие системные поля. Точный код нужно проверять на своём портале.
События и действия
У смарт-процессов есть REST-события для приложений. В коробочном PHP для изменения логики чаще используют действия операций: до сохранения, после сохранения, после удаления и так далее.
REST-события элементов
REST-события смарт-процессов срабатывают для элементов любых смарт-процессов. Поэтому
в обработчике нужно проверять ENTITY_TYPE_ID и отбрасывать чужие типы.
| Событие | Когда вызывается | Что приходит |
|---|---|---|
onCrmDynamicItemAdd | После добавления элемента смарт-процесса. | ID и ENTITY_TYPE_ID. |
onCrmDynamicItemUpdate | После изменения элемента смарт-процесса. | ID и ENTITY_TYPE_ID. |
onCrmDynamicItemDelete | После удаления элемента смарт-процесса. | ID и ENTITY_TYPE_ID. |
onCrmDynamicItemAdd_1044 | Вариант подписки на конкретный тип. | Может работать при подписке через приложение, но в интерфейсе вебхуков обычно не отображается. |
Для коробочной PHP-логики эти события не самый удобный вариант. Они больше подходят для REST-приложений и внешних интеграций.
Действия операций в PHP
В новом CRM API логику смарт-процесса обычно добавляют не через старые события вида
OnBeforeCrmDealUpdate, а через операции и действия. Действие можно
подключить к операции добавления, изменения или удаления.
| Точка | Когда выполняется | Для чего подходит |
|---|---|---|
Operation::ACTION_BEFORE_SAVE | Перед сохранением элемента. | Проверка полей, запрет изменения, служебная валидация. |
Operation::ACTION_AFTER_SAVE | После сохранения элемента. | Логирование, синхронизация, вспомогательные действия. |
Такой подход обычно требует своего класса фабрики и подмены фабрики для конкретного
entityTypeId. Это уже не разовый PHP-скрипт, а код для
/local или локального модуля.
Действие перед сохранением
Пример действия, которое запрещает перевод элемента на определённую стадию для
конкретного пользователя. Такой класс можно положить, например, в свой модуль или в
/local/php_interface/classes.
<?php
namespace Local\Crm\SmartProcess\Operation\Action;
use Bitrix\Crm\Item;
use Bitrix\Crm\Service\Container;
use Bitrix\Crm\Service\Operation\Action;
use Bitrix\Main\Error;
use Bitrix\Main\Result;
class RestrictStageChangeAction extends Action
{
private const RESTRICTED_USER_ID = 222;
private const RESTRICTED_STAGE_ID = 'D1044_1:CLIENT';
/**
* Проверяет изменение стадии перед сохранением.
*/
public function process(Item $item): Result
{
$result = new Result();
$user_id = Container::getInstance()->getContext()->getUserId();
if (
$user_id === self::RESTRICTED_USER_ID
&& $item->isChangedStageId()
&& $item->getStageId() === self::RESTRICTED_STAGE_ID
) {
$result->addError(
new Error('Пользователю запрещено переводить элемент на эту стадию')
);
}
return $result;
}
} Чтобы действие выполнилось, его нужно добавить к операции обновления в своей фабрике.
<?php
namespace Local\Crm\SmartProcess;
use Bitrix\Crm;
use Bitrix\Crm\Service\Factory\Dynamic;
use Bitrix\Crm\Service\Operation;
use Local\Crm\SmartProcess\Operation\Action\RestrictStageChangeAction;
class Factory extends Dynamic
{
/**
* Добавляет проверку перед сохранением элемента.
*/
public function getUpdateOperation(
Crm\Item $item,
Crm\Service\Context $context = null
): Crm\Service\Operation\Update {
$operation = parent::getUpdateOperation($item, $context);
$operation->addAction(
Operation::ACTION_BEFORE_SAVE,
new RestrictStageChangeAction()
);
return $operation;
}
} Действие после удаления
Пример действия, которое пишет в лог ID удалённого элемента смарт-процесса. Подходит для служебного аудита или синхронизации со своей таблицей.
<?php
namespace Local\Crm\SmartProcess\Operation\Action;
use Bitrix\Crm\Item;
use Bitrix\Crm\Service\Operation\Action;
use Bitrix\Main\Result;
class LogDeleteAction extends Action
{
/**
* Записывает удаление элемента в лог.
*/
public function process(Item $item): Result
{
AddMessage2Log(
[
'message' => 'Элемент смарт-процесса удалён',
'item_id' => $item->getId(),
'entity_type_id' => $item->getEntityTypeId(),
],
'smart_process_delete'
);
return new Result();
}
} Действие добавляется к операции удаления.
<?php
namespace Local\Crm\SmartProcess;
use Bitrix\Crm;
use Bitrix\Crm\Service\Factory\Dynamic;
use Bitrix\Crm\Service\Operation;
use Local\Crm\SmartProcess\Operation\Action\LogDeleteAction;
class Factory extends Dynamic
{
/**
* Добавляет логирование после удаления элемента.
*/
public function getDeleteOperation(
Crm\Item $item,
Crm\Service\Context $context = null
): Crm\Service\Operation\Delete {
$operation = parent::getDeleteOperation($item, $context);
$operation->addAction(
Operation::ACTION_AFTER_SAVE,
new LogDeleteAction()
);
return $operation;
}
} Если нужна полная подмена фабрики для конкретного смарт-процесса, это лучше вынести в отдельную статью про кастомизацию фабрик и контейнера CRM.
Источники
- Официальная документация: CRM Service Container
- Официальная документация: CRM Service Factory
- Официальная документация: CRM Item
- Официальная документация: CRM Operations
- REST: события элементов смарт-процессов
- REST: onCrmDynamicItemAdd
- REST: onCrmDynamicItemUpdate
- REST: onCrmDynamicItemDelete
- REST: Smart Processes / Overview
- Bitrix24: Книга разработчика — Универсальное API CRM
- Bitrix24: Книга разработчика — изменение логики смарт-процессов
- Nikaverro: CRM Bitrix24 коробка API