38 private static array $cache = [];
50 $this->
template = $this->getDefaultTemplate($documentType, $documentStatus);
54 $cacheKey = $this->getCacheKey($documentType, $documentStatus);
55 if (!isset(self::$cache[$cacheKey]))
57 self::$cache[$cacheKey] = $this->loadTemplate($documentType, $documentStatus);
60 if (self::$cache[$cacheKey])
62 $this->
template = self::$cache[$cacheKey];
63 $this->autoExecuteType = (int)$this->
template[
'AUTO_EXECUTE'];
68 private function getDefaultTemplate(
array $documentType, $documentStatus):
array
72 'MODULE_ID' => $documentType[0],
73 'ENTITY' => $documentType[1],
74 'DOCUMENT_TYPE' => $documentType[2],
75 'DOCUMENT_STATUS' => $documentStatus,
84 private function loadTemplate(
array $documentType, $documentStatus)
86 return WorkflowTemplateTable::getRow([
88 '=MODULE_ID' => $documentType[0],
89 '=ENTITY' => $documentType[1],
90 '=DOCUMENT_TYPE' => $documentType[2],
91 '=DOCUMENT_STATUS' => $documentStatus,
96 private function getCacheKey(
array $documentType, $documentStatus)
98 return \CBPHelper::stringify([...$documentType, $documentStatus]);
104 $instance->template = $tpl->collectValues();
112 $isSameRobot =
function ($lhsRobot, $rhsRobot) {
113 return strcmp($lhsRobot->getName(), $rhsRobot->getName());
116 $remainingRobots = array_udiff($this->
getRobots(), $robots, $isSameRobot);
123 return isset($this->
template[
'DOCUMENT_STATUS']) ? $this->
template[
'DOCUMENT_STATUS'] :
null;
128 $this->
template[
'DOCUMENT_STATUS'] = (string)
$status;
134 return $this->
template[
'TEMPLATE'] ??
null;
139 $this->
template[
'TEMPLATE'] = $template;
146 $this->
template[
'NAME'] = $name;
167 return isset($this->
template[
'ID']) ? (int)$this->
template[
'ID'] : 0;
172 return $this->
template[
'PARAMETERS'] ?? [];
177 if (isset($robot[
'Properties']) && is_array($robot[
'Properties']))
182 unset($robot[
'Delay'], $robot[
'Condition']);
185 $robots = $contextRobots ? [$robot, ...$contextRobots] : [$robot];
188 return \CBPActivity::callStaticMethod(
190 "GetPropertiesDialog",
193 $robot[
'Name'] ??
null,
194 $copy->template[
'TEMPLATE'],
195 $copy->getParameters(),
196 $copy->template[
'VARIABLES'] ?? [],
198 'bizproc_automation_robot_dialog',
201 $copy->template[
'CONSTANTS'] ?? [],
208 $saveResult =
new Result();
211 if (isset($robot[
'Properties']) && is_array($robot[
'Properties']))
219 $copy->setRobots([$robot]);
220 $raw = $copy->template[
'TEMPLATE'];
222 $robotErrors = $v =
$p =
array();
225 "GetPropertiesDialogValues",
228 $robot[
'Name'] ??
null,
237 if (
$result || (isset($robot[
'Activated']) && $robot[
'Activated'] ===
'N'))
239 $templateActivity = \CBPWorkflowTemplateLoader::findActivityByName($raw, $robot[
'Name'] ??
null);
241 $robotTitle = $robot[
'Properties'][
'Title'] ??
null;
242 $robot[
'Properties'] = $templateActivity[
'Properties'];
243 $robot[
'Properties'][
'Title'] = $robotTitle;
245 $saveResult->setData([
'robot' => $robot]);
249 foreach ($robotErrors as
$i =>
$error)
252 $errorCode =
$error[
'code'] ??
null;
253 $errorParameter =
$error[
'parameter'] ??
null;
254 $saveResult->addError(
new Error(
$errorMessage, $errorCode, [
'parameter' => $errorParameter]));
265 $templateId = !empty($this->
template[
'ID']) ? $this->
template[
'ID'] : 0;
267 if (isset($additional[
'PARAMETERS']) && is_array($additional[
'PARAMETERS']))
269 $this->
template[
'PARAMETERS'] = $additional[
'PARAMETERS'];
271 if (isset($additional[
'CONSTANTS']) && is_array($additional[
'CONSTANTS']))
273 $this->
template[
'CONSTANTS'] = $additional[
'CONSTANTS'];
286 if ($templateResult->isSuccess())
288 $resultData = $templateResult->getData();
289 if (isset($resultData[
'ID']))
291 $this->
template[
'ID'] = $resultData[
'ID'];
296 $result->addErrors($templateResult->getErrors());
304 $this->robots =
array();
308 if (is_array($robot))
309 $robot =
new Robot($robot);
311 if (!($robot instanceof
Robot))
316 $this->robots[] = $robot;
331 'ID' => $this->
getId(),
333 'DOCUMENT_STATUS' => $this->
template[
'DOCUMENT_STATUS'],
334 'PARAMETERS' => $this->
template[
'PARAMETERS'],
335 'CONSTANTS' => $this->
template[
'CONSTANTS'],
336 'VARIABLES' => $this->
template[
'VARIABLES'] ?? [],
344 $result[
'ROBOTS'][] = $robot->toArray();
352 $key = implode(
'@', $documentType);
353 if (!isset(static::$availableActivities[
$key]))
355 static::$availableActivities[
$key] = \CBPRuntime::getRuntime()
356 ->searchActivitiesByType(
'robot_activity', $documentType);
358 return static::$availableActivities[
$key];
363 $key = implode(
'@', $documentType);
364 if (!isset(static::$availableActivityClasses[
$key]))
366 static::$availableActivityClasses[
$key] =
array();
367 $activities = static::getAvailableRobots($documentType);
370 static::$availableActivityClasses[
$key][] =
$activity[
'CLASS'];
373 return static::$availableActivityClasses[
$key];
382 $raw[
'DOCUMENT_TYPE'] = $documentType;
385 $raw[
'MODIFIER_USER'] = new \CBPWorkflowTemplateUser(
$userId);
390 $raw[
'ID'] = \CBPWorkflowTemplateLoader::add($raw,
$userId === 1);
393 $raw[
'MODULE_ID'] = $documentType[0];
394 $raw[
'ENTITY'] = $documentType[1];
395 $raw[
'DOCUMENT_TYPE'] = $documentType[2];
396 $raw[
'PARAMETERS'] = [];
397 $raw[
'CONSTANTS'] = [];
398 $this->
template = $raw;
410 $msg = Loc::getMessage(
'BIZPROC_AUTOMATION_TEMPLATE_NAME', [
411 '#STATUS#' => $this->
template[
'DOCUMENT_STATUS']
416 $msg = Loc::getMessage(
'BIZPROC_AUTOMATION_TEMPLATE_SCRIPT_NAME');
437 'AUTO_EXECUTE' => $this->
template[
'AUTO_EXECUTE'],
439 'TEMPLATE' => $this->
template[
'TEMPLATE'],
440 'PARAMETERS' => $this->
template[
'PARAMETERS'],
442 'CONSTANTS' => $this->
template[
'CONSTANTS'],
443 'USER_ID' => $userId,
444 'MODIFIER_USER' => new \CBPWorkflowTemplateUser(
$userId),
447 if (isset($this->
template[
'NAME']))
449 $updateFields[
'NAME'] = $this->
template[
'NAME'];
453 isset($this->
template[
'MODULE_ID'])
454 && isset($this->
template[
'ENTITY'])
455 && isset($this->
template[
'DOCUMENT_TYPE'])
458 $updateFields[
'DOCUMENT_TYPE'] = [
459 $this->
template[
'MODULE_ID'],
460 $this->
template[
'ENTITY'],
461 $this->
template[
'DOCUMENT_TYPE']
467 \CBPWorkflowTemplateLoader::update(
$templateId, $updateFields,
false,
false);
469 catch (\Exception $e)
471 $result->addError(
new Error($e->getMessage()));
477 private function validateUpdatedRobots(
array $robots, \CBPWorkflowTemplateUser
$user): ErrorCollection
479 $errors =
new ErrorCollection();
480 $loader = \CBPWorkflowTemplateLoader::GetLoader();
483 $isSameRobot =
function ($lhsRobot, $rhsRobot) {
484 return $lhsRobot->getName() === $rhsRobot->getName();
490 if (is_array($robot))
492 $robot =
new Robot($robot);
494 if (!($robot instanceof Robot))
496 $errors->setError(
new Error(
'Robots array is incorrect'));
503 $indexOfFoundRobot = -1;
504 foreach ($originalRobots as $index => $originalRobot)
506 if ($isSameRobot($robot, $originalRobot))
508 $indexOfFoundRobot = $index;
513 if ($indexOfFoundRobot < 0 || !$this->areRobotsEqual($robot, $originalRobots[$indexOfFoundRobot]))
515 if ($robot->isActivated())
517 $sequence = $this->convertRobotToSequenceActivity($robot);
518 foreach ($loader->ValidateTemplate($sequence,
$user) as $rawError)
520 $errors->setError(
new Error(trim($rawError[
'message'])));
523 unset($originalRobots[$indexOfFoundRobot]);
530 private function areRobotsEqual(Robot $lhsRobot, Robot $rhsRobot): bool
532 $lhsCondition = $lhsRobot->getCondition() ??
new ConditionGroup();
533 $rhsCondition = $rhsRobot->getCondition() ??
new ConditionGroup();
535 $lhsDelay = $lhsRobot->getDelayInterval();
536 $rhsDelay = $rhsRobot->getDelayInterval();
537 if (!isset($lhsDelay) || $lhsDelay->isNow())
539 $lhsDelay =
new DelayInterval();
541 if (!isset($rhsDelay) || $rhsDelay->isNow())
543 $rhsDelay =
new DelayInterval();
547 $lhsCondition->toArray()[
'items'] === $rhsCondition->toArray()[
'items']
548 && $lhsDelay->toArray() === $rhsDelay->toArray()
549 && $lhsRobot->getBizprocActivity() === $rhsRobot->getBizprocActivity()
559 'TEMPLATE' => $raw[
'TEMPLATE'],
560 'PARAMETERS' => $raw[
'PARAMETERS'],
562 'CONSTANTS' => $raw[
'CONSTANTS'],
564 'MODIFIER_USER' => new \CBPWorkflowTemplateUser(
$userId),
567 if (isset($raw[
'NAME']))
569 $updateFields[
'NAME'] = $raw[
'NAME'];
574 \CBPWorkflowTemplateLoader::update($id, $updateFields);
586 $this->robots =
array();
589 if (!is_array($raw) || !isset($raw[
'TEMPLATE']))
600 if (empty($raw[
'TEMPLATE'][0][
'Children']) || !is_array($raw[
'TEMPLATE'][0][
'Children']))
603 if (
count($raw[
'TEMPLATE'][0][
'Children']) > 1)
609 $parallelActivity = $raw[
'TEMPLATE'][0][
'Children'][0];
612 || $parallelActivity[
'Type'] !== static::$parallelActivityType
613 || (isset($parallelActivity[
'Activated']) && $parallelActivity[
'Activated'] ===
'N')
620 foreach ($parallelActivity[
'Children'] as $sequence)
622 $delay = $condition =
null;
624 foreach ($sequence[
'Children'] as
$activity)
627 $activity[
'Type'] === static::$delayActivityType
628 ||
$activity[
'Type'] === static::$robotDelayActivityType)
634 if (
$activity[
'Type'] === static::$conditionActivityType)
637 if ($condition ===
false)
640 $this->robots =
array();
645 if (!$this->
isRobot($activity))
648 $this->robots =
array();
656 $delayInterval->setActivated(\CBPHelper::getBool($delay[
'Activated'] ??
true));
658 $robotActivity->setDelayInterval($delayInterval);
659 $robotActivity->setDelayName($delay[
'Name']);
661 if($delayInterval->isActivated() !== $robotActivity->isActivated())
672 if ($condition !==
null)
674 if ($condition->isActivated() !== $robotActivity->isActivated())
682 $robotActivity->setCondition($condition);
688 $robotActivity->setExecuteAfterPrevious();
692 $this->robots[] = $robotActivity;
696 $this->isConverted =
true;
704 'ID' => $this->
getId(),
705 'MODULE_ID' => $documentType[0],
706 'ENTITY' => $documentType[1],
707 'DOCUMENT_TYPE' => $documentType[2],
708 'DOCUMENT_STATUS' => $this->
template[
'DOCUMENT_STATUS'],
712 'Type' =>
'SequentialWorkflowActivity',
713 'Name' =>
'Template',
714 'Properties' => [
'Title' =>
'Bizproc Automation template'],
717 'PARAMETERS' => $this->
template[
'PARAMETERS'],
718 'CONSTANTS' => $this->
template[
'CONSTANTS'],
719 'SYSTEM_CODE' =>
'bitrix_bizproc_automation',
724 $parallelActivity = $this->createParallelActivity();
725 $sequence = $this->createSequenceActivity();
727 foreach ($this->robots as
$i => $robot)
729 if (
$i !== 0 && !$robot->isExecuteAfterPrevious())
731 $parallelActivity[
'Children'][] = $sequence;
732 $sequence = $this->convertRobotToSequenceActivity($robot);
736 $sequence[
'Children'] = array_merge(
737 $sequence[
'Children'],
738 $this->convertRobotToSequenceActivity($robot)[
'Children']
743 $parallelActivity[
'Children'][] = $sequence;
745 if (
count($parallelActivity[
'Children']) < 2)
747 $parallelActivity[
'Children'][] = $this->createSequenceActivity();
750 $this->
template[
'TEMPLATE'][0][
'Children'][] = $parallelActivity;
752 $this->robots =
null;
753 $this->isConverted =
false;
756 private function convertRobotToSequenceActivity(
Robot $robot):
array
758 $sequence = $this->createSequenceActivity();
761 if ($delayInterval && !$delayInterval->isNow())
770 $delayIntervalProperties = $delayInterval->toActivityProperties($this->
getDocumentType());
772 $sequence[
'Children'][] = $this->createDelayActivity(
773 $delayIntervalProperties,
782 if ($condition && $condition->getItems())
814 if (!(mb_strpos(
$activity[
'Type'], \CBPRuntime::REST_ACTIVITY_PREFIX) === 0))
832 if ($this->robots ===
null)
842 if ($this->robots ===
null)
847 $activatedRobots = [];
848 foreach ($this->robots as $robot)
850 if ($robot->isActivated())
852 $activatedRobots[] = $robot;
856 return $activatedRobots;
868 if (
$name === $robot->getName())
879 return array_uintersect($this->
getRobots(), $names,
function ($lhs, $rhs) {
880 $lhsName = is_string($lhs) ? $lhs : $lhs->getName();
881 $rhsName = is_string($rhs) ? $rhs : $rhs->getName();
883 return strcmp($lhsName, $rhsName);
892 return $this->
template[
'TEMPLATE'];
897 return $this->
template[
'MODIFIED'] ??
null;
914 return [$this->
template[
'MODULE_ID'], $this->
template[
'ENTITY'], $this->
template[
'DOCUMENT_TYPE']];
922 return $this->
template[
'PARAMETERS'][$field] ??
null;
924 return $this->
template[
'VARIABLES'][$field] ??
null;
926 return $this->
template[
'CONSTANTS'][$field] ??
null;
935 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
939 return $fields[$field] ??
null;
941 if ($this->isConverted)
943 return $this->findRobotProperty($object, $field);
947 return $this->findActivityProperty($object, $field);
952 private function findRobotProperty($object, $field): ?
array
958 private function findActivityProperty($object, $field): ?
array
960 $activity = self::findTemplateActivity($this->
template[
'TEMPLATE'], $object);
966 $props = \CBPRuntime::GetRuntime(
true)->getActivityReturnProperties(
$activity[
'Type']);
967 return $props[$field] ??
null;
970 private static function findTemplateActivity(
array $template, $id)
980 $found = self::findTemplateActivity(
$activity[
'Children'], $id);
990 private function createSequenceActivity()
993 'Type' => static::$sequenceActivityType,
996 'Title' =>
'Automation sequence',
1003 private function createParallelActivity()
1006 'Type' => static::$parallelActivityType,
1009 'Title' => Loc::getMessage(
'BIZPROC_AUTOMATION_PARALLEL_ACTIVITY'),
1016 private function createDelayActivity(
array $delayProperties, $delayName, $delayActived)
1018 if (!isset($delayProperties[
'Title']))
1020 $delayProperties[
'Title'] = Loc::getMessage(
'BIZPROC_AUTOMATION_ROBOT_DELAY_ACTIVITY');
1024 'Type' => static::$robotDelayActivityType,
1025 'Name' => $delayName,
1026 'Activated' => $delayActived ?
'Y' :
'N',
1027 'Properties' => $delayProperties,