Полный цикл в digital

Методы для работы с Компаниями в модуле CRM Битрикс24

Компания это комплексная структура состоящая из нескольких составных частей: основные данные, множественные поля, пользовательские поля, реквизиты, адреса.

Во многих подсистемах (генерация документов, счетов) подразумевается что взаимодействие осуществляется между двумя юртдическими лицами, клиентом и владельцем Битрикс24, поэтому для удобства хранения, разработчики решили использовать тот же механизм для хранения юридических лиц, что и для владельцев битрикса. Технически юридические лица хранятся в тех же таблицах, различие заключается в поле IS_MY_COMPANY которое имеет в значении Y, отображение этих компаний есть только на странице настроек CRM.

Получение списка полей

Получить большую часть полей, можно через php код:

\Bitrix\Main\Loader::IncludeModule('crm');

global $USER_FIELD_MANAGER;

if (\Bitrix\Main\Loader::IncludeModule('crm')) {
    $fieldsInfo = \CCrmCompany::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'] = \CCrmCompany::GetFieldCaption($code);
    }

    $userType = new \CCrmUserType(
        $USER_FIELD_MANAGER,
        \CCrmCompany::$sUFEntityID
    );
    $userType->PrepareFieldsInfo($fieldsInfo);

    var_dump($fieldsInfo);
}

Однако следует учитывать некоторые разночтения после начала ввода новой архитектуры D7, в систему были добавлены DataManager, которые в свою очередь имеют свой допустимый перечень полей. Можно посмотреть их в \Bitrix\Crm\CompanyTable::getMap().

Получение списка компаний

Существует несколько способов получить перечень лидов из системы:

Сравнение Старое API DataManager
Возможность получить данные из БД v v
Учет прав при получении v x
Простая фильтрация данных v v
Использование под запросов для сложной фильтрации x v

В случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого API дает возможность использовать проверку прав.

Используя старое API

Для получения контактов используя метод CCrmContact::GetListEx.

Сигнатура метода:

$entityResult = \CCrmCompany::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 = \CCrmCompany::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 = \CCrmCompany::GetListEx(
    ['ID' => 'DESC'],
    [],
    false,
    false,
    [
        'ID',
        'TITLE'
    ],
    [
        'QUERY_OPTIONS' => [
            'LIMIT' => 100,
            'OFFSET' => 200
        ]
    ]
);

Запросы с участием внешних таблиц в фильтре

Иногда бывает необходимость достать только те контакты, для которых есть запись в сторонней таблице. Для этого можно воспользоваться __JOINS ключом:

$entityAlias = 'CO';

$entityResult = \CCrmCompany::GetListEx(
    ['ID' => 'DESC'],
    [
        '__JOINS' => [
            [
                'TYPE' => 'INNER',
                'SQL' => 'INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = ' . $entityAlias . '.ID'
            ]
        ],
    ],
    false,
    false,
    [
        'ID',
        'TITLE'
    ]
);

Пример запроса:

SELECT
CO.ID as ID, CO.TITLE as TITLE
FROM b_crm_company CO
INNER JOIN SOME_TABLE ST ON ST.ENTITY_ID = CO.ID
ORDER BY CO.ID DESC

Но порой возникает необходимость не просто JOIN к таблице, а полноценные сложные запросы. Для реализации таких запросов в фильтрации существует ключ __CONDITIONS который добавляет любую строку к SQL запросу:

$entityResult = \CCrmCompany::GetListEx(
    ['ID' => 'DESC'],
    [
        '__CONDITIONS' => [
            [
                'SQL' => 'SOME_DUMP = 132'
            ]
        ],
    ],
    false,
    false,
    [
        'ID',
        'TITLE'
    ]
);
SELECT
CO.ID as ID, CO.TITLE as TITLE
FROM b_crm_company CO
WHERE SOME_DUMP = 132
ORDER BY CO.ID DESC

Помните что это опасные операции из-за непроверяемых параметров, они открыты для SQL Injection.

Используя DataManager

Для получения лидов через DataManager используется класс \Bitrix\Crm\CompanyTable который является представлением для таблицы b_crm_company. Для получения данных используется универсальный метод, который хорошо описан в документации.

Реализация DataManager архитектурно отличается от старого API, поэтому перечень полей для контакта старого и нового API может разниться. Актуальный список уже доступных полей можно найти получить из метода getMap(), а так же используя класс CCrmUserType.

Рассмотрим пример выше в реализации DataManager:

\Bitrix\Main\Loader::IncludeModule('crm');

