Штатно из коробки Битрикс не умеет добавлять в историю изменения пользовательских полей в CRM элементах. Но мы это исправим.
Для начала следует заменить фабрику через ServiceLocator
. В моем примере я работаю со смарт-процессом с идентификатором 171. В вашем случае, это может быть deal, lead, contact и пр.
Loader::includeModule('crm');
$type = Service\Container::getInstance()->getTypeByEntityTypeId(171);
$factory = new class($type) extends Service\Factory\Dynamic {
// ... тут исправим новые методы
}
\Bitrix\Main\DI\ServiceLocator::getInstance()->addInstance('crm.service.factory.dynamic.171', $factory);
Для начала исправим метод получения полей для отслеживания изменений, добавив туда ключи пользовательских полей
// заменяем метод фабрики getTrackedFieldNames и подсовывем на выходе массив с uf полями
protected function getTrackedFieldNames(): array
{
$parent = parent::getTrackedFieldNames();
$map = $this->getUserFields();
return array_merge($parent, array_keys($map));
}
Ура! отслеживание включено и записывается в историю изменений.
Но, появилась проблема вывода имени поля вместо ключа.
На этот случай заменим метод getFieldCaption
// выводим правильные title через подмену getFieldCaption
public function getFieldCaption(string $commonFieldName): string
{
$fieldCaption = parent::getFieldCaption($commonFieldName);
if($fieldCaption == $commonFieldName) {
$map = $this->getUserFields();
if(key_exists($commonFieldName,$map)) {
return $map[$commonFieldName]['EDIT_FORM_LABEL'];
}
}
return $fieldCaption;
}
И в добавок исправим ошибки вывода array
в множественных полях и имени файла вместо идентификатора
// Исправляем ошибку с полями в типа "файл" и массивы подменой метода getFieldValueCaption
public function getFieldValueCaption($commonFieldName, $fieldValue): string
{
$field = $this->getFieldsCollection()->getField($commonFieldName);
if ($field->getType() === \Bitrix\Crm\Field::TYPE_FILE) {
if (is_array($fieldValue)) {
$arFileName = [];
foreach ($fieldValue as $fileId) {
$fileArray = \CFile::GetFileArray($fileId);
$arFileName[] = $fileArray['FILE_NAME'];
}
$fieldValue = implode(',',$arFileName);
} else {
$fieldValue = \CFile::GetFileArray($fieldValue)['FILE_NAME'];
}
return $fieldValue ? (string)$fieldValue : Loc::getMessage('CRM_COMMON_EMPTY');
} else {
return parent::getFieldValueCaption($commonFieldName, $fieldValue);
}
}
Итоговый результат. Можно добавить в init.php
Loader::includeModule('crm');
$type = Service\Container::getInstance()->getTypeByEntityTypeId(171);
$factory = new class($type) extends Service\Factory\Dynamic {
// заменим метод фабрики getTrackedFieldNames и подмешаем на выходе массив с uf полями
protected function getTrackedFieldNames(): array
{
$parent = parent::getTrackedFieldNames();
$map = $this->getUserFields();
return array_merge($parent, array_keys($map));
}
// выводим правильные title через подмену getFieldCaption
public function getFieldCaption(string $commonFieldName): string
{
$fieldCaption = parent::getFieldCaption($commonFieldName);
if($fieldCaption == $commonFieldName) {
$map = $this->getUserFields();
if(key_exists($commonFieldName,$map)) {
return $map[$commonFieldName]['EDIT_FORM_LABEL'];
}
}
return $fieldCaption;
}
// Исправляем ошибку с полями в типа "файл" и массивы подменой метода getFieldValueCaption
public function getFieldValueCaption($commonFieldName, $fieldValue): string
{
$field = $this->getFieldsCollection()->getField($commonFieldName);
if ($field->getType() === \Bitrix\Crm\Field::TYPE_FILE) {
if (is_array($fieldValue)) {
$arFileName = [];
foreach ($fieldValue as $fileId) {
$fileArray = \CFile::GetFileArray($fileId);
$arFileName[] = $fileArray['FILE_NAME'];
}
$fieldValue = implode(',',$arFileName);
} else {
$fieldValue = \CFile::GetFileArray($fieldValue)['FILE_NAME'];
}
return $fieldValue ? (string)$fieldValue : Loc::getMessage('CRM_COMMON_EMPTY');
} else {
return parent::getFieldValueCaption($commonFieldName, $fieldValue);
}
}
};
DI\ServiceLocator::getInstance()->addInstance('crm.service.factory.dynamic.171', $factory);