Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
document.php
1<?php
2
4
15use CApplicationException;
16use CCatalogDocs;
17use CMain;
18
19class Document extends Controller
20{
21 //region Actions
25 public function getFieldsAction(): array
26 {
27 return ['DOCUMENT' => $this->getViewFields()];
28 }
29
35 public function conductListAction(array $documentIds): ?bool
36 {
37 if (!Feature::isInventoryManagementEnabled())
38 {
39 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
40
41 return null;
42 }
43
44 if (!\Bitrix\Catalog\Component\UseStore::isUsed())
45 {
46 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_MANAGEMENT_NOT_ENABLED')));
47
48 return null;
49 }
50
51 global $APPLICATION;
52
53 $documentData = $this->getDocumentData($documentIds);
54
55 $userId = CurrentUser::get()->getId();
56 foreach ($documentIds as $documentId)
57 {
58 $document = $documentData[$documentId] ?? null;
59 if (!$document)
60 {
61 $this->addError(
63 'CATALOG_CONTROLLER_DOCUMENT_CONDUCT_GENERAL_ERROR',
64 [
65 '#ERROR#' => Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_NOT_FOUND'),
66 ]
67 ))
68 );
69 continue;
70 }
71
72 $documentTitle = $document['TITLE'] ?: StoreDocumentTable::getTypeList(true)[$document['DOC_TYPE']];
73
74 $can = $this->accessController->check(
75 ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT,
76 StoreDocument::createFromArray($document)
77 );
78 if (!$can)
79 {
80 $this->addError(
81 new Error(Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_CONDUCT_ERROR',
82 [
83 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
84 '#ERROR#' => Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR'),
85 ]
86 ))
87 );
88 continue;
89 }
90
91 $isConducted = \CCatalogDocs::conductDocument($documentId, $userId);
92 if (!$isConducted)
93 {
94 if ($APPLICATION->GetException())
95 {
96 $this->addError(
98 'DOCUMENT_CONTROLLER_CONDUCT_ERROR',
99 [
100 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
101 '#ERROR#' => htmlspecialcharsbx($APPLICATION->GetException()->GetString()),
102 ]
103 ))
104 );
105 $APPLICATION->ResetException();
106 }
107 else
108 {
109 $this->addError(
110 new Error(Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_CONDUCT_GENERAL_ERROR',
111 [
112 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
113 ]
114 ))
115 );
116 }
117 }
118 }
119
120 if (!$this->errorCollection->isEmpty())
121 {
122 return null;
123 }
124
125 return true;
126 }
127
133 public function cancelListAction(array $documentIds): ?bool
134 {
135 if (!Feature::isInventoryManagementEnabled())
136 {
137 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
138
139 return null;
140 }
141
142 if (!\Bitrix\Catalog\Component\UseStore::isUsed())
143 {
144 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_MANAGEMENT_NOT_ENABLED')));
145
146 return null;
147 }
148
149 global $APPLICATION;
150
151 $documentData = $this->getDocumentData($documentIds);
152 $userId = CurrentUser::get()->getId();
153 foreach ($documentIds as $documentId)
154 {
155 $document = $documentData[$documentId] ?? null;
156 if (!$document)
157 {
158 $this->addError(
160 'CATALOG_CONTROLLER_DOCUMENT_CANCEL_ERROR',
161 [
162 '#ERROR#' => Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_NOT_FOUND'),
163 ]
164 ))
165 );
166 continue;
167 }
168
169 $documentTitle = $document['TITLE'] ?: StoreDocumentTable::getTypeList(true)[$document['DOC_TYPE']];
170
171 $can = $this->accessController->check(
172 ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT,
173 StoreDocument::createFromArray($document)
174 );
175 if (!$can)
176 {
177 $this->addError(
178 new Error(Loc::getMessage('DOCUMENT_CONTROLLER_CANCEL_ERROR',
179 [
180 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
181 '#ERROR#' => Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR'),
182 ]
183 ))
184 );
185 continue;
186 }
187
188 $isCancelled = \CCatalogDocs::cancellationDocument($documentId, $userId);
189 if (!$isCancelled)
190 {
191 if ($APPLICATION->GetException())
192 {
193 $this->addError(
195 'DOCUMENT_CONTROLLER_CANCEL_ERROR',
196 [
197 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
198 '#ERROR#' => htmlspecialcharsbx($APPLICATION->GetException()->GetString()),
199 ]
200 ))
201 );
202 $APPLICATION->ResetException();
203 }
204 else
205 {
206 $documentTitle = $documentData[$documentId]['TITLE'] ?: StoreDocumentTable::getTypeList(true)[$documentData[$documentId]['DOC_TYPE']];
207 $this->addError(
209 'CATALOG_CONTROLLER_DOCUMENT_CANCEL_ERROR',
210 [
211 '#ERROR#' => htmlspecialcharsbx($documentTitle),
212 ]
213 ))
214 );
215 }
216 }
217 }
218
219 if (!$this->errorCollection->isEmpty())
220 {
221 return null;
222 }
223
224 return true;
225 }
226
227 private function prepareFieldsAdd($fields)
228 {
229 if (!array_key_exists('SITE_ID', $fields))
230 {
231 if (defined('SITE_ID'))
232 {
233 $fields['SITE_ID'] = SITE_ID;
234 }
235 else
236 {
237 $fields['SITE_ID'] = 's1';
238 }
239 }
240
241 if (!CurrentUser::get()->isAdmin() || !array_key_exists('CREATED_BY', $fields))
242 {
243 $fields['CREATED_BY'] = CurrentUser::get()->getId();
244 }
245
246 if (!CurrentUser::get()->isAdmin() || !array_key_exists('MODIFIED_BY', $fields))
247 {
248 $fields['MODIFIED_BY'] = CurrentUser::get()->getId();
249 }
250
251 return $fields;
252 }
253
260 public function addAction(array $fields): ?array
261 {
262 if (!Feature::isInventoryManagementEnabled())
263 {
264 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
265
266 return null;
267 }
268
269 $docType = $fields['DOC_TYPE'] ?? null;
270
271 $availableTypes = self::getAvailableRestDocumentTypes();
272 if (!isset($availableTypes[$docType]))
273 {
274 $this->addError(new Error('DOC_TYPE isn\'t available'));
275
276 return null;
277 }
278
279 if (!$this->accessController->check(ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY, StoreDocument::createFromArray($fields)))
280 {
281 $this->addError(
282 new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR'))
283 );
284
285 return null;
286 }
287
288 $fields = $this->prepareFieldsAdd($fields);
289 $addResult = CCatalogDocs::add($fields);
290 if (!$addResult)
291 {
292 global $APPLICATION;
293 if ($APPLICATION->GetException())
294 {
295 $exception = $APPLICATION->GetException();
296 $this->addError(new Error($exception->GetString()));
297 $APPLICATION->ResetException();
298
299 return null;
300 }
301 }
302
303 return ['DOCUMENT' => $this->get($addResult)];
304 }
305
313 public function fieldsAction(): array
314 {
315 return [$this->getViewFields()];
316 }
317
325 public function updateAction(int $id, array $fields): ?array
326 {
327 if (!Feature::isInventoryManagementEnabled())
328 {
329 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
330
331 return null;
332 }
333
334 if (!$this->checkDocumentAccess(ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY, $id))
335 {
336 return null;
337 }
338
339 $user = CurrentUser::get();
340 if (!array_key_exists('MODIFIED_BY', $fields) || !$user->isAdmin())
341 {
342 $fields['MODIFIED_BY'] = $user->getId();
343 }
344
345 $result = CCatalogDocs::update($id, $fields);
346 if (!$result)
347 {
348 global $APPLICATION;
349 if ($APPLICATION->GetException())
350 {
351 $exception = $APPLICATION->GetException();
352 $this->addError(new Error($exception->GetString()));
353 $APPLICATION->ResetException();
354
355 return null;
356 }
357 }
358
359 return ['DOCUMENT' => $this->get($id)];
360 }
361
367 public function deleteListAction(array $documentIds): ?bool
368 {
369 global $APPLICATION;
370
371 if (!Feature::isInventoryManagementEnabled())
372 {
373 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
374
375 return null;
376 }
377
382 $documentData = $this->getDocumentData($documentIds);
383
384 foreach ($documentIds as $documentId)
385 {
386 $exception = null;
387 $document = $documentData[(int)$documentId] ?? null;
388
389 if (!$document)
390 {
391 $this->addError(
393 'DOCUMENT_CONTROLLER_DELETE_ERROR',
394 [
395 '#DOC_TITLE#' => "#{$documentId}",
396 '#ERROR#' => Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_NOT_FOUND'),
397 ]
398 ))
399 );
400 continue;
401 }
402
403 $can = $this->accessController->check(
404 ActionDictionary::ACTION_STORE_DOCUMENT_DELETE,
405 StoreDocument::createFromArray($document)
406 );
407 if ($can)
408 {
409 \CCatalogDocs::delete($documentId);
410
411 $exception = $APPLICATION->GetException();
412 }
413 else
414 {
415 $exception = new CApplicationException(
416 Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR')
417 );
418 }
419
420 if ($exception)
421 {
422 $documentTitle = $document['TITLE'] ?: StoreDocumentTable::getTypeList(true)[$document['DOC_TYPE']];
423 if ($exception->GetID() === CCatalogDocs::DELETE_CONDUCTED_ERROR)
424 {
425 $this->addError(
427 'DOCUMENT_CONTROLLER_DELETE_CONDUCTED_ERROR',
428 [
429 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
430 ]
431 ))
432 );
433 }
434 else
435 {
436 $this->addError(
438 'DOCUMENT_CONTROLLER_DELETE_ERROR',
439 [
440 '#DOC_TITLE#' => htmlspecialcharsbx($documentTitle),
441 '#ERROR#' => htmlspecialcharsbx($exception->GetString()),
442 ]
443 ))
444 );
445 }
446
447 $APPLICATION->ResetException();
448 }
449 }
450
451 return $this->errorCollection->isEmpty() ? true : null;
452 }
453
460 public function deleteAction(int $id): ?bool
461 {
462 if (!Feature::isInventoryManagementEnabled())
463 {
464 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
465
466 return null;
467 }
468
469 if (!$this->checkDocumentAccess(ActionDictionary::ACTION_STORE_DOCUMENT_DELETE, $id))
470 {
471 return null;
472 }
473
474 $deleteResult = CCatalogDocs::delete($id);
475 if (!$deleteResult)
476 {
477 $message = Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_NOT_FOUND');
478
479 $this->addError(
480 new Error($message)
481 );
482
483 return null;
484 }
485
486 global $APPLICATION;
487 if ($exception = $APPLICATION->getException())
488 {
489 if ($exception->getID() === CCatalogDocs::DELETE_CONDUCTED_ERROR)
490 {
491 $message = Loc::getMessage(
492 'DOCUMENT_CONTROLLER_DELETE_CONDUCTED_ERROR',
493 [
494 '#DOC_TITLE#' => $id,
495 ]
496 );
497 }
498 else
499 {
500 $message = Loc::getMessage(
501 'DOCUMENT_CONTROLLER_DELETE_ERROR',
502 [
503 '#DOC_TITLE#' => $id,
504 '#ERROR#' => htmlspecialcharsbx($exception->getString()),
505 ]
506 );
507 }
508
509 $this->addError(
510 new Error($message)
511 );
512
513 $APPLICATION->ResetException();
514
515 return null;
516 }
517
518 return $deleteResult;
519 }
520
531 public function listAction(
532 PageNavigation $pageNavigation,
533 array $order = [],
534 array $filter = [],
535 array $select = []
536 ): Page
537 {
538 // set available types for REST
539 $filter = [
540 '=DOC_TYPE' => array_keys(self::getAvailableRestDocumentTypes()),
541 $filter,
542 ];
543
544 $accessFilter = $this->accessController->getEntityFilter(
545 ActionDictionary::ACTION_STORE_DOCUMENT_VIEW,
546 get_class($this->getEntityTable())
547 );
548 if ($accessFilter)
549 {
550 // combines through a new array so that the `OR` condition does not bypass the access filter.
551 $filter = [
552 $accessFilter,
553 $filter,
554 ];
555 }
556
557 return new Page('DOCUMENTS',
558 $this->getList($select, $filter, $order, $pageNavigation),
559 $this->count($filter)
560 );
561 }
562
570 public function conductAction(int $id): ?bool
571 {
572 return $this->confirmAction($id);
573 }
574
584 public function confirmAction(int $id): ?bool
585 {
586 if (!Feature::isInventoryManagementEnabled())
587 {
588 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
589
590 return null;
591 }
592
593 if (!$this->checkDocumentAccess(ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT, $id))
594 {
595 return null;
596 }
597
598 $document = StoreDocumentTable::getById($id)->fetch();
599 if (!$document)
600 {
601 $message = Loc::getMessage('CATALOG_CONTROLLER_DOCUMENT_NOT_FOUND');
602 $this->addError(
603 new Error($message)
604 );
605
606 return null;
607 }
608
609 $userId = CurrentUser::get()->getId();
610
611 if (!CCatalogDocs::conductDocument($id, $userId))
612 {
613 $error = '';
614
615 global $APPLICATION;
616
617 if ($APPLICATION->GetException())
618 {
619 $error = $APPLICATION->GetException()->GetString();
620 $APPLICATION->ResetException();
621 }
622
623 $message = Loc::getMessage(
624 'CATALOG_CONTROLLER_DOCUMENT_CONDUCT_ERROR',
625 [
626 '#ERROR#' => $error,
627 ]
628 );
629
630 $this->addError(new Error($message));
631
632 return null;
633 }
634
635 return true;
636 }
637
645 public function cancelAction(int $id): ?bool
646 {
647 return $this->unconfirmAction($id);
648 }
649
657 public function unconfirmAction(int $id): ?bool
658 {
659 if (!Feature::isInventoryManagementEnabled())
660 {
661 $this->addError(new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_INVENTORY_MANAGEMENT_ENABLED_ERROR')));
662
663 return null;
664 }
665
666 if (!$this->checkDocumentAccess(ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT, $id))
667 {
668 return null;
669 }
670
671 $userId = CurrentUser::get()->getId();
672 if (!CCatalogDocs::cancellationDocument($id, $userId))
673 {
674 $error = '';
675
676 global $APPLICATION;
677 if ($APPLICATION->GetException())
678 {
679 $error = $APPLICATION->GetException()->GetString();
680 $APPLICATION->ResetException();
681 }
682
683 $message = Loc::getMessage(
684 'CATALOG_CONTROLLER_DOCUMENT_CANCEL_ERROR',
685 [
686 '#ERROR#' => $error,
687 ]
688 );
689 $this->addError(new Error($message));
690
691 return null;
692 }
693
694 return true;
695 }
696
700 public static function getAvailableRestDocumentTypes(): array
701 {
702 $types = StoreDocumentTable::getTypeList(true);
704
705 return $types;
706 }
707
714 protected function checkPermissionEntity($name, $arguments=[])
715 {
716 $name = mb_strtolower($name);
717 if ($name === 'fields')
718 {
719 return $this->checkGetFieldsPermissionEntity();
720 }
721
722 if (in_array($name, ['conductlist', 'cancellist', 'unconfirm', 'confirm', 'conduct', 'cancel'], true))
723 {
724 return $this->checkUpdatePermissionEntity();
725 }
726
727 if ($name === 'deletelist')
728 {
729 return $this->checkDeletePermissionEntity();
730 }
731
732 return parent::checkPermissionEntity($name, $arguments);
733 }
734
738 protected function getEntityTable()
739 {
740 return new \Bitrix\Catalog\StoreDocumentTable();
741 }
742
743 protected function checkModifyPermissionEntity()
744 {
745 $r = $this->checkReadPermissionEntity();
746 if ($r->isSuccess())
747 {
748 if (!$this->accessController->check(Controller::CATALOG_STORE))
749 {
750 $message = Loc::getMessage('DOCUMENT_CONTROLLER_NO_STORE_RIGHTS_ERROR');
751 $r->addError(new Error($message));
752 }
753 }
754
755 return $r;
756 }
757
758 protected function checkReadPermissionEntity()
759 {
760 $r = new Result();
761
762 if (
763 !$this->accessController->check(Controller::CATALOG_STORE)
764 && !$this->accessController->check(Controller::CATALOG_READ)
765 )
766 {
767 $message = Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR');
768 $r->addError(new Error($message));
769 }
770
771 return $r;
772 }
773
774 private function getDocumentData(array $documentIds): array
775 {
776 $documentTitlesRes = StoreDocumentTable::getList(['select' => ['ID', 'DOC_TYPE', 'TITLE'], 'filter' => ['ID' => $documentIds]]);
777 $documentTitles = [];
778 while ($document = $documentTitlesRes->fetch())
779 {
780 $documentTitles[$document['ID']] = [
781 'ID' => $document['ID'],
782 'TITLE' => $document['TITLE'],
783 'DOC_TYPE' => $document['DOC_TYPE'],
784 ];
785 }
786
787 return $documentTitles;
788 }
789
800 private function checkDocumentAccess(string $action, int $documentId): bool
801 {
802 $can = $this->accessController->check($action, StoreDocument::createFromId($documentId));
803 if (!$can)
804 {
805 $this->addError(
806 new Error(Loc::getMessage('DOCUMENT_CONTROLLER_NO_RIGHTS_ERROR'))
807 );
808
809 return false;
810 }
811
812 return true;
813 }
814}
conductListAction(array $documentIds)
Definition document.php:35
cancelListAction(array $documentIds)
Definition document.php:133
updateAction(int $id, array $fields)
Definition document.php:325
checkPermissionEntity($name, $arguments=[])
Definition document.php:714
listAction(PageNavigation $pageNavigation, array $order=[], array $filter=[], array $select=[])
Definition document.php:531
static getTypeList(bool $description=false)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getList(array $parameters=array())
addError(Main\Error $error)
Definition error.php:22