$entityResult = \Bitrix\Crm\CompanyTable::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' => [
        'COMPANY_TYPE' => 'DESC'
    ]
]);

foreach ($entityResult as $entity)
{
    var_dump($entity);
    var_dump($entity['ID']);
}

Создание компании

Добавление компании производится нестатическим методом Add класса CCrmCompany.

Сигнатура метода:

public function Add(
    array &$arFields,
    $bUpdateSearch = true,
    $options = array()
)

$arFields — передающийся по ссылке массив полей добавляемого элемента. $bUpdateSearch — флаг необходимости перерасчета поискового индекса. $options — дополнительные опции при добавлении элемента.

Общий процесс добавления компании:

  1. Проверка прав на добавление
  2. Проверка обязательных полей
  3. Подготовка технических полей
  4. Вызов события OnBeforeCrmCompanyAdd.
  5. Запись в таблицу
  6. Расчет прав
  7. Сохранение связанных сущностей
  8. Создание сообщения в ленту (по-умолчанию — да)
  9. Вызов события OnAfterCrmCompanyAdd
  10. При наличии ORIGIN_ID вызов события OnAfterExternalCrmCompanyAdd

Технически, компания не является простой сущностью и состоит из нескольких структур:

  • Общие данные
  • Множественные поля
  • Привязки к компаниям/реквизитам/faceid/адресам
  • Пользовательских полей

Однако на практике, часть полей не имеет смысла разделять их между собой. Ниже представлен код иллюстрирующий добавление компании.

\Bitrix\Main\Loader::IncludeModule('crm');

/**
 * true, если нужно проверять права текущего пользователя.
 * Текущий пользователь определяется ID в ключе CURRENT_USER
 * $arOptions
 * @var boolean
 */
$bCheckRight = true;

/**
 * Добавляемая сущность
 * @var array
 */
$entityFields = [

    // Основные поля
    'TITLE' => 'ООО "Ромашка"',
    'COMPANY_TYPE' => 'CUSTOMER',

    "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",
            ],
        ],
    ],

    'CONTACT_ID' => [
        123, // Связан с контактом ID:123
    ],

    // Технические поля
    "OPENED" => "Y", // "Доступен для всех" = Да
    "ASSIGNED_BY_ID" => 123, // По-умолчанию ответственным будет пользователь с ID:123
];


$entityObject = new \CCrmCompany($bCheckRight);

$entityId = $entityObject->Add(
    $entityFields,
    $bUpdateSearch = true,
    $arOptions = [
        /**
         * ID пользователя, от лица которого выполняется действие
         * в том числе проверка прав
         * @var integer
         */
        'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),

        /**
         * Устанавливайте флаг, только если сущность проходит
         * процедуру восстановления. В случае если флаг есть
         * можно заполнять технические поля DATE_CREATE, DATE_MODIFY
         * @var boolean
         */
        // 'IS_RESTORATION' => true,
    ]
);

if (!$entityId) {
    /**
     * Произошла ошибка при добавлении сущности, посмотреть ее можно
     * через любой из способов ниже:
     * 1. $entityFields['RESULT_MESSAGE']
     * 2. $entityObject->LAST_ERROR
     */
}

Обновление компании

Обновление (изменение) компании производится нестатическим методом Update класса CCrmCompany.

Сигнатура метода:

public function Update(
    $ID,
    array &$arFields,
    $bCompare = true,
    $bUpdateSearch = true,
    $options = array()
)

$ID — идентификатор изменяемого элемента. $arFields — передающийся по ссылке массив полей изменяемого элемента. $bCompare — флаг необходимости проведения сравнения с предыдущими значениями для фиксации события изменений. bUpdateSearch — флаг необходимости расчета старого поиска. $options — дополнительные опции при обновлении элемента.

Общий процесс обновления:

  1. Получение текущих данных
  2. Проверка обязательных полей
  3. Проверка прав на изменение
  4. Вызов события OnBeforeCrmCompanyUpdate.
  5. Подготовка технических полей (доступен для всех, загрузка фотографии, реляций).
  6. Проведения сравнения с предыдущими значениями (при необходимости)
  7. Запись изменений в таблицу
  8. Расчет прав
  9. Запись в контроль дубликатов
  10. Изменение привязок контактов
  11. Сохранение адреса (если используется)
  12. Обновление пользовательских полей
  13. Запись в статистические таблицы и историю
  14. Сброс кеша
  15. Обновление поискового индекса
  16. Запись сообщения в ленту компании/чат
  17. Вызов события OnAfterCrmCompanyUpdate

