Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
productselector.php
1<?php
2
4
40
42{
43 private ?Uploader $uploader = null;
44 private ?PendingFileCollection $pendingFileCollection = null;
45 private AccessController $accessController;
46
50 protected function init()
51 {
52 parent::init();
53
54 $this->accessController = AccessController::getCurrent();
55 }
56
57 public function configureActions()
58 {
59 return [
60 'getSelectedSku' => [
61 '+prefilters' => [
62 new ActionFilter\CloseSession(),
63 ],
64 ],
65 'getProduct' => [
66 '+prefilters' => [
67 new ActionFilter\CloseSession(),
68 ],
69 ],
70 ];
71 }
72
73 protected function getDefaultPreFilters()
74 {
75 return array_merge(
76 parent::getDefaultPreFilters(),
77 [
78 new ActionFilter\HttpMethod([ActionFilter\HttpMethod::METHOD_POST]),
79 new ActionFilter\Scope(ActionFilter\Scope::AJAX),
80 ]
81 );
82 }
83
84 protected function processBeforeAction(Action $action)
85 {
86 if ($action->getName() === 'getSkuTreeProperties')
87 {
88 return true;
89 }
90
91 if (
92 $this->accessController->check(ActionDictionary::ACTION_CATALOG_READ)
93 || $this->accessController->check(ActionDictionary::ACTION_CATALOG_VIEW)
94 )
95 {
96 return parent::processBeforeAction($action);
97 }
98
99 return false;
100 }
101
107 public function getSelectedSkuAction(int $variationId, array $options = []): ?array
108 {
109 $iterator = \CIBlockElement::GetList(
110 [],
111 [
112 'ID' => $variationId,
113 'ACTIVE' => 'Y',
114 'ACTIVE_DATE' => 'Y',
115 'CHECK_PERMISSIONS' => 'Y',
116 'MIN_PERMISSION' => 'R',
117 ],
118 false,
119 false,
120 ['ID', 'IBLOCK_ID']
121 );
122 $element = $iterator->Fetch();
123 if (!$element)
124 {
125 return null;
126 }
127 unset($iterator);
128
129 $skuRepository = ServiceContainer::getSkuRepository($element['IBLOCK_ID']);
130 if (!$skuRepository)
131 {
132 return null;
133 }
134
136 $sku = $skuRepository->getEntityById($variationId);
137
138 if (!$sku)
139 {
140 return null;
141 }
142
143 return $this->prepareResponse($sku, $options);
144 }
145
146 public function getProductIdByBarcodeAction($barcode): ?int
147 {
148 $iterator = \CIBlockElement::GetList(
149 [],
150 [
151 '=PRODUCT_BARCODE' => $barcode,
152 'ACTIVE' => 'Y',
153 'ACTIVE_DATE' => 'Y',
154 'CHECK_PERMISSIONS' => 'Y',
155 'MIN_PERMISSION' => 'R',
156 ],
157 false,
158 false,
159 ['ID']
160 );
161
162 if ($product = $iterator->Fetch())
163 {
164 return (int)$product['ID'];
165 }
166
167 return null;
168 }
169
175 public function getProductAction(int $productId, array $options = []): ?array
176 {
177 $iterator = \CIBlockElement::GetList(
178 [],
179 [
180 'ID' => $productId,
181 'ACTIVE' => 'Y',
182 'ACTIVE_DATE' => 'Y',
183 'CHECK_PERMISSIONS' => 'Y',
184 'MIN_PERMISSION' => 'R',
185 ],
186 false,
187 false,
188 ['ID', 'IBLOCK_ID', 'TYPE']
189 );
190 $element = $iterator->Fetch();
191 if (!$element)
192 {
193 return null;
194 }
195
196 if ((int)$element['TYPE'] === ProductTable::TYPE_OFFER)
197 {
198 $sku = $this->loadSkuById((int)$element['IBLOCK_ID'], (int)$element['ID']);
199 }
200 else
201 {
202 $sku = $this->loadFirstSkuForProduct((int)$element['IBLOCK_ID'], (int)$element['ID']);
203 }
204
205 if (!$sku)
206 {
207 return null;
208 }
209
210 $options['resetSku'] = true;
211
212 return $this->prepareResponse($sku, $options);
213 }
214
215 private function loadSkuById(int $iblockId, int $skuId): ?BaseSku
216 {
217 $skuRepository = ServiceContainer::getSkuRepository($iblockId);
218 if (!$skuRepository)
219 {
220 return null;
221 }
222
223 return $skuRepository->getEntityById($skuId);
224 }
225
231 private function loadFirstSkuForProduct(int $iblockId, int $productId): ?BaseSku
232 {
233 $productRepository = ServiceContainer::getProductRepository($iblockId);
234 if (!$productRepository)
235 {
236 return null;
237 }
238
240 $product = $productRepository->getEntityById($productId);
241 if (!$product)
242 {
243 return null;
244 }
245
246 return $product->getSkuCollection()->getFirst();
247 }
248
249 private function prepareResponse(BaseSku $sku, array $options = []): ?array
250 {
251 $builder = new BasketBuilder();
252 $basketItem = $builder->createItem();
253 $basketItem->setSku($sku);
254
255 $priceId = (int)($options['priceId'] ?? 0);
256 if ($priceId > 0)
257 {
258 $basketItem->setPriceGroupId($priceId);
259 }
260
261 if (!empty($options['urlBuilder']))
262 {
263 $basketItem->setDetailUrlManagerType($options['urlBuilder']);
264 }
265
266 $formFields = $basketItem->getFields();
267
268 $price = null;
269 $basePrice = null;
270 $currency = '';
271 $isCustomized = 'N';
272 if ($basketItem->getPriceItem() && $basketItem->getPriceItem()->hasPrice())
273 {
274 $basePrice = $basketItem->getPriceItem()->getPrice();
275 $price = $basketItem->getPriceItem()->getPrice();
276 $currency = $basketItem->getPriceItem()->getCurrency();
277 if (!empty($options['currency']) && $options['currency'] !== $currency)
278 {
279 $basePrice = \CCurrencyRates::ConvertCurrency($price, $currency, $options['currency']);
280 $currencyFormat = \CCurrencyLang::GetCurrencyFormat($currency);
281 $decimals = $currencyFormat['DECIMALS'] ?? 2;
282 $basePrice = round($basePrice, $decimals);
283 $price = \CCurrencyLang::CurrencyFormat($basePrice, $currency, false);
284 $isCustomized = 'Y';
285 $currency = $options['currency'];
286 }
287 }
288
290 $barcode = $sku->getBarcodeCollection()->getFirst();
291
292 $purchasingPrice = $sku->getField('PURCHASING_PRICE');
293 $purchasingCurrency = $sku->getField('PURCHASING_CURRENCY');
294 if ($purchasingCurrency !== $options['currency'])
295 {
296 $purchasingPrice = \CCurrencyRates::ConvertCurrency(
297 $purchasingPrice,
298 $purchasingCurrency,
299 $options['currency']
300 );
301 $purchasingCurrency = $options['currency'];
302 }
303
304 $productProps = $this->getProductProperties($sku);
305
306 $fields = [
307 'TYPE' => $sku->getType(),
308 'ID' => $formFields['skuId'],
309 'SKU_ID' => $formFields['skuId'],
310 'PRODUCT_ID' => $formFields['productId'],
311 'CUSTOMIZED' => $isCustomized,
312 'NAME' => $formFields['name'],
313 'MEASURE_CODE' => (string)$formFields['measureCode'],
314 'MEASURE_RATIO' => $formFields['measureRatio'],
315 'MEASURE_NAME' => $formFields['measureName'],
316 'PURCHASING_PRICE' => $purchasingPrice,
317 'PURCHASING_CURRENCY' => $purchasingCurrency,
318 'BARCODE' => $barcode ? $barcode->getBarcode() : '',
319 'COMMON_STORE_AMOUNT' => $sku->getField('QUANTITY'),
320 'COMMON_STORE_RESERVED' => $sku->getField('QUANTITY_RESERVED'),
321 'PRICE' => $price,
322 'BASE_PRICE' => $basePrice,
323 'CURRENCY_ID' => $currency,
324 'PROPERTIES' => $formFields['properties'],
325 'VAT_ID' => $formFields['taxId'],
326 'VAT_INCLUDED' => $formFields['taxIncluded'],
327 'BRANDS' => $this->getProductBrand($sku),
328 'WEIGHT' => $formFields['weight'],
329 'DIMENSIONS' => $formFields['dimensions'],
330 'PRODUCT_PROPERTIES' => $productProps,
331 ];
332
333 $fields = array_merge($fields, $productProps);
334
335 $previewImage = $sku->getFrontImageCollection()->getFrontImage();
336 if ($previewImage)
337 {
338 $fields['PREVIEW_PICTURE'] = [
339 'ID' => $previewImage->getId(),
340 'SRC' => Tools::getImageSrc($previewImage->getFileStructure(), true),
341 'WIDTH' => $previewImage->getField('WIDTH'),
342 'HEIGHT' => $previewImage->getField('HEIGHT'),
343 ];
344 }
345
346 $formResult = $basketItem->getResult();
347 $response = [
348 'skuId' => $formFields['skuId'],
349 'productId' => $formFields['productId'],
350 'image' => $formResult['image'],
351 'detailUrl' => $formResult['detailUrl'],
352 ];
353
354 $fields['DETAIL_URL'] = $formResult['detailUrl'];
355 $fields['IMAGE_INFO'] = $formResult['image'];
356 $fields['SKU_TREE'] = $formResult['skuTree'];
357 if (isset($options['resetSku']))
358 {
359 $response['skuTree'] =
360 ($formResult['skuTree'] !== '')
361 ? Json::decode($formResult['skuTree'])
362 : ''
363 ;
364 }
365
366 $response['fields'] = $fields;
367 $response['formFields'] = $formFields;
368
369 return $response;
370 }
371
372 private function getProductIdByBarcode(string $barcode): ?int
373 {
374 $barcodeRaw = StoreBarcodeTable::getList([
375 'filter' => ['=BARCODE' => $barcode],
376 'select' => ['PRODUCT_ID'],
377 'limit' => 1
378 ]);
379
380 if ($barcode = $barcodeRaw->fetch())
381 {
382 return $barcode['PRODUCT_ID'];
383 }
384
385 return null;
386 }
387
388 private function getProductBrand($sku): ?array
389 {
390 $product = $sku->getParent();
391 if (!$product)
392 {
393 return null;
394 }
395
396 $brand = $product->getPropertyCollection()->findByCode('BRAND_FOR_FACEBOOK');
397 if (!$brand)
398 {
399 return null;
400 }
401
402 $userType = \CIBlockProperty::GetUserType($brand->getUserType());
403 $userTypeMethod = $userType['GetUIEntityEditorProperty'];
404 $propertySettings = $brand->getSettings();
405 $propertyValues = $brand->getPropertyValueCollection()->getValues();
406 $description = $userTypeMethod($propertySettings, $propertyValues);
407 $propertyBrandItems = $description['data']['items'];
408
409 $selectedBrandItems = [];
410
411 foreach ($propertyBrandItems as $propertyBrandItem)
412 {
413 if (in_array($propertyBrandItem['VALUE'], $propertyValues, true))
414 {
415 $selectedBrandItems[] = $propertyBrandItem;
416 }
417 }
418
419 return $selectedBrandItems;
420 }
421
422 private function getProductProperties(BaseSku $sku): array
423 {
425 $emptyProps = [];
426 foreach ($columns as $columnName)
427 {
428 $emptyProps[$columnName] = '';
429 }
430
431 $productId = $sku->getParent()->getId();
432 $productIblockId = $sku->getIblockInfo()->getProductIblockId();
433 $productProps = PropertyProduct::getIblockProperties($productIblockId, $productId);
434
435 $skuId = $sku->getId();
436 $skuIblockId = $sku->getIblockId();
437 $skuProps = [];
438 if ($skuId && $skuIblockId)
439 {
440 $skuProps = PropertyProduct::getSkuProperties($skuIblockId, $skuId);
441 }
442
443 return array_merge($emptyProps, $productProps, $skuProps);
444 }
445
446 public function createProductAction(array $fields): ?array
447 {
448 $iblockId = (int)$fields['IBLOCK_ID'];
449 if (
450 !\CIBlockSectionRights::UserHasRightTo($iblockId, 0, 'section_element_bind')
451 || !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_ADD)
452 )
453 {
454 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_CREATION')));
455
456 return null;
457 }
458
459 $productFactory = ServiceContainer::getProductFactory($iblockId);
460 if (!$productFactory)
461 {
462 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
463
464 return null;
465 }
466
467 $skuRepository = ServiceContainer::getSkuRepository($iblockId);
468 $type = $skuRepository ? ProductTable::TYPE_SKU : ProductTable::TYPE_PRODUCT;
469
471 $product = $productFactory
472 ->createEntity()
473 ->setType($type)
474 ;
475
476 $sku =
477 $skuRepository
478 ? $product->getSkuCollection()->create()
479 : $product->getSkuCollection()->getFirst()
480 ;
481
482 if (!empty($fields['BARCODE']))
483 {
484 $productId = $this->getProductIdByBarcode($fields['BARCODE']);
485
486 if ($productId !== null)
487 {
488 $elementRaw = ElementTable::getList([
489 'filter' => ['=ID' => $productId],
490 'select' => ['NAME'],
491 'limit' => 1
492 ]);
493
494 $name = '';
495 if ($element = $elementRaw->fetch())
496 {
497 $name = $element['NAME'];
498 }
499
500 $this->addError(
501 new Error(
503 'PRODUCT_SELECTOR_ERROR_BARCODE_EXIST',
504 [
505 '#BARCODE#' => htmlspecialcharsbx($fields['BARCODE']),
506 '#PRODUCT_NAME#' => htmlspecialcharsbx($name),
507 ]
508 )
509 )
510 );
511
512 return null;
513 }
514
515 if ($sku)
516 {
517 $sku->getBarcodeCollection()->setSimpleBarcodeValue($fields['BARCODE']);
518 }
519 }
520
521 if (empty($fields['CODE']))
522 {
523 $productName = $fields['NAME'] ?? '';
524
525 if ($productName !== '')
526 {
527 $fields['CODE'] = (new \CIBlockElement())->generateMnemonicCode($productName, $iblockId);
528 }
529 }
530
531 if (isset($fields['CODE']) && \CIBlock::isUniqueElementCode($iblockId))
532 {
533 $elementRaw = ElementTable::getList([
534 'filter' => ['=CODE' => $fields['CODE']],
535 'select' => ['ID'],
536 'limit' => 1
537 ]);
538
539 if ($elementRaw->fetch())
540 {
541 $fields['CODE'] = uniqid($fields['CODE'] . '_', false);
542 }
543 }
544
545 if (!empty($fields['MEASURE_CODE']))
546 {
547 $fields['MEASURE'] = $this->getMeasureIdByCode($fields['MEASURE_CODE']);
548 }
549 else
550 {
551 $measure = MeasureTable::getRow([
552 'select' => ['ID'],
553 'filter' => ['=IS_DEFAULT' => 'Y'],
554 ]);
555 if ($measure)
556 {
557 $fields['MEASURE'] = $measure['ID'];
558 }
559 }
560
561 if (!$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT))
562 {
563 unset($fields['PRICE']);
564 }
565
566 $product->setFields($fields);
567 if ($fields['MEASURE'] > 0)
568 {
569 $sku->setField('MEASURE', $fields['MEASURE']);
570 }
571 if (Option::get('catalog', 'default_product_vat_included') === 'Y')
572 {
573 $sku->setField('VAT_INCLUDED', ProductTable::STATUS_YES);
574 }
575
576 if (isset($fields['PRICE']) && $fields['PRICE'] >= 0)
577 {
578 $basePrice = [
579 'PRICE' => (float)$fields['PRICE'],
580 ];
581
582 if (isset($fields['CURRENCY']))
583 {
584 $basePrice['CURRENCY'] = $fields['CURRENCY'];
585 }
586
587 if ($sku)
588 {
589 $sku
590 ->getPriceCollection()
591 ->setValues([
592 'BASE' => $basePrice
593 ])
594 ;
595 }
596 }
597
598 $result = $product->save();
599
600 if (!$result->isSuccess())
601 {
602 $this->addErrors($result->getErrors());
603
604 return null;
605 }
606
607 return [
608 'id' => $sku->getId(),
609 ];
610 }
611
612 public function updateSkuAction(int $id, array $updateFields, array $oldFields = []): ?array
613 {
614 if (empty($updateFields) || $id <= 0)
615 {
616 return null;
617 }
618
619 $repositoryFacade = ServiceContainer::getRepositoryFacade();
620 if (!$repositoryFacade)
621 {
622 return null;
623 }
624
625 $sku = $repositoryFacade->loadVariation($id);
626 if (!$sku)
627 {
628 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_SKU_NOT_EXIST')));
629 return null;
630 }
632 $parentProduct = $sku->getParent();
633
634 if (
635 !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_EDIT)
636 || !\CIBlockElementRights::UserHasRightTo($parentProduct->getIblockId(), $parentProduct->getId(), 'element_edit')
637 )
638 {
639 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_UPDATE')));
640
641 return null;
642 }
643
644 if (
645 !$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT)
646 || !\CIBlockElementRights::UserHasRightTo($parentProduct->getIblockId(), $parentProduct->getId(), 'element_edit_price')
647 )
648 {
649 unset($updateFields['PRICES']);
650 }
651
652 $result = $this->saveSku($sku, $updateFields, $oldFields);
653 if (!$result->isSuccess())
654 {
655 $this->addErrors($result->getErrors());
656
657 return null;
658 }
659
660 return [
661 'id' => $sku->getId(),
662 ];
663 }
664
665 public function updateProductAction(int $id, int $iblockId, array $updateFields): ?array
666 {
667 return $this->updateSkuAction($id, $updateFields);
668 }
669
670 public function saveMorePhotoAction(int $productId, int $variationId, int $iblockId, array $imageValues): ?array
671 {
672 if (
673 !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_EDIT)
674 || !\CIBlockElementRights::UserHasRightTo($iblockId, $productId, 'element_edit')
675 )
676 {
677 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_UPDATE')));
678
679 return null;
680 }
681
682 $productRepository = ServiceContainer::getProductRepository($iblockId);
683 if (!$productRepository)
684 {
685 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
686
687 return null;
688 }
689
691 $product = $productRepository->getEntityById($productId);
692 if (!$product)
693 {
694 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_PRODUCT_NOT_EXIST')));
695
696 return null;
697 }
698
699 // use the head product - in case when a simple product was saved but it became sku product
701 if ($productId === $variationId)
702 {
703 $entity = $product;
704 }
705 else
706 {
707 $entity = $product->getSkuCollection()->findById($variationId);
708 }
709
710 if (!$entity)
711 {
712 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_SKU_NOT_EXIST')));
713
714 return null;
715 }
716
717 $values = [];
718
719 $property = $entity->getPropertyCollection()->findByCode(MorePhotoImage::CODE);
720 foreach ($imageValues as $key => $newImage)
721 {
722 $newImage = $this->prepareMorePhotoValue($newImage, $entity);
723 if (empty($newImage))
724 {
725 continue;
726 }
727
728 if (!$property || !$property->isActive())
729 {
730 if (empty($previewPicture))
731 {
732 $previewPicture = $newImage;
733 continue;
734 }
735
736 $detailPicture = $newImage;
737 break;
738 }
739
740 if ($key === DetailImage::CODE)
741 {
742 $detailPicture = $newImage;
743 }
744 elseif ($key === PreviewImage::CODE)
745 {
746 $previewPicture = $newImage;
747 }
748 else
749 {
750 $values[$key] = $newImage;
751 }
752 }
753
754 $entity->getImageCollection()->setValues($values);
755
756 if (isset($detailPicture) && is_array($detailPicture))
757 {
758 $entity->getImageCollection()->getDetailImage()->setFileStructure($detailPicture);
759 }
760
761 if (isset($previewPicture) && is_array($previewPicture))
762 {
763 $entity->getImageCollection()->getPreviewImage()->setFileStructure($previewPicture);
764 }
765
766 $result = $product->save();
767 if (!$result->isSuccess())
768 {
769 $this->addErrors($result->getErrors());
770
771 return [];
772 }
773
774 $this->commitPendingCollection();
775
776 return (new ImageInput($entity))->getFormattedField();
777 }
778
779 private function prepareMorePhotoValue($imageValue, BaseIblockElementEntity $entity)
780 {
781 if (empty($imageValue))
782 {
783 return null;
784 }
785
786 if (!empty($imageValue['token']))
787 {
788 return $this->prepareMorePhotoValueByToken($imageValue, $entity);
789 }
790
791 if (is_string($imageValue))
792 {
793 try
794 {
795 static $signer = null;
796 if ($signer === null)
797 {
798 $signer = new Signer;
799 }
800
801 return (int)$signer->unsign($imageValue, ImageInput::FILE_ID_SALT);
802 }
803 catch (BadSignatureException $e)
804 {
805 return null;
806 }
807 }
808
809 if (
810 is_array($imageValue)
811 && !empty($imageValue['data'])
812 && is_array($imageValue['data'])
813 )
814 {
815 return \CIBlock::makeFileArray($imageValue['data']);
816 }
817
818 if (
819 is_array($imageValue)
820 && !empty($imageValue['base64Encoded'])
821 && is_array($imageValue['base64Encoded'])
822 )
823 {
824 $content = (string)($imageValue['base64Encoded']['content'] ?? '');
825 if ($content !== '')
826 {
827 $fileName = (string)($imageValue['base64Encoded']['filename'] ?? '');
828 $fileInfo = \CRestUtil::saveFile($content, $fileName);
829
830 return $fileInfo ?: null;
831 }
832 }
833
834 return null;
835 }
836
837 private function prepareMorePhotoValueByToken(array $image, BaseIblockElementEntity $entity): ?array
838 {
839 $token = $image['token'] ?? null;
840 if (empty($token))
841 {
842 return null;
843 }
844
845 $fileId = $this->getFileIdByToken($token, $entity);
846 if ($fileId)
847 {
848 return \CIBlock::makeFileArray($fileId, false, null, ['allow_file_id' => true]);
849 }
850
851 return null;
852 }
853
854 private function getFileIdByToken(string $token, BaseIblockElementEntity $entity): ?int
855 {
856 $uploader = $this->getUploader($entity);
857 $pendingFile = $uploader->getPendingFiles([$token])->get($token);
858
859 if ($pendingFile && $pendingFile->isValid())
860 {
861 $this->addPendingFileToCollection($pendingFile);
862
863 return $pendingFile->getFileId();
864 }
865
866 return null;
867 }
868
869 private function getUploader(BaseIblockElementEntity $entity): Uploader
870 {
871 if ($this->uploader === null)
872 {
873 $fileController = new ProductController([
874 'productId' => $entity->getId(),
875 ]);
876
877 $this->uploader = (new Uploader($fileController));
878 }
879
880 return $this->uploader;
881 }
882
883 private function addPendingFileToCollection(PendingFile $pendingFile): void
884 {
885 $this->getPendingFilesCollection()->add($pendingFile);
886 }
887
888 private function commitPendingCollection(): void
889 {
890 $this->getPendingFilesCollection()->makePersistent();
891 }
892
893 private function getPendingFilesCollection(): PendingFileCollection
894 {
895 if ($this->pendingFileCollection === null)
896 {
897 $this->pendingFileCollection = new PendingFileCollection();
898 }
899
900 return $this->pendingFileCollection;
901 }
902
903 private function saveSku(BaseSku $sku, array $fields = [], array $oldFields = []): Result
904 {
905 if ($sku->isNew() && empty($fields['CODE']))
906 {
907 $productName = $fields['NAME'] ?? '';
908
909 if ($productName !== '')
910 {
911 $fields['CODE'] = $this->prepareProductCode($productName);
912 }
913 }
914
915 if (!empty($fields['MEASURE_CODE']))
916 {
917 $fields['MEASURE'] = $this->getMeasureIdByCode($fields['MEASURE_CODE']);
918 }
919
920 $sectionId = $fields['IBLOCK_SECTION_ID'] ?? null;
921 unset($fields['IBLOCK_SECTION_ID']);
922
923 $sku->setFields($fields);
924
925 if (!empty($fields['PRICES']) && is_array($fields['PRICES']))
926 {
927 $priceCollection = $sku->getPriceCollection();
928 foreach ($fields['PRICES'] as $groupId => $price)
929 {
930 $priceCollection->setValues([
931 $groupId => [
932 'PRICE' => (float)$price['PRICE'],
933 'CURRENCY' => $price['CURRENCY'] ?? null,
934 ],
935 ]);
936 }
937 }
938
939 if (isset($fields['BARCODE']))
940 {
941 $skuId = $this->getProductIdByBarcode($fields['BARCODE']);
942 if ($skuId !== null && $sku->getId() !== $skuId)
943 {
944 $result = new Result();
945
946 $elementRaw = ElementTable::getList([
947 'filter' => ['=ID' => $skuId],
948 'select' => ['NAME'],
949 'limit' => 1
950 ]);
951
952 $name = '';
953 if ($element = $elementRaw->fetch())
954 {
955 $name = $element['NAME'];
956 }
957
958 $result->addError(
959 new Error(
961 'PRODUCT_SELECTOR_ERROR_BARCODE_EXIST',
962 [
963 '#BARCODE#' => htmlspecialcharsbx($fields['BARCODE']),
964 '#PRODUCT_NAME#' => htmlspecialcharsbx($name),
965 ]
966 )
967 )
968 );
969
970 return $result;
971 }
972
973 $updateBarcodeItem = null;
974 $barcodeCollection = $sku->getBarcodeCollection();
975 if (isset($oldFields['BARCODE']))
976 {
977 $updateBarcodeItem = $barcodeCollection->getItemByBarcode($oldFields['BARCODE']);
978 }
979
980 if ($updateBarcodeItem)
981 {
982 if (empty($fields['BARCODE']))
983 {
984 $barcodeCollection->remove($updateBarcodeItem);
985 }
986 else
987 {
988 $updateBarcodeItem->setBarcode($fields['BARCODE']);
989 }
990 }
991 else
992 {
993 $barcodeItem =
994 $barcodeCollection
995 ->create()
996 ->setBarcode($fields['BARCODE'])
997 ;
998
999 $barcodeCollection->add($barcodeItem);
1000 }
1001 }
1002
1004 $parentProduct = $sku->getParent();
1005
1006 if (isset($fields['BRANDS']) && is_array($fields['BRANDS']))
1007 {
1008 $parentProduct->getPropertyCollection()->setValues(['BRAND_FOR_FACEBOOK' => $fields['BRANDS']]);
1009 }
1010
1011 if (isset($sectionId))
1012 {
1013 $parentProduct->setField('IBLOCK_SECTION_ID', $sectionId);
1014 }
1015
1016 if (
1017 isset($fields['NAME'])
1018 && $parentProduct->getSkuCollection()->count() === 1
1019 )
1020 {
1021 $this->changeProductName($parentProduct, $fields['NAME']);
1022 }
1023
1024 return $parentProduct->save();
1025 }
1026
1027 private function changeProductName(BaseProduct $parentProduct, string $newName): void
1028 {
1029 $skuTreeEntity = ServiceContainer::make('sku.tree', [
1030 'iblockId' => $parentProduct->getIblockId(),
1031 ]);
1032 $skuTree = $skuTreeEntity->load([$parentProduct->getId()]);
1033 if (empty($skuTree))
1034 {
1035 $parentProduct->setField('NAME', $newName);
1036
1037 return;
1038 }
1039
1040 $skuTreeElement = reset($skuTree);
1041 $existingValues = $skuTreeElement['EXISTING_VALUES'] ?? null;
1042 if (!$existingValues)
1043 {
1044 $parentProduct->setField('NAME', $newName);
1045
1046 return;
1047 }
1048
1049 $hasFilledProperty = false;
1050 foreach ($existingValues as $existingValue)
1051 {
1052 $hasFilledProperty = $existingValue[0] !== 0;
1053 if ($hasFilledProperty)
1054 {
1055 break;
1056 }
1057 }
1058 if (!$hasFilledProperty)
1059 {
1060 $parentProduct->setField('NAME', $newName);
1061 }
1062 }
1063
1064 private function getMeasureIdByCode(string $code): ?int
1065 {
1066 $measure = MeasureTable::getRow([
1067 'select' => ['ID'],
1068 'filter' => ['=CODE' => $code],
1069 ]);
1070 if ($measure)
1071 {
1072 return (int) $measure['ID'];
1073 }
1074
1075 return null;
1076 }
1077
1078 private function getMeasureCodeById(string $id): ?string
1079 {
1080 $measure = MeasureTable::getRow([
1081 'select' => ['CODE'],
1082 'filter' => ['=ID' => $id],
1083 ]);
1084
1085 return $measure['CODE'] ?? null;
1086 }
1087
1088 private function prepareProductCode($name): string
1089 {
1090 return mb_strtolower(\CUtil::translit(
1091 $name,
1092 LANGUAGE_ID,
1093 [
1094 'replace_space' => '_',
1095 'replace_other' => '',
1096 ]
1097 )).'_'.random_int(0, 1000);
1098 }
1099
1100 public function getEmptyInputImageAction(int $iblockId): ?array
1101 {
1102 $productFactory = ServiceContainer::getProductFactory($iblockId);
1103 if (!$productFactory)
1104 {
1105 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
1106
1107 return null;
1108 }
1109
1110 $imageField = new ImageInput();
1111
1112 return $imageField->getFormattedField();
1113 }
1114
1115 public function getFileInputAction(int $iblockId, int $skuId = null): ?Response\Component
1116 {
1117 $productFactory = ServiceContainer::getProductFactory($iblockId);
1118 if (!$productFactory)
1119 {
1120 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
1121
1122 return null;
1123 }
1124
1125 $repositoryFacade = ServiceContainer::getRepositoryFacade();
1126
1127 $sku = null;
1128 if ($repositoryFacade && $skuId !== null)
1129 {
1130 $sku = $repositoryFacade->loadVariation($skuId);
1131 }
1132
1133 if ($sku === null)
1134 {
1135 $sku = $productFactory->createEntity();
1136 }
1137
1138 $imageField = new ImageInput($sku);
1139 $imageField->disableAutoSaving();
1140
1141 return $imageField->getComponentResponse();
1142 }
1143
1144 public function getSkuTreePropertiesAction(int $iblockId): array
1145 {
1146 $skuTree = ServiceContainer::make('sku.tree', [
1147 'iblockId' => $iblockId,
1148 ]);
1149
1150 if ($skuTree)
1151 {
1152 return $skuTree->getTreeProperties();
1153 }
1154
1155 return [];
1156 }
1157
1158 public function getSkuSelectorItemAction(int $id, array $options): ?array
1159 {
1160 if (!Loader::includeModule('ui'))
1161 {
1162 return null;
1163 }
1164
1165 $items = [
1166 ['product', $id]
1167 ];
1168 $dialogOptions = [
1169 [
1170 'id' => 'product',
1171 'options' => $options,
1172 ],
1173 ];
1174 $selectedItems = Dialog::getSelectedItems($items, $dialogOptions)->toArray();
1175 if (!isset($selectedItems[0]))
1176 {
1177 return null;
1178 }
1179
1180 $item = $selectedItems[0];
1181 if ($item['hidden'] === true)
1182 {
1183 return null;
1184 }
1185
1186 return $item;
1187 }
1188
1189 public function isInstalledMobileAppAction(): bool
1190 {
1191 return (bool)\CUserOptions::GetOption('mobile', 'iOsLastActivityDate')
1192 || (bool)\CUserOptions::GetOption('mobile', 'AndroidLastActivityDate')
1193 ;
1194 }
1195}
getFileInputAction(int $iblockId, int $skuId=null)
getProductAction(int $productId, array $options=[])
getSkuSelectorItemAction(int $id, array $options)
updateProductAction(int $id, int $iblockId, array $updateFields)
static getIblockProperties(int $iblockId, int $productId, array $filter=[])
static getSkuProperties(int $iblockId, int $skuId, array $filter=[])
static getImageSrc(array $image, $safe=true)
Definition tools.php:163
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getList(array $parameters=array())
getPendingFiles(array $tempFileIds)
Definition Uploader.php:358