47 public function __construct(array $documentType, $documentStatus =
null)
49 $this->
template = array(
51 'MODULE_ID' => $documentType[0],
52 'ENTITY' => $documentType[1],
53 'DOCUMENT_TYPE' => $documentType[2],
54 'DOCUMENT_STATUS' => $documentStatus,
55 'AUTO_EXECUTE' => $this->autoExecuteType,
64 $row = WorkflowTemplateTable::getList([
66 '=MODULE_ID' => $documentType[0],
67 '=ENTITY' => $documentType[1],
68 '=DOCUMENT_TYPE' => $documentType[2],
69 '=DOCUMENT_STATUS' => $documentStatus,
75 $this->
template = $row;
76 $this->autoExecuteType = (int) $this->
template[
'AUTO_EXECUTE'];
84 $instance->template = $tpl->collectValues();
85 $instance->autoExecuteType = (int) $instance->template[
'AUTO_EXECUTE'];
92 $isSameRobot =
function ($lhsRobot, $rhsRobot) {
93 return strcmp($lhsRobot->getName(), $rhsRobot->getName());
96 $remainingRobots = array_udiff($this->
getRobots(), $robots, $isSameRobot);
98 return $this->
save($remainingRobots, $userId);
103 return isset($this->
template[
'DOCUMENT_STATUS']) ? $this->
template[
'DOCUMENT_STATUS'] :
null;
108 $this->
template[
'DOCUMENT_STATUS'] = (string) $status;
114 $this->
template[
'NAME'] = $name;
135 return isset($this->
template[
'ID']) ? (int)$this->
template[
'ID'] : 0;
140 return $this->
template[
'PARAMETERS'] ?? [];
145 if (isset($robot[
'Properties']) && is_array($robot[
'Properties']))
147 $robot[
'Properties'] = Automation\Helper::convertProperties($robot[
'Properties'], $this->
getDocumentType());
150 unset($robot[
'Delay'], $robot[
'Condition']);
153 $copy->setRobots([$robot]);
155 return \CBPActivity::callStaticMethod(
157 "GetPropertiesDialog",
160 $robot[
'Name'] ??
null,
161 $copy->template[
'TEMPLATE'],
165 'bizproc_automation_robot_dialog',
174 $saveResult =
new Result();
177 if (isset($robot[
'Properties']) && is_array($robot[
'Properties']))
179 $robot[
'Properties'] = Automation\Helper::unConvertProperties($robot[
'Properties'], $documentType);
182 $request = Automation\Helper::unConvertProperties($request, $documentType);
185 $copy->setRobots([$robot]);
186 $raw = $copy->template[
'TEMPLATE'];
188 $robotErrors = $v = $p = array();
189 $result = \CBPActivity::callStaticMethod(
191 "GetPropertiesDialogValues",
194 $robot[
'Name'] ??
null,
203 if ($result || (isset($robot[
'Activated']) && $robot[
'Activated'] ===
'N'))
205 $templateActivity = \CBPWorkflowTemplateLoader::findActivityByName($raw, $robot[
'Name'] ??
null);
207 $robotTitle = $robot[
'Properties'][
'Title'] ??
null;
208 $robot[
'Properties'] = $templateActivity[
'Properties'];
209 $robot[
'Properties'][
'Title'] = $robotTitle;
211 $saveResult->setData([
'robot' => $robot]);
215 foreach ($robotErrors as $i => $error)
217 $errorMessage = $error[
'message'] ??
null;
218 $errorCode = $error[
'code'] ??
null;
219 $errorParameter = $error[
'parameter'] ??
null;
220 $saveResult->addError(
new Error($errorMessage, $errorCode, [
'parameter' => $errorParameter]));
227 public function save(array
$robots, $userId, array $additional = [])
229 $userId = (int)$userId;
231 $templateId = !empty($this->
template[
'ID']) ? $this->
template[
'ID'] : 0;
233 if (isset($additional[
'PARAMETERS']) && is_array($additional[
'PARAMETERS']))
235 $this->
template[
'PARAMETERS'] = $additional[
'PARAMETERS'];
237 if (isset($additional[
'CONSTANTS']) && is_array($additional[
'CONSTANTS']))
239 $this->
template[
'CONSTANTS'] = $additional[
'CONSTANTS'];
244 $templateResult = $this->updateTemplateRobots(
$robots, $userId);
252 if ($templateResult->isSuccess())
254 $resultData = $templateResult->getData();
255 if (isset($resultData[
'ID']))
257 $this->
template[
'ID'] = $resultData[
'ID'];
262 $result->addErrors($templateResult->getErrors());
270 $this->robots = array();
272 foreach ($robots as $robot)
274 if (is_array($robot))
275 $robot =
new Robot($robot);
277 if (!($robot instanceof
Robot))
282 $this->robots[] = $robot;
297 'ID' => $this->
getId(),
299 'DOCUMENT_STATUS' => $this->
template[
'DOCUMENT_STATUS'],
300 'PARAMETERS' => $this->
template[
'PARAMETERS'],
301 'CONSTANTS' => $this->
template[
'CONSTANTS'],
302 'VARIABLES' => $this->
template[
'VARIABLES'] ?? [],
306 $result[
'ROBOTS'] = array();
310 $result[
'ROBOTS'][] = $robot->toArray();
318 $key = implode(
'@', $documentType);
319 if (!isset(static::$availableActivities[$key]))
321 static::$availableActivities[$key] = \CBPRuntime::getRuntime()
322 ->searchActivitiesByType(
'robot_activity', $documentType);
324 return static::$availableActivities[$key];
329 $key = implode(
'@', $documentType);
330 if (!isset(static::$availableActivityClasses[$key]))
332 static::$availableActivityClasses[$key] = array();
333 $activities = static::getAvailableRobots($documentType);
334 foreach ($activities as $activity)
336 static::$availableActivityClasses[$key][] = $activity[
'CLASS'];
339 return static::$availableActivityClasses[$key];
344 $userId = (int)$userId;
348 $raw[
'DOCUMENT_TYPE'] = $documentType;
350 $raw[
'USER_ID'] = $userId;
351 $raw[
'MODIFIER_USER'] = new \CBPWorkflowTemplateUser($userId);
356 $raw[
'ID'] = \CBPWorkflowTemplateLoader::add($raw, $userId === 1);
357 $result->setData(array(
'ID' => $raw[
'ID']));
359 $raw[
'MODULE_ID'] = $documentType[0];
360 $raw[
'ENTITY'] = $documentType[1];
361 $raw[
'DOCUMENT_TYPE'] = $documentType[2];
362 $raw[
'PARAMETERS'] = [];
363 $raw[
'CONSTANTS'] = [];
364 $this->
template = $raw;
366 catch (\Exception $e)
368 $result->addError(
new Error($e->getMessage()));
377 '#STATUS#' => $this->
template[
'DOCUMENT_STATUS']
380 if ($this->autoExecuteType === \CBPDocumentEventType::Script)
388 private function updateTemplateRobots(array
$robots,
int $userId):
Result
390 $templateId = $this->
template[
'ID'];
393 $errors = $this->validateUpdatedRobots(
$robots,
new \CBPWorkflowTemplateUser($userId));
394 if (!$errors->isEmpty())
396 $result->addErrors($errors->getValues());
403 'TEMPLATE' => $this->
template[
'TEMPLATE'],
404 'PARAMETERS' => $this->
template[
'PARAMETERS'],
406 'CONSTANTS' => $this->
template[
'CONSTANTS'],
407 'USER_ID' => $userId,
408 'MODIFIER_USER' => new \CBPWorkflowTemplateUser($userId),
411 if (isset($this->
template[
'NAME']))
413 $updateFields[
'NAME'] = $this->
template[
'NAME'];
418 \CBPWorkflowTemplateLoader::update($templateId, $updateFields,
false,
false);
420 catch (\Exception $e)
422 $result->addError(
new Error($e->getMessage()));
428 private function validateUpdatedRobots(array
$robots, \CBPWorkflowTemplateUser $user): ErrorCollection
430 $errors =
new ErrorCollection();
431 $loader = \CBPWorkflowTemplateLoader::GetLoader();
434 $isSameRobot =
function ($lhsRobot, $rhsRobot) {
435 return $lhsRobot->getName() === $rhsRobot->getName();
441 if (is_array($robot))
443 $robot =
new Robot($robot);
445 if (!($robot instanceof Robot))
447 $errors->setError(
new Error(
'Robots array is incorrect'));
449 if (!$errors->isEmpty())
454 $indexOfFoundRobot = -1;
455 foreach ($originalRobots as $index => $originalRobot)
457 if ($isSameRobot($robot, $originalRobot))
459 $indexOfFoundRobot = $index;
464 if ($indexOfFoundRobot < 0 || !$this->areRobotsEqual($robot, $originalRobots[$indexOfFoundRobot]))
466 if ($robot->isActivated())
468 $sequence = $this->convertRobotToSequenceActivity($robot);
469 foreach ($loader->ValidateTemplate($sequence, $user) as $rawError)
471 $errors->setError(
new Error(trim($rawError[
'message'])));
474 unset($originalRobots[$indexOfFoundRobot]);
481 private function areRobotsEqual(Robot $lhsRobot, Robot $rhsRobot): bool
483 $lhsCondition = $lhsRobot->getCondition() ??
new ConditionGroup();
484 $rhsCondition = $rhsRobot->getCondition() ??
new ConditionGroup();
486 $lhsDelay = $lhsRobot->getDelayInterval();
487 $rhsDelay = $rhsRobot->getDelayInterval();
488 if (!isset($lhsDelay) || $lhsDelay->isNow())
490 $lhsDelay =
new DelayInterval();
492 if (!isset($rhsDelay) || $rhsDelay->isNow())
494 $rhsDelay =
new DelayInterval();
498 $lhsCondition->toArray()[
'items'] === $rhsCondition->toArray()[
'items']
499 && $lhsDelay->toArray() === $rhsDelay->toArray()
500 && $lhsRobot->getBizprocActivity() === $rhsRobot->getBizprocActivity()
510 'TEMPLATE' => $raw[
'TEMPLATE'],
511 'PARAMETERS' => $raw[
'PARAMETERS'],
513 'CONSTANTS' => $raw[
'CONSTANTS'],
514 'USER_ID' => $userId,
515 'MODIFIER_USER' => new \CBPWorkflowTemplateUser($userId),
518 if (isset($raw[
'NAME']))
520 $updateFields[
'NAME'] = $raw[
'NAME'];
525 \CBPWorkflowTemplateLoader::update($id, $updateFields);
527 catch (\Exception $e)
529 $result->addError(
new Error($e->getMessage()));
537 $this->robots = array();
540 if (!is_array($raw) || !isset($raw[
'TEMPLATE']))
551 if (empty($raw[
'TEMPLATE'][0][
'Children']) || !is_array($raw[
'TEMPLATE'][0][
'Children']))
554 if (count($raw[
'TEMPLATE'][0][
'Children']) > 1)
560 $parallelActivity = $raw[
'TEMPLATE'][0][
'Children'][0];
563 || $parallelActivity[
'Type'] !== static::$parallelActivityType
564 || (isset($parallelActivity[
'Activated']) && $parallelActivity[
'Activated'] ===
'N')
571 foreach ($parallelActivity[
'Children'] as $sequence)
573 $delay = $condition =
null;
575 foreach ($sequence[
'Children'] as $activity)
578 $activity[
'Type'] === static::$delayActivityType
579 || $activity[
'Type'] === static::$robotDelayActivityType)
585 if ($activity[
'Type'] === static::$conditionActivityType)
588 if ($condition ===
false)
591 $this->robots = array();
596 if (!$this->
isRobot($activity))
599 $this->robots = array();
603 $robotActivity =
new Robot($activity);
607 $delayInterval->setActivated(\CBPHelper::getBool($delay[
'Activated'] ??
true));
609 $robotActivity->setDelayInterval($delayInterval);
610 $robotActivity->setDelayName($delay[
'Name']);
612 if($delayInterval->isActivated() !== $robotActivity->isActivated())
623 if ($condition !==
null)
625 if ($condition->isActivated() !== $robotActivity->isActivated())
633 $robotActivity->setCondition($condition);
639 $robotActivity->setExecuteAfterPrevious();
643 $this->robots[] = $robotActivity;
647 $this->isConverted =
true;
655 'ID' => $this->
getId(),
656 'MODULE_ID' => $documentType[0],
657 'ENTITY' => $documentType[1],
658 'DOCUMENT_TYPE' => $documentType[2],
659 'DOCUMENT_STATUS' => $this->
template[
'DOCUMENT_STATUS'],
663 'Type' =>
'SequentialWorkflowActivity',
664 'Name' =>
'Template',
665 'Properties' => [
'Title' =>
'Bizproc Automation template'],
668 'PARAMETERS' => $this->
template[
'PARAMETERS'],
669 'CONSTANTS' => $this->
template[
'CONSTANTS'],
670 'SYSTEM_CODE' =>
'bitrix_bizproc_automation',
675 $parallelActivity = $this->createParallelActivity();
676 $sequence = $this->createSequenceActivity();
678 foreach ($this->robots as $i => $robot)
680 if ($i !== 0 && !$robot->isExecuteAfterPrevious())
682 $parallelActivity[
'Children'][] = $sequence;
683 $sequence = $this->convertRobotToSequenceActivity($robot);
687 $sequence[
'Children'] = array_merge(
688 $sequence[
'Children'],
689 $this->convertRobotToSequenceActivity($robot)[
'Children']
694 $parallelActivity[
'Children'][] = $sequence;
696 if (count($parallelActivity[
'Children']) < 2)
698 $parallelActivity[
'Children'][] = $this->createSequenceActivity();
701 $this->
template[
'TEMPLATE'][0][
'Children'][] = $parallelActivity;
703 $this->robots =
null;
704 $this->isConverted =
false;
707 private function convertRobotToSequenceActivity(
Robot $robot): array
709 $sequence = $this->createSequenceActivity();
712 if ($delayInterval && !$delayInterval->isNow())
721 $delayIntervalProperties = $delayInterval->toActivityProperties($this->
getDocumentType());
723 $sequence[
'Children'][] = $this->createDelayActivity(
724 $delayIntervalProperties,
733 if ($condition && $condition->getItems())
735 $activity = $condition->createBizprocActivity($activity, $this->
getDocumentType(), $this);
738 $sequence[
'Children'][] = $activity;
745 if (!in_array($activity[
'Type'], static::getAvailableRobotClasses($this->
getDocumentType())))
747 if ($this->isRestRobot($activity))
755 if (!empty($activity[
'Children']))
763 private function isRestRobot(array $activity): bool
765 if (!(mb_strpos($activity[
'Type'], \CBPRuntime::REST_ACTIVITY_PREFIX) === 0))
770 if (!empty($activity[
'Children']))
783 if ($this->robots ===
null)
793 if ($this->robots ===
null)
798 $activatedRobots = [];
799 foreach ($this->robots as $robot)
801 if ($robot->isActivated())
803 $activatedRobots[] = $robot;
807 return $activatedRobots;
819 if ($name === $robot->getName())
830 return array_uintersect($this->
getRobots(), $names,
function ($lhs, $rhs) {
831 $lhsName = is_string($lhs) ? $lhs : $lhs->getName();
832 $rhsName = is_string($rhs) ? $rhs : $rhs->getName();
834 return strcmp($lhsName, $rhsName);
843 return $this->
template[
'TEMPLATE'];
848 return $this->
template[
'MODIFIED'] ??
null;
865 return [$this->
template[
'MODULE_ID'], $this->
template[
'ENTITY'], $this->
template[
'DOCUMENT_TYPE']];
873 return $this->
template[
'PARAMETERS'][$field] ??
null;
875 return $this->
template[
'VARIABLES'][$field] ??
null;
877 return $this->
template[
'CONSTANTS'][$field] ??
null;
879 return Bizproc\Workflow\Type\GlobalConst::getVisibleById($field, $this->
getDocumentType());
881 return Bizproc\Workflow\Type\GlobalVar::getVisibleById($field, $this->
getDocumentType());
886 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
887 $fields = $documentService->GetDocumentFields($this->
getDocumentType());
890 return $fields[$field] ??
null;
892 if ($this->isConverted)
894 return $this->findRobotProperty($object, $field);
898 return $this->findActivityProperty($object, $field);
903 private function findRobotProperty($object, $field): ?array
909 private function findActivityProperty($object, $field): ?array
911 $activity = self::findTemplateActivity($this->
template[
'TEMPLATE'], $object);
917 $props = \CBPRuntime::GetRuntime(
true)->getActivityReturnProperties($activity[
'Type']);
918 return $props[$field] ??
null;
921 private static function findTemplateActivity(array
$template, $id)
925 if ($activity[
'Name'] === $id)
929 if (is_array($activity[
'Children']))
931 $found = self::findTemplateActivity($activity[
'Children'], $id);
941 private function createSequenceActivity()
944 'Type' => static::$sequenceActivityType,
947 'Title' =>
'Automation sequence',
954 private function createParallelActivity()
957 'Type' => static::$parallelActivityType,
967 private function createDelayActivity(array $delayProperties, $delayName, $delayActived)
969 if (!isset($delayProperties[
'Title']))
971 $delayProperties[
'Title'] =
Loc::getMessage(
'BIZPROC_AUTOMATION_ROBOT_DELAY_ACTIVITY');
975 'Type' => static::$robotDelayActivityType,
976 'Name' => $delayName,
977 'Activated' => $delayActived ?
'Y' :
'N',
978 'Properties' => $delayProperties,
static getMessage($code, $replace=null, $language=null)