1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
WorkflowStateService.php
См. документацию.
1<?php
2
3namespace Bitrix\Bizproc\Api\Service;
4
5use Bitrix\Bizproc\Api\Data\WorkflowStateService\WorkflowStateToGet;
6use Bitrix\Bizproc\Api\Request\WorkflowAccessService\CanViewTimelineRequest;
7use Bitrix\Bizproc\Api\Request\WorkflowStateService\GetAverageWorkflowDurationRequest;
8use Bitrix\Bizproc\Api\Request\WorkflowStateService\GetExecutionTimeRequest;
9use Bitrix\Bizproc\Api\Request\WorkflowStateService\GetEfficiencyDataRequest;
10use Bitrix\Bizproc\Api\Request\WorkflowStateService\GetTimelineRequest;
11use Bitrix\Bizproc\Api\Response\Error;
12use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetAverageWorkflowDurationResponse;
13use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetExecutionTimeResponse;
14use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetEfficiencyDataResponse;
15use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetFullFilledListResponse;
16use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetListResponse;
17use Bitrix\Bizproc\Api\Response\WorkflowStateService\GetTimelineResponse;
18use Bitrix\Bizproc\Workflow\Entity\EO_WorkflowState_Collection;
19use Bitrix\Bizproc\Workflow\Entity\WorkflowDurationStatTable;
20use Bitrix\Bizproc\Workflow\Entity\WorkflowInstanceTable;
21use Bitrix\Bizproc\Workflow\Entity\WorkflowStateTable;
22use Bitrix\Bizproc\Workflow\Entity\WorkflowUserTable;
23use Bitrix\Bizproc\Workflow\Task\EO_Task_Collection;
24use Bitrix\Bizproc\Workflow\Task\TaskTable;
25use Bitrix\Bizproc\Workflow\Timeline;
26use Bitrix\Bizproc\Workflow\WorkflowState;
27use Bitrix\Main\SystemException;
28use Bitrix\Main\Type\DateTime;
29
31{
32 private const CONVERTER_VERSION = 2;
33
34 private const THREE_DAYS_IN_SECONDS = 259200; // 3600 * 24 *3
35
37 {
38 $this->convertProcesses($toGet->getFilterUserId());
39
41 $responseCollection = new EO_WorkflowState_Collection();
42
43 $query = WorkflowUserTable::query()
44 ->addSelect('WORKFLOW_ID')
45 ->addSelect('MODIFIED')
46 ->setFilter($toGet->getOrmFilter())
47 ->setOrder($toGet->getOrder())
48 ->setLimit($toGet->getLimit())
49 ->setOffset($toGet->getOffset())
50 ->countTotal($toGet->isCountingTotal())
51 ;
52 $runtimeField = $toGet->getOrmRuntime();
53
54 if ($runtimeField)
55 {
56 $query->registerRuntimeField($runtimeField);
57 }
58
59 $queryResult = $query->exec();
60
61 if ($toGet->isCountingTotal())
62 {
63 $response->setTotalCount($queryResult->getCount());
64 }
65 $workflowStates = $queryResult->fetchAll();
66 $ids = array_column($workflowStates, 'WORKFLOW_ID');
67 $mods = array_column($workflowStates, 'MODIFIED');
68
69 if ($ids)
70 {
71 $query = WorkflowStateTable::query()->setSelect($toGet->getSelect());
72 if (count($ids) === 1)
73 {
74 $query->where('ID', '=', $ids[0]);
75 }
76 else
77 {
78 $query->whereIn('ID', $ids);
79 }
80
81 $collection = $query->exec()->fetchCollection();
82
83 foreach ($ids as $k => $id)
84 {
85 $workflowState = $collection->getByPrimary($id);
86 if ($workflowState)
87 {
88 $responseCollection->add($workflowState);
89 $response->setUserModified($id, $mods[$k]);
90 $workflowTasks = $this->getWorkflowTasks($workflowState, $toGet);
91 if (isset($workflowTasks))
92 {
93 $response->setWorkflowTasks($id, $workflowTasks);
94 }
95 }
96 }
97 }
98
99 return $response->setWorkflowStatesCollection($responseCollection);
100 }
101
102 private function getWorkflowTasks(WorkflowState $workflowState, WorkflowStateToGet $toGet): ?EO_Task_Collection
103 {
104 $taskFields = $toGet->getSelectTaskFields();
105 if ($taskFields)
106 {
107 $activeTasksQuery = TaskTable::query()
108 ->setSelect($taskFields)
109 ->setFilter([
110 '=WORKFLOW_ID' => $workflowState->getId(),
111 '=TASK_USERS.USER_ID' => $toGet->getFilterUserId(),
112 '=TASK_USERS.STATUS' => \CBPTaskUserStatus::Waiting,
113 ])
114 ->setOrder(['ID' => 'DESC'])
115 ;
116
117 $taskLimit = $toGet->getSelectTaskLimit();
118 if (isset($taskLimit))
119 {
120 $activeTasksQuery->setLimit($taskLimit);
121 }
122
123 $userActiveTasks = $activeTasksQuery->exec()->fetchCollection();
124
125 $remainingTasksCount = null;
126 if (isset($taskLimit))
127 {
128 $remainingTasksCount = $taskLimit - $userActiveTasks->count();
129 }
130
131 if (isset($remainingTasksCount) && $remainingTasksCount <= 0)
132 {
133 return $userActiveTasks;
134 }
135
136 $workflowTasksQuery = TaskTable::query()
137 ->setSelect($taskFields)
138 ->setFilter([
139 '=WORKFLOW_ID' => $workflowState->getId(),
140 [
141 'LOGIC' => 'OR',
142 '!=TASK_USERS.USER_ID' => $toGet->getFilterUserId(),
143 '!=TASK_USERS.STATUS' => \CBPTaskUserStatus::Waiting,
144 ],
145 ])
146 ->setOrder(['ID' => 'DESC'])
147 ;
148
149 if (isset($remainingTasksCount))
150 {
151 $workflowTasksQuery->setLimit($remainingTasksCount);
152 }
153
154 return $userActiveTasks->merge($workflowTasksQuery->exec()->fetchCollection());
155 }
156
157 return null;
158 }
159
161 {
163
164 $toGet->setSelectAllFields();
165 $getListResult = $this->getList($toGet);
166 $collection = $getListResult->getWorkflowStatesCollection();
167 if (!$collection)
168 {
169 return $response->setWorkflowStatesList([]);
170 }
171
172 $fullFilledList = [];
173 $userIds = [];
174 foreach ($collection as $stateElement)
175 {
176 $tasksInfo = $stateElement->getTasksInfo();
177 foreach ($tasksInfo as $task)
178 {
179 if (!empty($task['TASK_USERS']))
180 {
181 foreach ($task['TASK_USERS'] as $row)
182 {
183 $userIds[$row['USER_ID']] = true;
184 $userIds[$row['ORIGINAL_USER_ID']] = true;
185 }
186 }
187 }
188
189 $fullFilledList[] = [
190 'ID' => $stateElement->getId(),
191 'STARTED' => $stateElement->getStarted(),
192 'MODIFIED' => $stateElement->getModified(),
193 'STATE_INFO' => $stateElement->getStateInfo(),
194 'DOCUMENT_INFO' => $this->getDocumentInfo($stateElement->getComplexDocumentId()),
195 'STARTED_USER_INFO' => [
196 'ID' => $stateElement->getStartedBy(),
197 ],
198 'TASKS_INFO' => $tasksInfo,
199 'WORKFLOW_TEMPLATE_ID' => $stateElement->getWorkflowTemplateId(),
200 'TEMPLATE_NAME' => $stateElement->getTemplate()?->getName(),
201 'META' => $stateElement->getMeta()?->collectValues() ?? [],
202 ];
203
204 $userIds[$stateElement->getStartedBy()] = true;
205 }
206
207 return (
209 ->setWorkflowStatesList($fullFilledList)
210 ->setMembersInfo($this->getMembersInfo(array_keys($userIds)))
211 );
212 }
213
215 {
216 if (!$request->workflowId)
217 {
218 return GetTimelineResponse::createError(Error::fromCode(Error::WORKFLOW_NOT_FOUND));
219 }
220
221 $isAdmin = (new \CBPWorkflowTemplateUser($request->userId))->isAdmin();
222
223 if (!$isAdmin)
224 {
225 $accessService = new WorkflowAccessService();
226 $accessRequest = new CanViewTimelineRequest(workflowId: $request->workflowId, userId: $request->userId);
227
228 $accessResponse = $accessService->canViewTimeline($accessRequest);
229 if (!$accessResponse->isSuccess())
230 {
231 return (new GetTimelineResponse())->addErrors($accessResponse->getErrors());
232 }
233 }
234
235 $timeline = Timeline::createByWorkflowId($request->workflowId);
236
237 if (!$timeline)
238 {
239 return GetTimelineResponse::createError(Error::fromCode(Error::WORKFLOW_NOT_FOUND));
240 }
241
242 return GetTimelineResponse::createOk(['timeline' => $timeline->setUserId($request->userId)]);
243 }
244
245 private function getDocumentInfo(array $complexDocumentId): array
246 {
247 $documentService = \CBPRuntime::getRuntime()->getDocumentService();
248
249 $key = null;
250 try
251 {
252 $complexDocumentType = $documentService->getDocumentType($complexDocumentId);
253 if ($complexDocumentType)
254 {
255 $key = $complexDocumentId[0] . '@' . $complexDocumentId[1] . '@' . $complexDocumentType[2];
256 }
257 }
258 catch (SystemException | \Exception $exception)
259 {
260 $complexDocumentType = null;
261 }
262
263 static $cache = [];
264 if ($key && !isset($cache[$key]))
265 {
266 $cache[$key] = $documentService->getDocumentTypeCaption($complexDocumentType);
267 }
268 $typeCaption = $key ? $cache[$key] : '';
269
270 return [
271 'COMPLEX_ID' => $complexDocumentId,
272 'COMPLEX_TYPE' => $complexDocumentType,
273 'NAME' => $documentService->getDocumentName($complexDocumentId),
274 'TYPE_CAPTION' => $typeCaption,
275 ];
276 }
277
278 private function getMembersInfo(array $ids): array
279 {
280 if (empty($ids))
281 {
282 return [];
283 }
284
285 $userFields = ['ID', 'NAME', 'SECOND_NAME', 'LAST_NAME', 'LOGIN', 'TITLE', 'EMAIL', 'PERSONAL_PHOTO'];
286
287 $users = \CUser::GetList(
288 'id',
289 'asc',
290 ['ID' => implode('|', $ids)],
291 ['FIELDS' => $userFields]
292 );
293
294 $info = [];
295 while ($user = $users->Fetch())
296 {
297 $fullName = \CUser::FormatName(\CSite::GetNameFormat(false), $user, true, false);
298 $personalPhoto = (int)$user['PERSONAL_PHOTO'];
299
300 $info[] = [
301 'ID' => (int)($user['ID'] ?? 0),
302 'FULL_NAME' => $fullName,
303 'PERSONAL_PHOTO' => $personalPhoto,
304 ];
305 }
306
307 return $info;
308 }
309
310 private function convertProcesses(int $userId)
311 {
312 if (empty($userId))
313 {
314 return;
315 }
316
317 $converterVersion = \CUserOptions::getOption(
318 'bizproc',
319 'processes_converted',
320 0,
321 $userId
322 );
323
324 if ($converterVersion === self::CONVERTER_VERSION)
325 {
326 return;
327 }
328
329 WorkflowUserTable::convertUserProcesses($userId);
330
331 \CUserOptions::setOption(
332 'bizproc',
333 'processes_converted',
334 self::CONVERTER_VERSION,
335 false,
336 $userId
337 );
338 }
339
343 {
344 // rights? canUserOperateDocumentType(CBPCanUserOperateOperation::ReadDocument, ...)
345
347 if ($request->templateId <= 0)
348 {
349 $response->addError(new Error('incorrect template id'));
350 }
351
352 if ($response->isSuccess())
353 {
354 $averageDuration = WorkflowDurationStatTable::getAverageDurationByTemplateId($request->templateId);
355 if ($averageDuration !== null)
356 {
357 $response->setAverageDuration($averageDuration);
358 }
359 }
360
361 return $response;
362 }
363
365 {
367
368 if ($request->workflowStarted === null)
369 {
370 return $response->addError(new Error('incorrect workflowStarted'));
371 }
372
373 $startedTimestamp = $request->workflowStarted?->getTimestamp();
374 if (WorkflowInstanceTable::exists($request->workflowId))
375 {
376 $currentTimestamp = (new DateTime())->getTimestamp();
377
378 return $response->setExecutionTime($currentTimestamp - $startedTimestamp);
379 }
380
381 $modifiedTimestamp = $request->workflowModified->getTimestamp();
382
383 return $response->setExecutionTime($modifiedTimestamp - $startedTimestamp);
384 }
385
387 {
388 $workflow = WorkflowStateTable::query()
389 ->setSelect([
390 'ID',
391 'MODIFIED',
392 'STARTED',
393 'WORKFLOW_TEMPLATE_ID',
394 ])
395 ->setFilter([
396 '=ID' => $workflowId,
397 '=STATE' => 'Completed',
398 ])
399 ->exec()
400 ->fetchObject()
401 ;
402
403 if ($workflow)
404 {
405 $executionTime = $this->getExecutionTime(
407 workflowId: $workflow->getId(),
408 workflowStarted: $workflow->getStarted(),
409 workflowModified: $workflow->getModified()
410 )
411 )->getRoundedExecutionTime();
412 $averageDuration = $this->getAverageWorkflowDuration(
414 templateId: $workflow->getWorkflowTemplateId(),
415 )
416 )->getRoundedAverageDuration();
418 executionTime: $executionTime,
419 averageDuration: $averageDuration ?? $executionTime
420 );
421
422 return $this->getEfficiencyData($request);
423 }
424
426 $response->addError(new Error('WorkflowState not found'));
427
428 return $response;
429 }
430
432 {
434
435 $averageDuration = $request->averageDuration;
436 $currentDuration = $request->executionTime;
437
438 $efficiency = 'stopped';
439 if (null === $averageDuration)
440 {
441 $efficiency = 'first';
442 }
443 elseif ($currentDuration <= $averageDuration)
444 {
445 $efficiency = 'fast';
446 }
447 elseif ($currentDuration <= ($averageDuration + self::THREE_DAYS_IN_SECONDS))
448 {
449 $efficiency = 'slow';
450 }
451
452 $response->setAverageDuration($request->averageDuration);
453 $response->setExecutionTime($request->executionTime);
454 $response->setEfficiency($efficiency);
455
456 return $response;
457 }
458}
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
getTimeline(GetTimelineRequest $request)
Определения WorkflowStateService.php:214
getEfficiencyData(GetEfficiencyDataRequest $request)
Определения WorkflowStateService.php:431
getExecutionTime(GetExecutionTimeRequest $request)
Определения WorkflowStateService.php:364
getList(WorkflowStateToGet $toGet)
Определения WorkflowStateService.php:36
getAverageWorkflowDuration(GetAverageWorkflowDurationRequest $request)
Определения WorkflowStateService.php:340
getCompletedWorkflowEfficiency(string $workflowId)
Определения WorkflowStateService.php:386
getFullFilledList(WorkflowStateToGet $toGet)
Определения WorkflowStateService.php:160
static fromCode(string $code, $customData=null)
Определения error.php:13
Определения error.php:15
const Waiting
Определения constants.php:273
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$query
Определения get_search.php:11
if($NS['step']==6) if( $NS[ 'step']==7) if(COption::GetOptionInt('main', 'disk_space', 0) > 0) $info
Определения backup.php:924
$user
Определения mysql_to_pgsql.php:33
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$response
Определения result.php:21
$k
Определения template_pdf.php:567