вторник, 26 августа 2014 г.

Битрикс КП. Запуск бизнес процессов для элементов универсального списка, добавленных через экспорт.

Проблема: при добавлении элементов универсального списка через систему экспорта csv не запускаются приписанные этому списку бизнес-процессы.
Техподы ответили, что проблему можно решить добавлением кода, который сразу после создания элементов определенных ИБ (массив должен быть редактируемым), будет проверять, если ли у текущего элемента запущенный экземпляр бизнес-процесса, если нет, то запускать бизнес-процесс. Вы можете использовать метод CBPDocument::StartWorkflow() в событии OnAfterIBlockElementAdd

Короче, проблему знаем, решите уж как-нибудь сами.

UPD: приведённое решение (и вы сами должны это понимать) не годится для закачек скажем более 50 элементов. продолжение следует...

План действий

  1. на событие OnAfterIBlockElementAdd вешаем функцию, которая проверяет наличие запущенных бизнес-процессов у элемента.
  2. если бизнес-процессов нет, то запускаем те бизнес процессы, которые должны быть запущены при создании элемента данного универсального списка.
"Слона надо кушать маленькими кусочками", как говорил мой первый преподаватель по PHP. Так что сначала учимся получать список БП, запущенных на элементе.
После некоторого гугления и штудирования доков получаем
$documentType = array("iblock", "CIBlockDocument", "iblock_".$iblock_id);
$documentId = array("iblock", "CIBlockDocument", $element_id);
$arDocumentStates = CBPDocument::GetDocumentStates($documentType, $documentId); 

Случайно в процессе гугления находим функцию CBPDocument::AutoStartWorkflows(), которая стартует все нужные БП для элемента. Так что нам теперь не надо получать список БП для применения, просто используем этот метод.

Итак, после проверки на экспорте мы действительно получаем запущенные БП. А теперь пробуем добавить элемент ручками и получаем дублирование запущенных БП.
Чешем ластой затылок. У меня на тот момент возникло только одно предположение: порядок создания элемента УС и запуска для него БП вот такой:
  1. создание элемента списка
  2. вызов события onafter
  3. возвращение айдишки элемента коду, который просил создать элемент 
  4. вызов БП для этого элемента
Соответственно проверка на  существование экземпляров запущенных БП в событии onafter бессмысленна.
После мозгового штурма приходит идея тупо отсрочить вызов функции CBPDocument::AutoStartWorkflows(), скажем, на пять секунд.

Костыли-велосипеды

Вздыхаю, пишу вызов агента. Чрез некоторое время понимаю, что внутри агента не существует $GLOBALS['USER'], которую использует метод автостарта БП. Бегаю, нервно пью кофе.
Дописываю авторизацию. Костылиииииии!
//по событию onafter вызывается функция, которая создаёт одноразового агента
AddEventHandler("iblock", "OnAfterIBlockElementAdd", "AutoBPStartAdd");

function AutoBPStartAdd(&$arFields)
{
 //формируем битриксовое датавремя первого запуска агента (и единственного ващета)
 $start_time = time() + 5;
 $start_time = ConvertTimeStamp($start_time, 'FULL');

 //мы должны создать агента, который будет запускать нам проверку и по
 // результатам проверки - запускать автостарт бизнес процессов
 $hello = CAgent::AddAgent(
  "AutoBPStart_Agent(".$arFields['ID'].", ".$arFields['IBLOCK_ID'].");",  //строка запуска агента
  "bizproc",
  "N",
  5,
  $start_time,
  'Y',
  $start_time
 );
}


function AutoBPStart_Agent($element_id, $iblock_id)
{
 //автостарт воркфлоу требует юзерса. а в мире агентов его просто так нетуть.
 if(empty($GLOBALS["USER"]))
 {
  $GLOBALS['USER'] = new CUser;
  $GLOBALS['USER']->Authorize(1);
  $removeUser = true;
 }
 else
 {
  $removeUser = false;
 }

 if(CModule::IncludeModule("bizproc"))
 {
  //заполняем массивы для получения статуса БП запрошенного элемента
  $documentType = array("iblock", "CIBlockDocument", "iblock_".$iblock_id);
  $documentId = array("iblock", "CIBlockDocument", $element_id);
  //получаем статусы БП
  $arDocumentStates = CBPDocument::GetDocumentStates($documentType, $documentId);

  //если запущен или выполнен хоть один БП, значит это не загрузка и автостарт не надо делать
  if (!count($arDocumentStates))
  {
   $arErrors = array();
   $arParameters = array();
  
   CBPDocument::AutoStartWorkflows(
    array("iblock", "CIBlockDocument", "iblock_".$iblock_id),
    CBPDocumentEventType::Create,
    array("iblock", "CIBlockDocument", $element_id),
    $arParameters,
    $arErrors
   );
  }
 }

 if($removeUser)
  unset($GLOBALS["USER"]);
}



На это всё был потрачен весь рабочий день, включая написание этой статьи и удаление кое-каких проверок из кода, которые вы напишете сами. ^-^

Комментариев нет:

Отправить комментарий