22 private static $allowedOperations = [
'',
'!',
'<',
'<=',
'>',
'>='];
40 private const ALLOWED_TASK_ACTIVITIES = [
43 'RequestInformationActivity',
44 'RequestInformationOptionalActivity'
51 if (self::isEnabled())
55 'bizproc.activity.add' => [__CLASS__,
'addActivity'],
56 'bizproc.activity.update' => [__CLASS__,
'updateActivity'],
57 'bizproc.activity.delete' => [__CLASS__,
'deleteActivity'],
58 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
59 'bizproc.activity.list' => [__CLASS__,
'getActivityList'],
62 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
65 'bizproc.task.list' => [__CLASS__,
'getTaskList'],
66 'bizproc.task.complete' => [__CLASS__,
'completeTask'],
69 'bizproc.workflow.terminate' => [__CLASS__,
'terminateWorkflow'],
70 'bizproc.workflow.kill' => [__CLASS__,
'killWorkflow'],
71 'bizproc.workflow.start' => [__CLASS__,
'startWorkflow'],
74 'bizproc.workflow.instance.list' => [__CLASS__,
'getWorkflowInstances'],
77 'bizproc.workflow.template.list' => [__CLASS__,
'getWorkflowTemplates'],
78 'bizproc.workflow.template.add' => [__CLASS__,
'addWorkflowTemplate'],
79 'bizproc.workflow.template.update' => [__CLASS__,
'updateWorkflowTemplate'],
80 'bizproc.workflow.template.delete' => [__CLASS__,
'deleteWorkflowTemplate'],
83 'bizproc.workflow.instances' => [__CLASS__,
'getWorkflowInstances'],
89 || self::isEnabled(
'crm_automation_lead')
90 || self::isEnabled(
'crm_automation_deal')
91 || self::isEnabled(
'crm_automation_order')
92 || self::isEnabled(
'tasks_automation')
95 $map = array_merge($map, array(
96 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
97 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
100 'bizproc.robot.add' => array(__CLASS__,
'addRobot'),
101 'bizproc.robot.update' => array(__CLASS__,
'updateRobot'),
102 'bizproc.robot.delete' => array(__CLASS__,
'deleteRobot'),
103 'bizproc.robot.list' => array(__CLASS__,
'getRobotList'),
106 'bizproc.provider.add' => [__CLASS__,
'addProvider'],
107 'bizproc.provider.delete' => [__CLASS__,
'deleteProvider'],
108 'bizproc.provider.list' => [__CLASS__,
'getProviderList'],
113 $map[\CRestUtil::PLACEMENTS] = [
114 static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG => [
'private' =>
true],
118 static::SCOPE => $map,
122 private static function isEnabled(
string $feature =
'bizproc'): bool
124 if (Loader::includeModule(
'bitrix24'))
126 return \Bitrix\Bitrix24\Feature::isFeatureEnabled($feature);
139 $fields = array_change_key_case($fields, CASE_UPPER);
140 if (empty($fields[
'APP_ID']))
143 if (!Loader::includeModule(
'rest'))
146 $dbRes = AppTable::getById($fields[
'APP_ID']);
147 $app = $dbRes->fetch();
152 $iterator = RestActivityTable::getList(array(
153 'select' => array(
'ID'),
154 'filter' => array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
157 while ($activity = $iterator->fetch())
159 RestActivityTable::delete($activity[
'ID']);
162 $iterator = RestProviderTable::getList(array(
163 'select' => array(
'ID'),
164 'filter' => array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
167 while ($activity = $iterator->fetch())
169 RestProviderTable::delete($activity[
'ID']);
172 self::deleteAppPlacement(
$app[
'ID']);
182 static::onRestAppDelete($fields);
194 return self::addActivityInternal($params, $server,
false);
204 public static function addRobot($params, $n, $server)
206 return self::addActivityInternal($params, $server,
true);
217 private static function addActivityInternal($params, $server, $isRobot =
false)
219 if(!$server->getClientId())
224 self::checkAdminPermissions();
225 $params = self::prepareActivityData($params);
228 self::validateRobot($params, $server);
230 self::validateActivity($params, $server);
232 $appId = self::getAppId($server->getClientId());
233 $params[
'APP_ID'] = $server->getClientId();
234 $params[
'INTERNAL_CODE'] = self::generateInternalCode($params);
235 $params[
'APP_NAME'] = self::getAppName($params[
'APP_ID']);
237 $iterator = RestActivityTable::getList(array(
238 'select' => array(
'ID'),
239 'filter' => array(
'=INTERNAL_CODE' => $params[
'INTERNAL_CODE'])
241 $result = $iterator->fetch();
244 throw new RestException(
'Activity or Robot already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
247 $params[
'AUTH_USER_ID'] = isset($params[
'AUTH_USER_ID'])? (int) $params[
'AUTH_USER_ID'] : 0;
248 $params[
'IS_ROBOT'] = $isRobot ?
'Y' :
'N';
249 $params[
'USE_PLACEMENT'] = (isset($params[
'USE_PLACEMENT']) && $params[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
251 if ($params[
'USE_PLACEMENT'] ===
'Y')
253 self::validateActivityHandler($params[
'PLACEMENT_HANDLER'] ??
null, $server);
254 self::upsertAppPlacement($appId, $params[
'CODE'], $params[
'PLACEMENT_HANDLER'] ??
null);
257 $result = RestActivityTable::add($params);
259 if ($result->getErrors())
261 if ($params[
'USE_PLACEMENT'] ===
'Y')
263 self::deleteAppPlacement($appId, $params[
'CODE']);
266 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
281 return self::updateActivityInternal($params, $server,
false);
293 return self::deleteActivityInternal($params, $server,
false);
305 return self::updateActivityInternal($params, $server,
true);
317 return self::deleteActivityInternal($params, $server,
true);
328 private static function deleteActivityInternal($params, $server, $isRobot =
false)
330 if(!$server->getClientId())
335 $params = array_change_key_case($params, CASE_UPPER);
336 self::checkAdminPermissions();
337 self::validateActivityCode($params[
'CODE']);
338 $params[
'APP_ID'] = $server->getClientId();
339 $internalCode = self::generateInternalCode($params);
341 $iterator = RestActivityTable::getList(array(
342 'select' => array(
'ID'),
344 '=INTERNAL_CODE' => $internalCode,
345 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
348 $result = $iterator->fetch();
351 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
353 RestActivityTable::delete($result[
'ID']);
354 self::deleteAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE']);
370 private static function updateActivityInternal($params, $server, $isRobot =
false)
372 if(!$server->getClientId())
374 throw new AccessException(
"Application context required");
377 $params = self::prepareActivityData($params);
378 self::checkAdminPermissions();
379 self::validateActivityCode($params[
'CODE']);
380 $params[
'APP_ID'] = $server->getClientId();
381 $internalCode = self::generateInternalCode($params);
383 $iterator = RestActivityTable::getList(array(
384 'select' => array(
'ID'),
386 '=INTERNAL_CODE' => $internalCode,
387 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
390 $result = $iterator->fetch();
393 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
396 $fields = (isset($params[
'FIELDS']) && is_array($params[
'FIELDS'])) ? $params[
'FIELDS'] : null;
400 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
405 if (isset($fields[
'HANDLER']))
407 self::validateActivityHandler($fields[
'HANDLER'], $server);
408 $toUpdate[
'HANDLER'] = $fields[
'HANDLER'];
411 if (isset($fields[
'AUTH_USER_ID']))
413 $toUpdate[
'AUTH_USER_ID'] = (int) $fields[
'AUTH_USER_ID'];
416 if (isset($fields[
'USE_SUBSCRIPTION']))
418 $toUpdate[
'USE_SUBSCRIPTION'] = (string) $fields[
'USE_SUBSCRIPTION'];
421 if (isset($fields[
'USE_PLACEMENT']))
423 $toUpdate[
'USE_PLACEMENT'] = ($fields[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
426 if (!empty($fields[
'NAME']))
428 $toUpdate[
'NAME'] = $fields[
'NAME'];
431 if (isset($fields[
'DESCRIPTION']))
433 $toUpdate[
'DESCRIPTION'] = $fields[
'DESCRIPTION'];
436 if (isset($fields[
'PROPERTIES']))
438 self::validateActivityProperties($fields[
'PROPERTIES']);
439 $toUpdate[
'PROPERTIES'] = $fields[
'PROPERTIES'];
442 if (isset($fields[
'RETURN_PROPERTIES']))
444 self::validateActivityProperties($fields[
'RETURN_PROPERTIES']);
445 $toUpdate[
'RETURN_PROPERTIES'] = $fields[
'RETURN_PROPERTIES'];
448 if (isset($fields[
'DOCUMENT_TYPE']))
450 if (empty($fields[
'DOCUMENT_TYPE']))
452 $toUpdate[
'DOCUMENT_TYPE'] =
null;
456 static::validateActivityDocumentType($fields[
'DOCUMENT_TYPE']);
457 $toUpdate[
'DOCUMENT_TYPE'] = $fields[
'DOCUMENT_TYPE'];
461 if (isset($fields[
'FILTER']))
463 if (empty($fields[
'FILTER']))
465 $toUpdate[
'FILTER'] =
null;
469 if (!is_array($fields[
'FILTER']))
471 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
473 $toUpdate[
'FILTER'] = $fields[
'FILTER'];
479 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
482 if (isset($fields[
'PLACEMENT_HANDLER']))
484 self::validateActivityHandler($fields[
'PLACEMENT_HANDLER'], $server);
485 self::upsertAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE'], $fields[
'PLACEMENT_HANDLER']);
488 if (isset($toUpdate[
'USE_PLACEMENT']) && $toUpdate[
'USE_PLACEMENT'] ===
'N')
490 self::deleteAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE']);
493 $updateResult = RestActivityTable::update($result[
'ID'], $toUpdate);
495 if (!$updateResult->isSuccess())
497 throw new RestException(
498 implode(
'; ', $updateResult->getErrorMessages()),
499 self::ERROR_ACTIVITY_VALIDATION_FAILURE
516 $params = array_change_key_case($params, CASE_UPPER);
517 [$workflowId, $activityName, $eventId] = self::extractEventToken($params[
'EVENT_TOKEN']);
520 \CBPDocument::sendExternalEvent(
524 'EVENT_ID' => $eventId,
525 'RETURN_VALUES' => $params[
'RETURN_VALUES'] ?? [],
526 'LOG_MESSAGE' => $params[
'LOG_MESSAGE'] ??
'',
533 $error = current($errors);
550 $params = array_change_key_case($params, CASE_UPPER);
551 [$workflowId, $activityName, $eventId] = self::extractEventToken($params[
'EVENT_TOKEN']);
553 $logMessage = isset($params[
'LOG_MESSAGE']) ? $params[
'LOG_MESSAGE'] :
'';
555 if (empty($logMessage))
556 throw new RestException(
'Empty log message!', self::ERROR_EMPTY_LOG_MESSAGE);
559 \CBPDocument::sendExternalEvent(
563 'EVENT_ID' => $eventId,
564 'LOG_ACTION' =>
true,
565 'LOG_MESSAGE' => $logMessage
572 $error = current($errors);
589 return self::getActivityListInternal($params, $server,
false);
602 return self::getActivityListInternal($params, $server,
true);
612 private static function getActivityListInternal($params, $server, $isRobot =
false)
614 if(!$server->getClientId())
619 self::checkAdminPermissions();
620 $iterator = RestActivityTable::getList(array(
621 'select' => array(
'CODE'),
623 '=APP_ID' => $server->getClientId(),
624 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
629 while ($row = $iterator->fetch())
631 $result[] = $row[
'CODE'];
647 self::checkAdminPermissions();
648 $params = array_change_key_case($params, CASE_UPPER);
652 'MODIFIED' =>
'MODIFIED',
653 'OWNED_UNTIL' =>
'OWNED_UNTIL',
654 'MODULE_ID' =>
'MODULE_ID',
655 'ENTITY' =>
'ENTITY',
656 'DOCUMENT_ID' =>
'DOCUMENT_ID',
657 'STARTED' =>
'STARTED',
658 'STARTED_BY' =>
'STARTED_BY',
659 'TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
662 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID',
'MODIFIED',
'OWNED_UNTIL'));
663 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED',
'OWNED_UNTIL'));
664 $order = static::getOrder($params[
'ORDER'], $fields, array(
'MODIFIED' =>
'DESC'));
666 $iterator = WorkflowInstanceTable::getList(array(
670 'limit' => static::LIST_LIMIT,
671 'offset' => (
int) $n,
672 'count_total' =>
true,
676 while ($row = $iterator->fetch())
678 if (isset($row[
'MODIFIED']))
679 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
680 if (isset($row[
'STARTED']))
681 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
682 if (isset($row[
'OWNED_UNTIL']))
683 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
687 return static::setNavData($result, [
'count' => $iterator->getCount(),
'offset' => $n]);
700 self::checkAdminPermissions();
701 $params = array_change_key_case($params, CASE_UPPER);
703 if (empty($params[
'ID']))
705 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
709 $status = isset($params[
'STATUS']) ? (string)$params[
'STATUS'] :
'';
712 if (!\CBPDocument::terminateWorkflow($id, [], $errors, $status))
730 self::checkAdminPermissions();
731 $params = array_change_key_case($params, CASE_UPPER);
733 if (empty($params[
'ID']))
735 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
739 $errors = \CBPDocument::killWorkflow($id);
759 $params = array_change_key_case($params, CASE_UPPER);
761 if (empty($params[
'TEMPLATE_ID']))
763 throw new RestException(
'Empty TEMPLATE_ID', self::ERROR_WRONG_WORKFLOW_ID);
765 $templateId = (int)$params[
'TEMPLATE_ID'];
766 $tplDocumentType = self::getTemplateDocumentType($templateId);
768 if (!$tplDocumentType)
770 throw new RestException(
'Template not found', self::ERROR_WRONG_WORKFLOW_ID);
774 $getParams = array_change_key_case($_GET, CASE_UPPER);
775 if (isset($getParams[
'DOCUMENT_ID']) && is_array($getParams[
'DOCUMENT_ID']))
777 $params[
'DOCUMENT_ID'] = $getParams[
'DOCUMENT_ID'];
780 $documentId = self::getDocumentId($params[
'DOCUMENT_ID']);
787 $documentType = self::getDocumentType($documentId);
794 if (!\CBPHelper::isEqualDocument($tplDocumentType, $documentType))
796 throw new RestException(
'Template type and DOCUMENT_ID mismatch!');
799 self::checkStartWorkflowPermissions($documentId, $templateId);
801 $workflowParameters = isset($params[
'PARAMETERS']) && is_array($params[
'PARAMETERS']) ? $params[
'PARAMETERS'] : [];
803 $workflowParameters[\CBPDocument::PARAM_TAGRET_USER] = self::getCurrentUserId();
806 $workflowId = \CBPDocument::startWorkflow($templateId, $documentId, $workflowParameters, $errors);
816 private static function checkStartWorkflowPermissions(array $documentId, $templateId)
818 if (static::isAdmin())
824 \CBPDocument::CanUserOperateDocument(
825 \CBPCanUserOperateOperation::StartWorkflow,
826 static::getCurrentUserId(),
828 [
'WorkflowTemplateId' => $templateId]
835 throw new AccessException();
850 self::checkAdminPermissions();
851 $params = array_change_key_case($params, CASE_UPPER);
855 'MODULE_ID' =>
'MODULE_ID',
856 'ENTITY' =>
'ENTITY',
857 'DOCUMENT_TYPE' =>
'DOCUMENT_TYPE',
858 'AUTO_EXECUTE' =>
'AUTO_EXECUTE',
860 'DESCRIPTION' =>
'DESCRIPTION',
861 'TEMPLATE' =>
'TEMPLATE',
862 'PARAMETERS' =>
'PARAMETERS',
863 'VARIABLES' =>
'VARIABLES',
864 'CONSTANTS' =>
'CONSTANTS',
865 'MODIFIED' =>
'MODIFIED',
866 'IS_MODIFIED' =>
'IS_MODIFIED',
867 'USER_ID' =>
'USER_ID',
868 'SYSTEM_CODE' =>
'SYSTEM_CODE',
871 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID'));
872 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED'));
873 $filter[
'<AUTO_EXECUTE'] = \CBPDocumentEventType::Automation;
875 $order = static::getOrder($params[
'ORDER'], $fields, array(
'ID' =>
'ASC'));
877 $iterator = WorkflowTemplateTable::getList(array(
881 'limit' => static::LIST_LIMIT,
882 'offset' => (
int) $n,
883 'count_total' =>
true,
886 $countTotal = $iterator->getCount();
888 $iterator = new \CBPWorkflowTemplateResult($iterator, \CBPWorkflowTemplateLoader::useGZipCompression());
891 while ($row = $iterator->fetch())
893 if (isset($row[
'MODIFIED']))
894 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
895 if (isset($row[
'STARTED']))
896 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
897 if (isset($row[
'OWNED_UNTIL']))
898 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
902 return static::setNavData($result, [
'count' => $countTotal,
'offset' => $n]);
914 if(!$server->getClientId())
919 self::checkAdminPermissions();
920 $params = array_change_key_case($params, CASE_UPPER);
922 self::validateTemplateDocumentType($params[
'DOCUMENT_TYPE']);
923 self::validateTemplateName($params[
'NAME']);
925 $autoExecute = \CBPDocumentEventType::None;
926 if (isset($params[
'AUTO_EXECUTE']))
928 self::validateTemplateAutoExecution($params[
'AUTO_EXECUTE']);
929 $autoExecute = (int) $params[
'AUTO_EXECUTE'];
932 $data = self::prepareTemplateData($params[
'TEMPLATE_DATA']);
934 return \CBPWorkflowTemplateLoader::ImportTemplate(
936 $params[
'DOCUMENT_TYPE'],
939 isset($params[
'DESCRIPTION']) ? (
string) $params[
'DESCRIPTION'] :
'',
941 self::generateTemplateSystemCode($server)
954 if(!$server->getClientId())
959 self::checkAdminPermissions();
960 $params = array_change_key_case($params, CASE_UPPER);
962 $fields = (isset($params[
'FIELDS']) && is_array($params[
'FIELDS'])) ? $params[
'FIELDS'] :
null;
969 $tpl = WorkflowTemplateTable::getList(array(
970 'select' => [
'ID',
'SYSTEM_CODE',
'NAME',
'DESCRIPTION',
'AUTO_EXECUTE',
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
971 'filter' => [
'=ID' => (
int) $params[
'ID']],
979 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
981 throw new RestException(
"You can update ONLY templates created by current application");
984 if (isset($fields[
'NAME']))
986 self::validateTemplateName($fields[
'NAME']);
987 $tpl[
'NAME'] = $fields[
'NAME'];
990 if (isset($fields[
'DESCRIPTION']))
992 $tpl[
'DESCRIPTION'] = (string) $fields[
'DESCRIPTION'];
995 if (isset($fields[
'AUTO_EXECUTE']))
997 self::validateTemplateAutoExecution($fields[
'AUTO_EXECUTE']);
998 $tpl[
'AUTO_EXECUTE'] = (int) $fields[
'AUTO_EXECUTE'];
1001 if (isset($fields[
'TEMPLATE_DATA']))
1003 $data = self::prepareTemplateData($fields[
'TEMPLATE_DATA']);
1005 return \CBPWorkflowTemplateLoader::ImportTemplate(
1007 [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']],
1008 $tpl[
'AUTO_EXECUTE'],
1010 $tpl[
'DESCRIPTION'],
1017 return \CBPWorkflowTemplateLoader::Update($tpl[
'ID'], [
1018 'NAME' => $tpl[
'NAME'],
1019 'DESCRIPTION' => $tpl[
'DESCRIPTION'],
1020 'AUTO_EXECUTE' => $tpl[
'AUTO_EXECUTE'],
1034 if(!$server->getClientId())
1039 self::checkAdminPermissions();
1040 $params = array_change_key_case($params, CASE_UPPER);
1042 $tpl = WorkflowTemplateTable::getList(array(
1043 'select' => [
'ID',
'SYSTEM_CODE'],
1044 'filter' => [
'=ID' => (
int) $params[
'ID']],
1052 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
1054 throw new RestException(
"You can delete ONLY templates created by current application");
1057 \CBPWorkflowTemplateLoader::Delete($tpl[
'ID']);
1069 $params = array_change_key_case($params, CASE_UPPER);
1073 'ACTIVITY' =>
'ACTIVITY',
1074 'ACTIVITY_NAME' =>
'ACTIVITY_NAME',
1075 'WORKFLOW_ID' =>
'WORKFLOW_ID',
1076 'DOCUMENT_NAME' =>
'DOCUMENT_NAME',
1077 'DESCRIPTION' =>
'DESCRIPTION',
1079 'MODIFIED' =>
'MODIFIED',
1080 'WORKFLOW_STARTED' =>
'WORKFLOW_STARTED',
1081 'WORKFLOW_STARTED_BY' =>
'WORKFLOW_STARTED_BY',
1082 'OVERDUE_DATE' =>
'OVERDUE_DATE',
1083 'WORKFLOW_TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
1084 'WORKFLOW_TEMPLATE_NAME' =>
'WORKFLOW_TEMPLATE_NAME',
1085 'WORKFLOW_STATE' =>
'WORKFLOW_STATE',
1086 'STATUS' =>
'STATUS',
1087 'USER_ID' =>
'USER_ID',
1088 'USER_STATUS' =>
'USER_STATUS',
1089 'MODULE_ID' =>
'MODULE_ID',
1090 'ENTITY' =>
'ENTITY',
1091 'DOCUMENT_ID' =>
'DOCUMENT_ID',
1092 'PARAMETERS' =>
'PARAMETERS',
1095 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID',
'WORKFLOW_ID',
'DOCUMENT_NAME',
'NAME'));
1096 $select = array_merge(array(
'MODULE',
'ENTITY',
'DOCUMENT_ID'), $select);
1097 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED',
'WORKFLOW_STARTED',
'OVERDUE_DATE'));
1098 $order = static::getOrder($params[
'ORDER'], $fields, array(
'ID' =>
'DESC'));
1100 $currentUserId = self::getCurrentUserId();
1101 $isAdmin = static::isAdmin();
1103 if (!$isAdmin && !isset($filter[
'USER_ID']))
1105 $filter[
'USER_ID'] = $currentUserId;
1108 $targetUserId = isset($filter[
'USER_ID'])? (int)$filter[
'USER_ID'] : 0;
1109 if ($targetUserId !== $currentUserId && !\CBPHelper::checkUserSubordination($currentUserId, $targetUserId))
1111 self::checkAdminPermissions();
1114 $iterator = \CBPTaskService::getList(
1118 static::getNavData($n),
1123 while ($row = $iterator->fetch())
1125 if (isset($row[
'MODIFIED']))
1126 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
1127 if (isset($row[
'WORKFLOW_STARTED']))
1128 $row[
'WORKFLOW_STARTED'] = \CRestUtil::convertDateTime($row[
'WORKFLOW_STARTED']);
1129 if (isset($row[
'OVERDUE_DATE']))
1130 $row[
'OVERDUE_DATE'] = \CRestUtil::convertDateTime($row[
'OVERDUE_DATE']);
1131 $row[
'DOCUMENT_URL'] = \CBPDocument::getDocumentAdminPage(array(
1132 $row[
'MODULE_ID'], $row[
'ENTITY'], $row[
'DOCUMENT_ID']
1135 if (isset($row[
'PARAMETERS']))
1137 $row[
'PARAMETERS'] = static::prepareTaskParameters($row[
'PARAMETERS'], $row);
1143 return static::setNavData($result, $iterator);
1146 private static function prepareTaskParameters(array $parameters, array $task)
1149 [
'CommentLabelMessage',
'CommentLabel'],
1150 'CommentRequired',
'ShowComment',
1151 [
'TaskButtonMessage',
'StatusOkLabel'],
1152 [
'TaskButton1Message',
'StatusYesLabel'],
1153 [
'TaskButton2Message',
'StatusNoLabel'],
1154 [
'TaskButtonCancelMessage',
'StatusCancelLabel'],
1155 [
'REQUEST',
'Fields'],
1160 foreach ($whiteList as $whiteKey)
1162 $filterKey = $whiteKey;
1163 if (is_array($whiteKey))
1165 $filterKey = $whiteKey[1];
1166 $whiteKey = $whiteKey[0];
1168 if (isset($parameters[$whiteKey]))
1170 $filtered[$filterKey] = $parameters[$whiteKey];
1174 if (isset($filtered[
'Fields']))
1176 $filtered[
'Fields'] = self::externalizeRequestFields($task, $filtered[
'Fields']);
1182 private static function externalizeRequestFields($task, array $fields): array
1184 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1186 foreach ($fields as $requestField)
1188 $id = $requestField[
'Name'];
1189 $requestField[
'Name'] = $requestField[
'Title'];
1191 $property[
'Id'] = $id;
1193 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1194 if ($fieldTypeObject)
1196 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1197 $property[
'Default'] = $fieldTypeObject->externalizeValue(
1199 $property[
'Default']
1203 $result[] = $property;
1208 private static function internalizeRequestFields($task, array $values): array
1210 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1213 foreach ($task[
'PARAMETERS'][
'REQUEST'] as $property)
1215 if (!isset($values[$property[
'Name']]))
1221 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1222 if ($fieldTypeObject)
1224 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1240 $params = array_change_key_case($params, CASE_UPPER);
1241 self::validateTaskParameters($params);
1243 $userId = self::getCurrentUserId();
1244 $task = static::getTask($params[
'TASK_ID'], $userId);
1246 if (!in_array($task[
'ACTIVITY'], self::ALLOWED_TASK_ACTIVITIES))
1248 throw new RestException(
'Incorrect task type', self::ERROR_TASK_TYPE);
1251 if (!empty($params[
'FIELDS']))
1253 $params[
'FIELDS'] = self::internalizeRequestFields($task, $params[
'FIELDS']);
1258 'INLINE_USER_STATUS' => \CBPTaskUserStatus::resolveStatus($params[
'STATUS']),
1259 'task_comment' => !empty($params[
'COMMENT']) && is_string($params[
'COMMENT']) ? $params[
'COMMENT'] :
null,
1260 'fields' => $params[
'FIELDS'] ??
null,
1263 if (!\CBPDocument::postTaskForm($task, $userId, $request, $errors))
1265 throw new RestException($errors[0][
"message"], self::ERROR_TASK_EXECUTION);
1271 private static function validateTaskParameters(array $params)
1273 if (empty($params[
'TASK_ID']))
1275 throw new RestException(
'empty TASK_ID', self::ERROR_TASK_VALIDATION);
1277 if (empty($params[
'STATUS']) || \CBPTaskUserStatus::resolveStatus($params[
'STATUS']) ===
null)
1279 throw new RestException(
'incorrect STATUS', self::ERROR_TASK_VALIDATION);
1283 private static function getTask($id, $userId)
1285 $dbTask = \CBPTaskService::getList(
1287 array(
"ID" => (
int)$id,
"USER_ID" => $userId),
1290 array(
"ID",
"WORKFLOW_ID",
"ACTIVITY",
"ACTIVITY_NAME",
"MODIFIED",
"OVERDUE_DATE",
"NAME",
"DESCRIPTION",
"PARAMETERS",
"USER_STATUS")
1292 $task = $dbTask->fetch();
1296 throw new RestException(
'Task not found', self::ERROR_TASK_NOT_FOUND);
1298 elseif ((
int)$task[
'USER_STATUS'] !== \CBPTaskUserStatus::Waiting)
1300 throw new RestException(
'Task already completed', self::ERROR_TASK_COMPLETED);
1305 $task[
"PARAMETERS"][
"DOCUMENT_ID"] = \CBPStateService::getStateDocumentId($task[
'WORKFLOW_ID']);
1306 $task[
"MODULE_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][0];
1307 $task[
"ENTITY"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][1];
1308 $task[
"DOCUMENT_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][2];
1323 if (Loader::includeModule(
'messageservice'))
1325 return \Bitrix\MessageService\RestService::addSender($params, $n, $server);
1328 if(!$server->getClientId())
1333 self::checkAdminPermissions();
1334 $params = self::prepareActivityData($params);
1336 self::validateProvider($params, $server);
1338 $params[
'APP_ID'] = $server->getClientId();
1339 $params[
'APP_NAME'] = self::getAppName($params[
'APP_ID']);
1341 $iterator = RestProviderTable::getList(array(
1342 'select' => array(
'ID'),
1344 '=APP_ID' => $params[
'APP_ID'],
1345 '=CODE' => $params[
'CODE']
1348 $result = $iterator->fetch();
1351 throw new RestException(
'Provider already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
1354 $result = RestProviderTable::add($params);
1356 if ($result->getErrors())
1357 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
1371 if (Loader::includeModule(
'messageservice'))
1373 return \Bitrix\MessageService\RestService::deleteSender($params, $n, $server);
1376 if(!$server->getClientId())
1381 $params = array_change_key_case($params, CASE_UPPER);
1382 self::checkAdminPermissions();
1383 self::validateActivityCode($params[
'CODE']);
1384 $params[
'APP_ID'] = $server->getClientId();
1386 $iterator = RestProviderTable::getList(array(
1387 'select' => array(
'ID'),
1389 '=APP_ID' => $params[
'APP_ID'],
1390 '=CODE' => $params[
'CODE']
1393 $result = $iterator->fetch();
1396 throw new RestException(
'Provider not found!', self::ERROR_ACTIVITY_NOT_FOUND);
1398 RestProviderTable::delete($result[
'ID']);
1413 if (Loader::includeModule(
'messageservice'))
1415 return \Bitrix\MessageService\RestService::getSenderList($params, $n, $server);
1418 if(!$server->getClientId())
1423 self::checkAdminPermissions();
1424 $iterator = RestProviderTable::getList(array(
1425 'select' => array(
'CODE'),
1427 '=APP_ID' => $server->getClientId()
1432 while ($row = $iterator->fetch())
1434 $result[] = $row[
'CODE'];
1439 private static function getSelect($rules, $fields, $default = array())
1442 if (!empty($rules) && is_array($rules))
1444 foreach ($rules as $field)
1446 $field = mb_strtoupper($field);
1447 if (isset($fields[$field]) && !in_array($field, $select))
1448 $select[$field] = $fields[$field];
1452 return $select ? $select : $default;
1455 private static function getOrder($rules, $fields, array $default = array())
1458 if (!empty($rules) && is_array($rules))
1460 foreach ($rules as $field => $ordering)
1462 $field = mb_strtoupper($field);
1463 $ordering = mb_strtoupper($ordering);
1464 if (isset($fields[$field]))
1465 $order[$fields[$field]] = $ordering ==
'DESC' ?
'DESC' :
'ASC';
1469 return $order ? $order : $default;
1472 private static function getFilter($rules, $fields, array $datetimeFieldsList = array())
1475 if (!empty($rules) && is_array($rules))
1477 foreach ($rules as $key => $value)
1479 if (preg_match(
'/^([^a-zA-Z]*)(.*)/', $key, $matches))
1481 $operation = $matches[1];
1482 $field = $matches[2];
1484 if (in_array($operation, static::$allowedOperations,
true) && isset($fields[$field]))
1486 if (in_array($field, $datetimeFieldsList))
1487 $value = \CRestUtil::unConvertDateTime($value);
1489 $filter[$operation.$fields[$field]] = $value;
1498 private static function checkAdminPermissions()
1500 if (!static::isAdmin())
1502 throw new AccessException();
1506 private static function isAdmin()
1514 || Loader::includeModule(
'bitrix24') && \CBitrix24::isPortalAdmin($USER->getID())
1519 private static function getCurrentUserId()
1522 return (isset($USER) && is_object($USER)) ? (int)$USER->getID() : 0;
1525 private static function generateInternalCode($data)
1527 return md5($data[
'APP_ID'].
'@'.$data[
'CODE']);
1530 private static function getAppName($appId)
1532 if (!Loader::includeModule(
'rest'))
1533 return array(
'*' =>
'No app');
1535 $iterator = AppTable::getList(
1538 '=CLIENT_ID' => $appId
1540 'select' => array(
'ID',
'APP_NAME',
'CODE'),
1543 $app = $iterator->fetch();
1544 $result = array(
'*' =>
$app[
'APP_NAME'] ?
$app[
'APP_NAME'] :
$app[
'CODE']);
1546 $iterator = AppLangTable::getList(array(
1548 '=APP_ID' =>
$app[
'ID'],
1550 'select' => array(
'LANGUAGE_ID',
'MENU_NAME')
1552 while($lang = $iterator->fetch())
1554 $result[mb_strtoupper($lang[
'LANGUAGE_ID'])] = $lang[
'MENU_NAME'];
1560 private static function getAppId($clientId)
1562 if (!Loader::includeModule(
'rest'))
1567 $iterator = AppTable::getList(
1570 '=CLIENT_ID' => $clientId
1572 'select' => array(
'ID'),
1575 $app = $iterator->fetch();
1577 return (
int)
$app[
'ID'];
1580 private static function prepareActivityData(array $data, $ignore =
false)
1583 $data = array_change_key_case($data, CASE_UPPER);
1584 foreach ($data as $key => &$field)
1586 if (is_array($field))
1587 $field = self::prepareActivityData($field, $key ==
'PROPERTIES' || $key ==
'RETURN_PROPERTIES' || $key ==
'OPTIONS');
1592 private static function validateActivity($data, $server)
1594 if (!is_array($data) || empty($data))
1595 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1597 static::validateActivityCode($data[
'CODE']);
1598 static::validateActivityHandler($data[
'HANDLER'], $server);
1599 if (empty($data[
'NAME']))
1600 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1602 if (isset($data[
'PROPERTIES']))
1603 static::validateActivityProperties($data[
'PROPERTIES']);
1605 if (isset($data[
'RETURN_PROPERTIES']))
1606 static::validateActivityProperties($data[
'RETURN_PROPERTIES']);
1607 if (isset($data[
'DOCUMENT_TYPE']))
1608 static::validateActivityDocumentType($data[
'DOCUMENT_TYPE']);
1609 if (isset($data[
'FILTER']) && !is_array($data[
'FILTER']))
1610 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1613 private static function validateProvider($data, $server)
1615 if (!is_array($data) || empty($data))
1616 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1618 static::validateActivityCode($data[
'CODE']);
1619 static::validateActivityHandler($data[
'HANDLER'], $server);
1620 if (empty($data[
'NAME']))
1621 throw new RestException(
'Empty provider NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1623 if (empty($data[
'TYPE']))
1624 throw new RestException(
'Empty provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1627 throw new RestException(
'Unknown provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1630 private static function validateRobot($data, $server)
1632 if (!is_array($data) || empty($data))
1633 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1635 static::validateActivityCode($data[
'CODE']);
1636 static::validateActivityHandler($data[
'HANDLER'], $server);
1637 if (empty($data[
'NAME']))
1638 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1640 if (isset($data[
'PROPERTIES']))
1641 static::validateActivityProperties($data[
'PROPERTIES']);
1643 if (isset($data[
'RETURN_PROPERTIES']))
1644 static::validateActivityProperties($data[
'RETURN_PROPERTIES']);
1645 if (isset($data[
'FILTER']) && !is_array($data[
'FILTER']))
1646 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1649 private static function validateActivityCode($code)
1653 throw new RestException(
'Empty activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1655 if (!is_string($code) || !preg_match(
'#^[a-z0-9\.\-_]+$#i', $code))
1657 throw new RestException(
'Wrong activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1661 private static function validateActivityHandler($handler, $server)
1666 private static function validateActivityProperties($properties)
1668 if (!is_array($properties))
1669 throw new RestException(
'Wrong properties array!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1671 foreach ($properties as $key => $property)
1673 if (!preg_match(
'#^[a-z][a-z0-9_]*$#i', $key))
1674 throw new RestException(
'Wrong property key ('.$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1675 if (empty($property[
'NAME']))
1676 throw new RestException(
'Empty property NAME ('.$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1680 private static function validateActivityDocumentType($documentType)
1684 $runtime = \CBPRuntime::getRuntime();
1685 $runtime->startRuntime();
1687 $documentService = $runtime->getService(
'DocumentService');
1688 $documentService->getDocumentFieldTypes($documentType);
1690 catch (\CBPArgumentNullException $e)
1692 throw new RestException(
'Wrong activity DOCUMENT_TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1696 private static function getDocumentId($documentId): ?array
1700 $documentService = \CBPRuntime::getRuntime()->getDocumentService();
1701 $documentId = $documentService->normalizeDocumentId($documentId);
1702 if ($documentService->getDocument($documentId))
1707 catch (\CBPArgumentException $exception) {}
1712 private static function getDocumentType(array $documentId): ?array
1716 $documentId = \CBPHelper::parseDocumentId($documentId);
1717 $runtime = \CBPRuntime::getRuntime(
true);
1718 $documentService = $runtime->getDocumentService();
1720 return $documentService->getDocumentType($documentId);
1722 catch (\CBPArgumentNullException $e) {}
1727 private static function getTemplateDocumentType(
int $id): ?array
1729 $tpl = WorkflowTemplateTable::getList([
1730 'select' => [
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
1731 'filter' => [
'=ID' => $id],
1736 return [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']];
1741 private static function validateTemplateName($name)
1745 throw new RestException(
'Empty activity code!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1749 private static function upsertAppPlacement(
int $appId,
string $code,
string $handler)
1752 '=APP_ID' => $appId,
1753 '=ADDITIONAL' => $code,
1754 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1757 $dbRes = PlacementTable::getList(array(
1761 $placementHandler = $dbRes->fetch();
1763 if ($placementHandler)
1765 $result = PlacementTable::update($placementHandler[
'ID'], [
'PLACEMENT_HANDLER' => $handler]);
1769 $placementBind = array(
1771 'ADDITIONAL' => $code,
1772 'PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1773 'PLACEMENT_HANDLER' => $handler,
1776 $result = PlacementTable::add($placementBind);
1779 if(!$result->isSuccess())
1781 $errorMessage = $result->getErrorMessages();
1782 throw new RestException(
1783 'Unable to set placement handler: '.implode(
', ', $errorMessage),
1789 private static function deleteAppPlacement(
int $appId,
string $code =
null)
1792 '=APP_ID' => $appId,
1793 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1798 $filter[
'=ADDITIONAL'] = $code;
1801 $dbRes = PlacementTable::getList(array(
1805 while($placementHandler = $dbRes->fetch())
1807 PlacementTable::delete($placementHandler[
"ID"]);
1811 private static function prepareTemplateData($data)
1815 $fileFields = \CRestUtil::saveFile($data);
1819 return file_get_contents($fileFields[
'tmp_name']);
1822 throw new RestException(
'Incorrect field TEMPLATE_DATA!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1825 private static function validateTemplateDocumentType($documentType)
1829 $documentService = \CBPRuntime::getRuntime(
true)->getDocumentService();
1830 $documentService->getDocumentFieldTypes($documentType);
1832 catch (\CBPArgumentNullException $e)
1834 throw new RestException(
'Incorrect field DOCUMENT_TYPE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1838 private static function validateTemplateAutoExecution($flag)
1840 if ($flag === (
string) (
int) $flag)
1842 $flag = (int) $flag;
1847 \CBPDocumentEventType::None,
1848 \CBPDocumentEventType::Create,
1849 \CBPDocumentEventType::Edit,
1850 \CBPDocumentEventType::Create | \CBPDocumentEventType::Edit
1860 throw new RestException(
'Incorrect field AUTO_EXECUTE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1863 private static function generateTemplateSystemCode(\CRestServer $server)
1865 $appId = self::getAppId($server->getClientId());
1867 return 'rest_app_'.$appId;
1870 private static function extractEventToken($token)
1872 $data = \CBPRestActivity::extractToken($token);
1874 throw new AccessException();
1884 private static function getApp($server)
1886 if(self::$app ==
null)
1888 if (Loader::includeModule(
'rest'))
1890 $result = AppTable::getList(
1893 '=CLIENT_ID' => $server->getClientId()
1897 self::$app = $result->fetch();