Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
manager.php
1<?php
2
4
5use Bitrix\Bizproc\Script\Entity\EO_ScriptQueue;
10use Bitrix\Main;
13
15{
16 private const CACHE_TTL = 3600;
17 private const LIMIT_DOCUMENT_ID = 1000;
18 private const LIMIT_QUEUES = 1;
19
20 public static function getListByDocument(array $documentType, $showInactive = false)
21 {
22
23 $filter = [
24 '=MODULE_ID' => $documentType[0],
25 '=ENTITY' => $documentType[1],
26 '=DOCUMENT_TYPE' => $documentType[2],
27 ];
28
29 if (!$showInactive)
30 {
31 $filter['=ACTIVE'] = 'Y';
32 }
33
34 $list = Entity\ScriptTable::getList(
35 [
36 'select' => [
37 'ID', 'NAME', 'ORIGINATOR_ID', 'ORIGIN_ID',
38 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'NAME', 'DESCRIPTION',
39 ],
40 'filter' => $filter,
41 'order' => [
42 'SORT' => 'ASC',
43 'NAME' => 'ASC'
44 ],
45 'cache' => ['ttl' => self::CACHE_TTL],
46 ]
47 )->fetchAll();
48
49 return $list;
50 }
51
52 public static function getById($id)
53 {
54 $script = Entity\ScriptTable::getList(
55 [
56 'select' => ['*'],
57 'filter' => [
58 '=ID' => $id,
59 ],
60 ]
61 )->fetchObject();
62
63 return $script;
64 }
65
66 public static function getQueueById(int $queueId): ?EO_ScriptQueue
67 {
68 return Entity\ScriptQueueTable::getById($queueId)->fetchObject();
69 }
70
71 public static function saveScript(int $id, array $documentType, array $fields, $userId = null)
72 {
73 if ($id > 0)
74 {
75 $result = self::updateScript($id, $fields['script'], $fields['robotsTemplate'], $userId);
76 }
77 else
78 {
79 $result = self::addScript($documentType, $fields['script'], $fields['robotsTemplate'], $userId);
80 }
81
82 if ($result->isSuccess())
83 {
84 self::clearMenuCache();
85 }
86
87 return $result;
88 }
89
90 public static function createScript(array $documentType)
91 {
92 $fields = [
93 'ID' => 0,
94 'MODULE_ID' => $documentType[0],
95 'ENTITY' => $documentType[1],
96 'DOCUMENT_TYPE' => $documentType[2],
97 'NAME' => Loc::getMessage("BIZPROC_SCRIPT_MANAGER_NEW_SCRIPT"),
98 'DESCRIPTION' => Loc::getMessage("BIZPROC_SCRIPT_MANAGER_NEW_DESCRIPTION"),
99 ];
100
101 return $fields;
102 }
103
104 private static function updateScript($id, array $scriptFields, array $templateFields, $userId): Main\Result
105 {
106 $script = static::getById($id);
107
108 if (!$script)
109 {
110 $result = new Main\Result();
111 $result->addError(new Main\Error('Script not found'));
112
113 return $result;
114 }
115
116 $wl = array_fill_keys(['NAME', 'DESCRIPTION'], true);
117
118 $scriptFields = array_intersect_key($scriptFields, $wl);
119 $scriptFields['MODIFIED_BY'] = $userId;
120 $scriptFields['MODIFIED_DATE'] = new Main\Type\DateTime();
121
122 $scriptUpdateResult = Entity\ScriptTable::update($script['ID'], $scriptFields);
123
124 if (!$scriptUpdateResult->isSuccess())
125 {
126 return $scriptUpdateResult;
127 }
128
129 $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
130
131 $template = null;
132 $tpl = WorkflowTemplateTable::getById($script['WORKFLOW_TEMPLATE_ID'])->fetchObject();
133 if ($tpl)
134 {
135 $template = \Bitrix\Bizproc\Automation\Engine\Template::createByTpl($tpl);
136 }
137
138 if (!$template)
139 {
140 $template = new \Bitrix\Bizproc\Automation\Engine\Template($documentType);
141 }
142
143 $template->setName($scriptFields['NAME'] ?? $script->getName());
144 $robots = isset($templateFields['ROBOTS']) && is_array($templateFields['ROBOTS']) ? $templateFields['ROBOTS'] : [];
145
146 $result = $template->save($robots, $userId);
147
148 if ($result->isSuccess())
149 {
150 self::saveTemplateConfigs($template->getId(), $templateFields);
151 }
152
153 return $result;
154 }
155
156 private static function addScript(array $documentType, array $scriptFields, array $templateFields, $userId): Main\Result
157 {
158 $templateFields['NAME'] = $scriptFields['NAME'];
159 $result = self::addWorkflowTemplate($documentType, $templateFields, $userId);
160
161 if (!$result->isSuccess())
162 {
163 return $result;
164 }
165
166 return self::addScriptRecord(
167 $documentType,
168 [
169 'WORKFLOW_TEMPLATE_ID' => $result->getData()['ID'],
170 'NAME' => $scriptFields['NAME'],
171 'DESCRIPTION' => $scriptFields['DESCRIPTION'],
172 ],
173 $userId
174 );
175 }
176
177 private static function addWorkflowTemplate(array $documentType, array $templateFields, int $userId, $extractParameters = true)
178 {
179 $template = new \Bitrix\Bizproc\Automation\Engine\Template($documentType);
180 $robots = isset($templateFields['ROBOTS']) && is_array($templateFields['ROBOTS']) ? $templateFields['ROBOTS'] : [];
181 $template->setDocumentStatus('SCRIPT');
182 $template->setName($templateFields['NAME']);
183 $template->setExecuteType(\CBPDocumentEventType::Script);
184
185 $result = $template->save($robots, $userId);
186
187 if (!$result->isSuccess())
188 {
189 return $result;
190 }
191
192 self::saveTemplateConfigs($template->getId(), $templateFields, $extractParameters);
193
194 $result->setData(['ID' => $template->getId()]);
195
196 return $result;
197 }
198
199 private static function addScriptRecord(array $documentType, array $scriptFields, int $userId)
200 {
201 $addFields = [
202 'MODULE_ID' => $documentType[0],
203 'ENTITY' => $documentType[1],
204 'DOCUMENT_TYPE' => $documentType[2],
205 'WORKFLOW_TEMPLATE_ID' => $scriptFields['WORKFLOW_TEMPLATE_ID'],
206 'NAME' => $scriptFields['NAME'],
207 'DESCRIPTION' => $scriptFields['DESCRIPTION'],
208 'CREATED_BY' => $userId,
209 'CREATED_DATE' => new Main\Type\DateTime(),
210 'MODIFIED_BY' => $userId,
211 'MODIFIED_DATE' => new Main\Type\DateTime(),
212 ];
213
214 if (isset($scriptFields['ORIGINATOR_ID']) && isset($scriptFields['ORIGIN_ID']))
215 {
216 $addFields['ORIGINATOR_ID'] = $scriptFields['ORIGINATOR_ID'];
217 $addFields['ORIGIN_ID'] = $scriptFields['ORIGIN_ID'];
218 }
219
220 return Entity\ScriptTable::add($addFields);
221 }
222
223 private static function saveTemplateConfigs(int $tplId, array $templateFields, $extractParameters = true)
224 {
225 $tpl = WorkflowTemplateTable::getById($tplId)->fetchObject();
226 if (!$tpl)
227 {
228 return false;
229 }
230
231 $constants = $templateFields['CONSTANTS'] ?? [];
232 $parameters = $templateFields['PARAMETERS'] ?? [];
233
234 $usages = $tpl->collectUsages();
235
236 $usedConstants = $usages->getValuesBySourceType(SourceType::Constant);
237 $usedParameters = $usages->getValuesBySourceType(SourceType::Parameter);
238
239 $constants = array_intersect_key($constants, array_fill_keys($usedConstants, true));
240 $parameters = array_intersect_key($parameters, array_fill_keys($usedParameters, true));
241
242 if ($extractParameters)
243 {
244 $constants = self::extractProperties($constants, $tpl->getDocumentComplexType());
245 $parameters = self::extractProperties($parameters, $tpl->getDocumentComplexType());
246 }
247
248 \CBPWorkflowTemplateLoader::update(
249 $tplId,
250 ['CONSTANTS' => $constants, 'PARAMETERS' => $parameters],
251 true
252 );
253 }
254
255 private static function extractProperties(array $properties, array $documentType): array
256 {
257 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
258
259 foreach ($properties as $i => $property)
260 {
261 $properties[$i]['Default'] = $documentService->GetFieldInputValue(
262 $documentType,
263 $property,
264 'field',
265 ['field' => $property['Default']],
266 $errors
267 );
268 }
269
270 return $properties;
271 }
272
273 public static function deleteScript($id): Main\Result
274 {
275 $script = static::getById($id);
276 $result = new Main\Result();
277
278 if (!$script)
279 {
280 $result->addError(new Main\Error('Script not found'));
281
282 return $result;
283 }
284
285 try
286 {
287 \CBPWorkflowTemplateLoader::getLoader()->deleteTemplate($script['WORKFLOW_TEMPLATE_ID']);
288 Entity\ScriptTable::delete($id);
289 Entity\ScriptQueueTable::deleteByScript($id);
290
291 self::clearMenuCache();
292 }
293 catch (\Exception $e)
294 {
295 $result->addError(new Main\Error($e->getMessage()));
296 }
297
298 return $result;
299 }
300
301 public static function activateScript($id): Main\Result
302 {
303 $script = static::getById($id);
304 $result = new Main\Result();
305
306 if (!$script)
307 {
308 $result->addError(new Main\Error('Script not found'));
309
310 return $result;
311 }
312
313 $script->setActive('Y');
314 $script->save();
315
316 \CBPWorkflowTemplateLoader::update($script->getWorkflowTemplateId(), ['ACTIVE' => 'Y'], true);
317
318 self::clearMenuCache();
319
320 return $result;
321 }
322
323 public static function deactivateScript($id): Main\Result
324 {
325 $script = static::getById($id);
326 $result = new Main\Result();
327
328 if (!$script)
329 {
330 $result->addError(new Main\Error('Script not found'));
331
332 return $result;
333 }
334
335 \CBPWorkflowTemplateLoader::update($script->getWorkflowTemplateId(), ['ACTIVE' => 'N'], true);
336
337 $script->setActive('N');
338 $script->save();
339 self::clearMenuCache();
340
341 return $result;
342 }
343
344 public static function startScript(
345 int $scriptId,
346 int $userId,
347 array $documentIds,
348 array $parameters = []
350 {
351 $result = new StartScriptResult();
352
353 $script = self::getById($scriptId);
354 if (!$script)
355 {
356 return $result->addScriptNotExistError();
357 }
358 if (!$script->getActive())
359 {
360 return $result->addInactiveScriptError();
361 }
362
363 $script->fill('WORKFLOW_TEMPLATE');
364 $template = $script->getWorkflowTemplate();
365 if (!$template)
366 {
367 return $result->addTemplateNotExistError();
368 }
369
370 $templateParameters = $template->getParameters();
371 if ($templateParameters)
372 {
373 if (empty($parameters))
374 {
375 return $result->addEmptyTemplateParameterError();
376 }
377
378 $errors = [];
379 $parameters = \CBPWorkflowTemplateLoader::checkWorkflowParameters(
380 $templateParameters,
381 $parameters,
382 $template->getDocumentComplexType(),
383 $errors
384 );
385 if ($errors)
386 {
387 return $result->addInvalidParameterErrors($errors);
388 }
389 }
390
391 $documentIds = array_unique($documentIds);
392
393 $addResult = ScriptQueueTable::add([
394 'SCRIPT_ID' => $scriptId,
395 'STARTED_DATE' => new Main\Type\DateTime(),
396 'STARTED_BY' => $userId,
397 'STATUS' => Queue\Status::QUEUED,
398 'MODIFIED_DATE' => new Main\Type\DateTime(),
399 'WORKFLOW_PARAMETERS' => $parameters,
400 ]);
401
402 $queueId = null;
403 if ($addResult->isSuccess())
404 {
405 $queueId = $addResult->getId();
406 $documentRows = array_map(
407 function ($id) use ($queueId)
408 {
409 return [
410 'QUEUE_ID' => $queueId,
411 'DOCUMENT_ID' => $id,
412 'STATUS' => Queue\Status::QUEUED,
413 ];
414 },
415 $documentIds
416 );
417 ScriptQueueDocumentTable::addMulti($documentRows, true);
418 }
419
420 Queue\Stepper::bind(1, [$queueId, $scriptId]);
421
422 $result->setData([
423 'queueId' => $queueId,
424 ]);
425
426 return $result;
427 }
428
429 public static function getActiveQueueCountByScriptId(int $scriptId): int
430 {
431 if ($scriptId > 0)
432 {
433 return \Bitrix\Bizproc\Script\Entity\ScriptTable::getActiveQueueCount($scriptId);
434 }
435
436 return 0;
437 }
438
439 public static function terminateQueue(int $queueId, int $userId)
440 {
441 ScriptQueueTable::markTerminated($queueId, $userId);
442 }
443
444 public static function deleteQueue(int $queueId, int $userId)
445 {
446 ScriptQueueTable::delete($queueId);
448 }
449
450 public static function canUserStartScript(int $scriptId, int $userId): bool
451 {
452 $user = new \CBPWorkflowTemplateUser($userId);
453
454 if ($user->isAdmin())
455 {
456 return true;
457 }
458
459 $script = static::getById($scriptId);
460 if (!$script)
461 {
462 return false;
463 }
464
465 $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
466
467 return \CBPDocument::canUserOperateDocumentType(
468 \CBPCanUserOperateOperation::ViewWorkflow,
469 $userId,
470 $documentType
471 );
472 }
473
474 public static function canUserEditScript(int $scriptId, int $userId): bool
475 {
476 $script = static::getById($scriptId);
477 if (!$script)
478 {
479 return false;
480 }
481
482 $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
483
484 return static::canUserCreateScript($documentType, $userId);
485 }
486
487 public static function canUserCreateScript(array $documentType, int $userId): bool
488 {
489 $user = new \CBPWorkflowTemplateUser($userId);
490
491 if ($user->isAdmin())
492 {
493 return true;
494 }
495
496 return \CBPDocument::canUserOperateDocumentType(
497 \CBPCanUserOperateOperation::CreateWorkflow,
498 $userId,
499 $documentType
500 );
501 }
502
503 public static function exportScript(int $scriptId): ?array
504 {
505 $script = static::getById($scriptId);
506 if (!$script)
507 {
508 return null;
509 }
510
511 $exportData = [
512 'MODULE_ID' => $script->getModuleId(),
513 'ENTITY' => $script->getEntity(),
514 'DOCUMENT_TYPE' => $script->getDocumentType(),
515 'NAME' => $script->getName(),
516 'DESCRIPTION' => $script->getDescription(),
517 'ORIGINATOR_ID' => $script->getOriginatorId(),
518 'ORIGIN_ID' => $script->getOriginId(),
519 ];
520
521 $script->fillWorkflowTemplate();
522 $roboPackage = new RoboPackage();
523 $packageData = $roboPackage->makePackageData($script->getWorkflowTemplate());
524 $exportData['WORKFLOW_TEMPLATE'] = [
525 'PARAMETERS' => $packageData['PARAMETERS'],
526 'CONSTANTS' => $packageData['CONSTANTS'],
527 'ROBOTS' => $packageData['ROBOTS'],
528 'DOCUMENT_FIELDS' => $packageData['DOCUMENT_FIELDS'],
529 'REQUIRED_APPLICATIONS' => $packageData['REQUIRED_APPLICATIONS'],
530 ];
531
532 return $exportData;
533 }
534
535 public static function importScript(array $data, int $userId)
536 {
537 $documentType = [$data['MODULE_ID'], $data['ENTITY'], $data['DOCUMENT_TYPE']];
538 $templateFields = $data['WORKFLOW_TEMPLATE'];
539 $templateFields['DOCUMENT_TYPE'] = $documentType;
540 $templateFields['NAME'] = $data['NAME'];
541 $templateFields['DESCRIPTION'] = $data['DESCRIPTION'];
542 $templateFields['ORIGINATOR_ID'] = $data['ORIGINATOR_ID'];
543 $templateFields['ORIGIN_ID'] = $data['ORIGIN_ID'];
544
545 $result = self::importWorkflowTemplate($templateFields, $userId);
546
547 if (!$result->isSuccess())
548 {
549 return $result;
550 }
551
552 $result = self::addScriptRecord(
553 $documentType,
554 [
555 'WORKFLOW_TEMPLATE_ID' => $result->getData()['ID'],
556 'NAME' => $data['NAME'],
557 'DESCRIPTION' => $data['DESCRIPTION'],
558 'ORIGINATOR_ID' => $data['ORIGINATOR_ID'],
559 'ORIGIN_ID' => $data['ORIGIN_ID'],
560 ],
561 $userId
562 );
563
564 if ($result->isSuccess())
565 {
566 self::clearMenuCache();
567 }
568
569 return $result;
570 }
571
572 private static function importWorkflowTemplate(array $data, int $userId)
573 {
574 $roboPackage = new RoboPackage();
575 $result = $roboPackage->unpack($data);
576
577 if ($result->isSuccess())
578 {
579 $tpl = $result->getTpl();
580 $tpl->setUserId($userId);
581 $tpl->setDocumentStatus('SCRIPT');
582 $tpl->setAutoExecute(\CBPDocumentEventType::Script);
583
584 $saveResult = $tpl->save();
585
586 if ($saveResult->isSuccess())
587 {
588 $result->setData(['ID' => $saveResult->getId()]);
589
590 \CBPWorkflowTemplateLoader::importDocumentFields(
591 $tpl->getDocumentComplexType(),
592 $result->getDocumentFields()
593 );
594 }
595 else
596 {
597 $result->addErrors($saveResult->getErrors());
598 }
599 }
600
601 return $result;
602 }
603
604 private static function clearMenuCache(): void
605 {
606 if (defined('BX_COMP_MANAGED_CACHE'))
607 {
608 $cache = Main\Application::getInstance()->getTaggedCache();
609 $cache->clearByTag('intranet_menu_binding');
610 }
611 }
612
613 public static function checkDocumentIdsLimit(array $documentIds): bool
614 {
615 return count($documentIds) <= self::getDocumentIdLimit();
616 }
617
618 public static function getDocumentIdLimit(): int
619 {
620 return self::LIMIT_DOCUMENT_ID;
621 }
622
623 public static function checkQueuesCount(int $scriptId): bool
624 {
625 $queuesCount = self::getActiveQueueCountByScriptId($scriptId);
626
627 return $queuesCount < self::getQueuesLimit();
628 }
629
630 public static function getQueuesLimit(): int
631 {
632 return self::LIMIT_QUEUES;
633 }
634}
static markTerminated(int $queueId, int $userId)
static saveScript(int $id, array $documentType, array $fields, $userId=null)
Definition manager.php:71
static getQueueById(int $queueId)
Definition manager.php:66
static checkQueuesCount(int $scriptId)
Definition manager.php:623
static exportScript(int $scriptId)
Definition manager.php:503
static canUserCreateScript(array $documentType, int $userId)
Definition manager.php:487
static checkDocumentIdsLimit(array $documentIds)
Definition manager.php:613
static getActiveQueueCountByScriptId(int $scriptId)
Definition manager.php:429
static createScript(array $documentType)
Definition manager.php:90
static canUserStartScript(int $scriptId, int $userId)
Definition manager.php:450
static startScript(int $scriptId, int $userId, array $documentIds, array $parameters=[])
Definition manager.php:344
static getListByDocument(array $documentType, $showInactive=false)
Definition manager.php:20
static deleteQueue(int $queueId, int $userId)
Definition manager.php:444
static canUserEditScript(int $scriptId, int $userId)
Definition manager.php:474
static terminateQueue(int $queueId, int $userId)
Definition manager.php:439
static importScript(array $data, int $userId)
Definition manager.php:535
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29