Ниже представлен код иллюстрирующий изменение компании:

\Bitrix\Main\Loader::IncludeModule('crm');

/**
 * true, если нужно проверять права текущего пользователя.
 * Текущий пользователь определяется ID в ключе CURRENT_USER
 * $arOptions
 * @var boolean
 */
$bCheckRight = true;

/**
 * Идентификатор изменяемого элемента
 * @var integer
 */
$entityId = 123;

/**
 * Поля изменяемого элемента
 * @var array
 */
$entityFields = [
    // Основные поля
    'TITLE' => 'ООО "Лаванда"',
    "FM" => [
        "PHONE" => [
            // Телефон с ID 3567 будет изменен
            "3567" => [
                "VALUE" => '+78889996644',
                "VALUE_TYPE" => "WORK",
            ],
            // Телефон в ID 1234 будет удален
            "1234" => [
                "VALUE" => '',
                "VALUE_TYPE" => "HOME",
            ]
        ],
    ],

    "ASSIGNED_BY_ID" => 123,
];

$entityObject = new \CCrmCompany($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,

        /**
         * Отмечать кеш менеджера дубликатов для этого элемента.
         * @var boolean
         */
        `ENABLE_DUP_INDEX_INVALIDATION` => true,

        /**
         * В случае 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 (!$isUpdateSuccess) {
    /**
     * Произошла ошибка при обновлении элемента, посмотреть ее можно
     * через любой из способов ниже:
     * 1. $entityFields['RESULT_MESSAGE']
     * 2. $entityObject->LAST_ERROR
     */
}

Удаление компании

Удаление компании в системе осуществляется исключительно по ID.

Общий процесс удаления:

  1. Проверка существования элемента и прав на него
  2. Вызов события OnBeforeCrmCompanyDelete
  3. Удаление элемента
  4. Очистка связанных данных
  5. Вызов события OnAfterCrmCompanyDelete

За удаление отвечает нестатический метод Delete класса CCrmCompany, который имеет следующую сигнатуру:

public function Delete(
    $ID,
    $arOptions = array()
): bool

Полное описание метода удаления на примере элемента с идентификатором 123:

$eventManager = \Bitrix\Main\EventManager::getInstance();

/**
 * Идентификатор для удаления
 * @var integer
 */
$entityId = 123;

/**
 * true, если нужно проверять права текущего пользователя.
 * Текущий пользователь определяется ID в ключе CURRENT_USER
 * $arOptions
 * @var boolean
 */
$bCheckRight = true;

$entityObject = new \CCrmCompany($bCheckRight);

$deleteResult = $entityObject->Delete(
    $entityId,
    [
        /**
         * ID пользователя, от лица которого выполняется операция
         * Значение по-умолчанию: ID текущего пользователя
         * @var int
         */
        'CURRENT_USER' => \CCrmSecurityHelper::GetCurrentUserID(),

        /**
         * Удалить связанные бизнес-процессы
         * Значение по-умолчанию: true
         * @var boolean
         */
        'PROCESS_BIZPROC' => true,

        /**
         * Включить отложенное удаление
         * Значение по-умолчанию хранится в методе \Bitrix\Crm\Settings\CompanySettings::getCurrent()->isDeferredCleaningEnabled()
         * @var boolean
         */
        'ENABLE_DEFERRED_MODE' => \Bitrix\Crm\Settings\CompanySettings::getCurrent()->isDeferredCleaningEnabled(),

        /**
         * Пометить кеш дубликатов не актуальным
         * Значение по-умолчанию: true
         * @var boolean
         */
        'ENABLE_DUP_INDEX_INVALIDATION' => true,
    ]
);

if (!$deleteResult) {
    // Операция не удалась
    var_dump($entityObject->LAST_ERROR);
}

Это излишнее описание с указанием значений по-умолчанию. В большинстве случае достаточно будет использовать упрощенную форму:

\Bitrix\Main\Loader::IncludeModule('crm');

/**
 * Идентификатор для удаления
 * @var integer
 */
$entityId = 123;

/**
 * Идентификатор пользователя, чье имя нужно занести в историю
 * @var integer
 */
$logHistoryUserId = \CCrmSecurityHelper::GetCurrentUserID();

$entityObject = new \CCrmCompany(false);

$deleteResult = $entityObject->Delete(
    $entityId,
    [
        'CURRENT_USER' => $logHistoryUserId,
    ]
);

if (!$deleteResult) {
    // Операция не удалась
    var_dump($entityObject->LAST_ERROR);
}

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!