Как у меня возникла идея это реализовать?
После очередного обновления коробочного портала Битрикс 24 в марте 2023г, в бизнес процессах, перестала работать модификация типов при присвоении значения строковым переменным.
Например, при присвоении переменной "Variable1
" значения "{{Начальная сумма > double}}|{{Валюта > user}}
" в блоке "Изменение переменных" бизнес процесса, модификатор " > double
" преобразует нам типо поля "Деньги" (вида 100|RUB
) по правилам преобразования строки в "Число" — 100, а из поля "Валюта" модификатор " > user" всегда выдавал код валюты — "RUB". Таким образом это преобразование должно присвоить переменной "Variable1" значение вида "100|RUB". А после обновления выдаёт "100|RUB|Российсий рубль
".
Однако после злополучного обновления, и по сей день, кстати, эти модификаторы перестали работать, конкретно при присвоении значения переменной типа "Строка", во всех остальных случаях, включая блок действия "Уведомление" — работает!
Для того чтобы данное преобразование сработало в бизнес процессе после обновления, требуется «обернуть» модификаторы в другую функцию, так как ещё раз повторюсь, не работает модификация только со строковыми переменными.
Я для этого использовал функцию «trim()», в итоге получаем следующую запись:
{{trim({{Начальная сумма > double}}&"|"&{{Валюта > user}})}}
Такой метод реализации модификаторов работает как "до", так и "после" злополучного обновления.
Отсюда у меня и возникла потребность подменить данную запись у одного из клиентов более, чем в четырехстах бизнес процессах! При этом, многие бизнес-процессы, содержат сотни действий, в десятках веток условий. Вероятность пропустить подобную запись, при ручном изнуряющем редактировании, стремится к 100%!
Порядок реализации автозамены чего-либо в одном, либо во всех бизнес процессах
-
Получаем шаблон(ы) бизнес процесса в виде многомерного массива.
-
Используем функцию поиска по нужным критериям и модификации действия.
Реализуем п.1 (получаем шаблоны)
В документации Битрикс 24, ни как не описан функционал получения шаблонов бизнес‑процессов в виде массивов данных, есть только описание, что они именно таким образом хранятся. Поэтому помощь пришла из другой полезной статьи на ХАБРе про перенос бизнес-процессов.
Итак к коду.
Получения одного или нескольких шаблонов бизнес процессов:
$resFields = CBPWorkflowTemplateLoader::GetList(
[],
['ID' => 474], //для получения всех шаблонов, оставляем пустым
// ['USER_ID' => 34], //для получения всех шаблонов, одного создателя
false,
false,
['ID', 'NAME', 'TEMPLATE', 'VARIABLES']); //нам нужны только шаблоны,
//однако для фильтрации нужных значений понадобится типы переменных,
//а для отладки ID и имена БП
Дальше перебираем полученный результат:
while ($arFields = $resFields->GetNext()) {
if (!is_array($arFields)) {
echo "Из базы ничего не пришло!";
break;
}
//ниже 4 строчки которыми я убираю дополнительно пришедшие из БД дубликаты массивов
unset($arFields['~ID']);
unset($arFields['~NAME']);
unset($arFields['~TEMPLATE']);
unset($arFields['~VARIABLES']);
//помещаем в отдельные массивы шаблоны и переменные БП
$arTemplate = $arFields['TEMPLATE'];
$arVariables = $arFields['VARIABLES'];
/*дальше я прохожусь функией по всему массиву,
т.к. я не знаю какова страутура многомерного массива,
какие названеи переменных и сколько раз им назначаются значения в БП
callback функцию "changeNeedleStringInArray", приведу ниже */
array_walk($arTemplate, 'changeNeedleStringInArray');
$arNewFields['TEMPLATE'] = $arTemplate;
//без поля "MODIFIER_USER" - сохранение не срабатывает, выдаёт ошибку совершенно на этот факт не указывающую
$arNewFields["MODIFIER_USER"] = new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser);
CBPWorkflowTemplateLoader::update($arFields['ID'], $arNewFields);
//чистим память
unset($arFields);
unset($arNewFields);
unset($arTemplate);
unset($arVariables);
}
//выводим строки для проверки дебага результата
echo "<pre>";
if (!empty($convert)) {
print_r(count($convert));
print_r(PHP_EOL);
print_r($convert);
}
Реализуем п.2 (поиск и модификацию)
Выполняем преобразования в функции 'changeNeedleStringInArray', у меня будет ниже 3 примера:
1. Исправляем проблему описанную в начале статьи.{{Начальная сумма > double}}|{{Валюта > user}}
преобразуем в {{trim({{Начальная сумма > double}}&"|"&{{Валюта > user}})}}
/*
*/
function changeNeedleStringInArray(&$val, $key)
{
if (is_array($val)) {
array_walk($val, 'changeNeedleStringInArray'); //заходим этой же функцией во вложенный массив
} elseif (is_string($val)) {
if (stripos($val, '|{=Document:CURRENCY_ID > user') // ищем нужное значение в действии БП
&& !stripos($val, '{{=trim') //проверяем не сделано ли уже нужное нам преобразование
&& (isVarTypeString($key)) //проверяем тип переменной (нам надо менять только в строках)
) {
$val = convertActivityValue($val, $key);
}
}
}
function isVarTypeString($key)
{
global $arVariables;
if ($arVariables[$key]['Type'] == 'string')
return true;
return false;
}
function convertActivityValue($str, $key)
{
global $convert, $arFields;
if (!stripos($str, "|")) //проверяем что найденна требуемая нам строка
return $str;
$arHelp = explode("|", $str);
if (stripos($arHelp[0], "=")) {
$resStr = "{{=trim(" . $arHelp[0] . "&"|"&" . $arHelp[1] . ")}}";
} else {
$resStr = "{{=trim("" . $arHelp[0] . "|"&" . $arHelp[1] . ")}}";
}
$convert[$arFields['NAME']][$arFields['ID']][$key][] = $str;
$convert[$arFields['NAME']][$arFields['ID'] . "_new"][$key][] = $resStr;
return $resStr;
}
-
С каким-то из обновлений некоторые REST запросы стали чувствительны к регистру "ID" объектов в передаваемых параметрах, теперь работает только в нижнем регистре "id". Точно проверено с удалением комментариев в
timeline
:crm.timeline.comment.delete
Так как в некоторых БП я использовал вызовы REST посредствам curl, в качестве асинхронных вызовов, после обновлений пришлось вносить правки и тут. Исправляем'"ID"'
на'"id"
' вcurl
function changeNeedleStringInArray(&$val, $key)
{
if (is_array($val)) {
array_walk($val, 'changeNeedleStringInArray'); //заходим этой же функцией во вложенный массив
} elseif (is_string($val)) {
if (stripos($val, 'curl') // ищем нужное значение в действии БП
&& strpos($val, '"ID"') // ищем дополнительное нужное значение в действии БП
&& ($key == 'ExecuteCode') //проверяем тип переменной (нам надо менять только в PHP блоках)
) {
$val = convertActivityValue($val, $key);
}
}
}
function convertActivityValue($str, $key)
{
global $convert, $arFields;
$resStr = str_replace('"ID"', '"id"', $str);
$convert[$arFields['NAME']][$arFields['ID']][$key][] = $str;
$convert[$arFields['NAME']][$arFields['ID'] . "_new"][$key][] = $resStr;
return $resStr;
}
-
В "Уведомлениях" перестал работать BBCode с указанием цветов по их названию, типа
[color=red]Текст[/color]
- в сообщение выводится без форматирования
но[color=#ff0000]Текст[/color]
- вполне себе работает. Подменяем:
function convertActivityValue($str, $key)
{
global $convert, $arFields;
$resStr = str_replace('red', '#db0000', $str);
$convert[$arFields['NAME']][$arFields['ID']][$key][] = $str;
$convert[$arFields['NAME']][$arFields['ID'] . "_new"][$key][] = $resStr;
return $resStr;
}
function changeNeedleStringInArray(&$val, $key)
{
if (is_array($val)) {
array_walk($val, 'changeNeedleStringInArray'); //заходим этой же функцией во вложенный массив
} elseif (is_string($val)) {
if (stripos($val, '[color=red]') // ищем нужное значение в действии БП
&& ($key == 'MessageSite') //проверяем тип переменной (нам надо менять только в Уведомлениях)
) {
$val = convertActivityValue($val, $key);
}
}
}
Итоги
Таким образом мы имеем возможность вносить любые изменения в шаблоны бизнес‑процессов массово. Редактировать шаблоны не только из красивого вэб‑интрефейса, но в виде «хардкода». Так же на базе данного кода можно сделать отладку шаблонов бизнес‑процессов, или динамическое изменения в них.
Уверен, что с подобными изменениями в работы бизнес процессов, сталкиваются многие интеграторы Б24.
Поэтому, думаю, что существенно облегчил нам наш нелёгкий труд, данной статьёй.
Автор: sevnet