1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
productselector.php
См. документацию.
1<?php
2
3namespace Bitrix\Catalog\Controller;
4
5use Bitrix\Main\Config\Option;
6use Bitrix\Catalog\Access\AccessController;
7use Bitrix\Catalog\Access\ActionDictionary;
8use Bitrix\Catalog\Component\ImageInput;
9use Bitrix\Catalog\MeasureTable;
10use Bitrix\Catalog\ProductTable;
11use Bitrix\Catalog\StoreBarcodeTable;
12use Bitrix\Catalog\UI\PropertyProduct;
13use Bitrix\Catalog\v2\Barcode\Barcode;
14use Bitrix\Catalog\v2\BaseIblockElementEntity;
15use Bitrix\Catalog\v2\Image\DetailImage;
16use Bitrix\Catalog\v2\Image\MorePhotoImage;
17use Bitrix\Catalog\v2\Image\PreviewImage;
18use Bitrix\Catalog\v2\Integration\JS\ProductForm\BasketBuilder;
19use Bitrix\Catalog\UI\FileUploader\ProductController;
20use Bitrix\Catalog\v2\IoC\ServiceContainer;
21use Bitrix\Catalog\v2\Product\BaseProduct;
22use Bitrix\Catalog\v2\Sku\BaseSku;
23use Bitrix\Iblock\Component\Tools;
24use Bitrix\Iblock\ElementTable;
25use Bitrix\Main\Engine\Action;
26use Bitrix\Main\Engine\ActionFilter;
27use Bitrix\Main\Engine\JsonController;
28use Bitrix\Main\Engine\Response;
29use Bitrix\Main\Error;
30use Bitrix\Main\Localization\Loc;
31use Bitrix\Main\Result;
32use Bitrix\Main\Security\Sign\BadSignatureException;
33use Bitrix\Main\Security\Sign\Signer;
34use Bitrix\Main\Web\Json;
35use Bitrix\Main\Loader;
36use Bitrix\UI\EntitySelector\Dialog;
37use Bitrix\UI\FileUploader\PendingFile;
38use Bitrix\UI\FileUploader\PendingFileCollection;
39use Bitrix\UI\FileUploader\Uploader;
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' => [
63 ],
64 ],
65 'getProduct' => [
66 '+prefilters' => [
68 ],
69 ],
70 ];
71 }
72
73 protected function getDefaultPreFilters()
74 {
75 return array_merge(
76 parent::getDefaultPreFilters(),
77 [
80 ]
81 );
82 }
83
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([$this, 'isActiveSku']);
247 }
248
255 public function isActiveSku(BaseSku $sku): bool
256 {
257 return $sku->isActive();
258 }
259
260 private function prepareResponse(BaseSku $sku, array $options = []): ?array
261 {
262 $builder = new BasketBuilder();
263 $basketItem = $builder->createItem();
264 $basketItem->setSku($sku);
265
266 $priceId = (int)($options['priceId'] ?? 0);
267 if ($priceId > 0)
268 {
269 $basketItem->setPriceGroupId($priceId);
270 }
271
272 if (!empty($options['urlBuilder']))
273 {
274 $basketItem->setDetailUrlManagerType($options['urlBuilder']);
275 }
276
277 $formFields = $basketItem->getFields();
278
279 $price = null;
280 $basePrice = null;
281 $currency = '';
282 $isCustomized = 'N';
283 if ($basketItem->getPriceItem() && $basketItem->getPriceItem()->hasPrice())
284 {
285 $basePrice = $basketItem->getPriceItem()->getPrice();
286 $price = $basketItem->getPriceItem()->getPrice();
287 $currency = $basketItem->getPriceItem()->getCurrency();
288 if (!empty($options['currency']) && $options['currency'] !== $currency)
289 {
290 $basePrice = \CCurrencyRates::ConvertCurrency($price, $currency, $options['currency']);
291 $currencyFormat = \CCurrencyLang::GetCurrencyFormat($options['currency']);
292 $decimals = $currencyFormat['DECIMALS'] ?? 2;
293 $basePrice = round($basePrice, $decimals);
294 $price = \CCurrencyLang::CurrencyFormat($basePrice, $options['currency'], false);
295 $isCustomized = 'Y';
296 $currency = $options['currency'];
297 }
298 }
299
301 $barcode = $sku->getBarcodeCollection()->getFirst();
302
303 $purchasingPrice = $sku->getField('PURCHASING_PRICE');
304 $purchasingCurrency = $sku->getField('PURCHASING_CURRENCY');
305 if ($purchasingCurrency !== $options['currency'])
306 {
307 $purchasingPrice = \CCurrencyRates::ConvertCurrency(
308 $purchasingPrice,
309 $purchasingCurrency,
310 $options['currency']
311 );
312 $purchasingCurrency = $options['currency'];
313 }
314
315 $productProps = $this->getProductProperties($sku);
316
317 $fields = [
318 'TYPE' => $sku->getType(),
319 'ID' => $formFields['skuId'],
320 'SKU_ID' => $formFields['skuId'],
321 'PRODUCT_ID' => $formFields['productId'],
322 'CUSTOMIZED' => $isCustomized,
323 'NAME' => $formFields['name'],
324 'MEASURE_CODE' => (string)$formFields['measureCode'],
325 'MEASURE_RATIO' => $formFields['measureRatio'],
326 'MEASURE_NAME' => $formFields['measureName'],
327 'PURCHASING_PRICE' => $purchasingPrice,
328 'PURCHASING_CURRENCY' => $purchasingCurrency,
329 'BARCODE' => $barcode ? $barcode->getBarcode() : '',
330 'COMMON_STORE_AMOUNT' => $sku->getField('QUANTITY'),
331 'COMMON_STORE_RESERVED' => $sku->getField('QUANTITY_RESERVED'),
332 'PRICE' => $price,
333 'BASE_PRICE' => $basePrice,
334 'CURRENCY_ID' => $currency,
335 'PROPERTIES' => $formFields['properties'],
336 'VAT_ID' => $formFields['taxId'],
337 'VAT_INCLUDED' => $formFields['taxIncluded'],
338 'TAX_RATE' => $formFields['taxRate'],
339 'TAX_RATE_FORMATTED' => $this->formatTaxRate($formFields['taxRate']),
340 'TAX_INCLUDED' => $formFields['taxIncluded'],
341 'TAX_INCLUDED_FORMATTED' => $this->formatTaxIncluded($formFields['taxIncluded']),
342 'BRANDS' => $this->getProductBrand($sku),
343 'WEIGHT' => $formFields['weight'],
344 'DIMENSIONS' => $formFields['dimensions'],
345 'PRODUCT_PROPERTIES' => $productProps,
346 ];
347
348 $fields = array_merge($fields, $productProps);
349
350 $previewImage = $sku->getFrontImageCollection()->getFrontImage();
351 if ($previewImage)
352 {
353 $fields['PREVIEW_PICTURE'] = [
354 'ID' => $previewImage->getId(),
355 'SRC' => Tools::getImageSrc($previewImage->getFileStructure(), true),
356 'WIDTH' => $previewImage->getField('WIDTH'),
357 'HEIGHT' => $previewImage->getField('HEIGHT'),
358 ];
359 }
360
361 $formResult = $basketItem->getResult();
362 $response = [
363 'skuId' => $formFields['skuId'],
364 'productId' => $formFields['productId'],
365 'image' => $formResult['image'],
366 'detailUrl' => $formResult['detailUrl'],
367 ];
368
369 $fields['DETAIL_URL'] = $formResult['detailUrl'];
370 $fields['IMAGE_INFO'] = $formResult['image'];
371 $fields['SKU_TREE'] = $formResult['skuTree'];
372 if (isset($options['resetSku']))
373 {
374 $response['skuTree'] =
375 ($formResult['skuTree'] !== '')
376 ? Json::decode($formResult['skuTree'])
377 : ''
378 ;
379 }
380
381 $response['fields'] = $fields;
382 $response['formFields'] = $formFields;
383
384 return $response;
385 }
386
387 private function formatTaxRate(?float $rate): string
388 {
389 if ($rate === null)
390 {
391 return Loc::getMessage('PRODUCT_SELECTOR_PRODUCT_NOT_TAX');
392 }
393
394 return $rate . ' %';
395 }
396
397 private function formatTaxIncluded(string $taxIncluded): string
398 {
399 return ($taxIncluded === 'Y')
400 ? Loc::getMessage('PRODUCT_SELECTOR_PRODUCT_TAX_INCLUDED')
401 : Loc::getMessage('PRODUCT_SELECTOR_PRODUCT_TAX_NOT_INCLUDED');
402 }
403
404 private function getProductIdByBarcode(string $barcode): ?int
405 {
406 $barcodeRaw = StoreBarcodeTable::getList([
407 'filter' => ['=BARCODE' => $barcode],
408 'select' => ['PRODUCT_ID'],
409 'limit' => 1
410 ]);
411
412 if ($barcode = $barcodeRaw->fetch())
413 {
414 return $barcode['PRODUCT_ID'];
415 }
416
417 return null;
418 }
419
420 private function getProductBrand($sku): ?array
421 {
422 $product = $sku->getParent();
423 if (!$product)
424 {
425 return null;
426 }
427
428 $brand = $product->getPropertyCollection()->findByCodeLazy('BRAND_FOR_FACEBOOK');
429 if (!$brand)
430 {
431 return null;
432 }
433
434 $userType = \CIBlockProperty::GetUserType($brand->getUserType());
435 $userTypeMethod = $userType['GetUIEntityEditorProperty'];
436 $propertySettings = $brand->getSettings();
437 $propertyValues = $brand->getPropertyValueCollection()->getValues();
438 $description = $userTypeMethod($propertySettings, $propertyValues);
439 $propertyBrandItems = $description['data']['items'];
440
441 $selectedBrandItems = [];
442
443 foreach ($propertyBrandItems as $propertyBrandItem)
444 {
445 if (in_array($propertyBrandItem['VALUE'], $propertyValues, true))
446 {
447 $selectedBrandItems[] = $propertyBrandItem;
448 }
449 }
450
451 return $selectedBrandItems;
452 }
453
454 private function getProductProperties(BaseSku $sku): array
455 {
456 $emptyProps = [];
458 foreach ($columns as $columnName)
459 {
460 $emptyProps[$columnName] = '';
461 }
462
463 $productProps = [];
464 $parent = $sku->getParent();
465 if ($parent)
466 {
467 $productId = $parent->getId();
468 $productIblockId = $sku->getIblockInfo()->getProductIblockId();
469 if ($productId && $productIblockId)
470 {
471 $productProps = PropertyProduct::getIblockProperties($productIblockId, $productId);
472 }
473 }
474 unset($parent);
475
476 $skuProps = [];
477 $skuId = $sku->getId();
478 $skuIblockId = $sku->getIblockId();
479 if ($skuId && $skuIblockId)
480 {
481 $skuProps = PropertyProduct::getSkuProperties($skuIblockId, $skuId);
482 }
483
484 return array_merge($emptyProps, $productProps, $skuProps);
485 }
486
487 public function createProductAction(array $fields): ?array
488 {
489 $iblockId = (int)$fields['IBLOCK_ID'];
490 if (
491 !\CIBlockSectionRights::UserHasRightTo($iblockId, 0, 'section_element_bind')
492 || !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_ADD)
493 )
494 {
495 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_CREATION')));
496
497 return null;
498 }
499
500 $productFactory = ServiceContainer::getProductFactory($iblockId);
501 if (!$productFactory)
502 {
503 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
504
505 return null;
506 }
507
508 $skuRepository = ServiceContainer::getSkuRepository($iblockId);
510
512 $product = $productFactory
513 ->createEntity()
514 ->setType($type)
515 ;
516
517 $sku =
518 $skuRepository
519 ? $product->getSkuCollection()->create()
520 : $product->getSkuCollection()->getFirst()
521 ;
522
523 if (!empty($fields['BARCODE']))
524 {
525 $productId = $this->getProductIdByBarcode($fields['BARCODE']);
526
527 if ($productId !== null)
528 {
529 $elementRaw = ElementTable::getList([
530 'filter' => ['=ID' => $productId],
531 'select' => ['NAME'],
532 'limit' => 1
533 ]);
534
535 $name = '';
536 if ($element = $elementRaw->fetch())
537 {
538 $name = $element['NAME'];
539 }
540
541 $this->addError(
542 new Error(
543 Loc::getMessage(
544 'PRODUCT_SELECTOR_ERROR_BARCODE_EXIST',
545 [
546 '#BARCODE#' => htmlspecialcharsbx($fields['BARCODE']),
547 '#PRODUCT_NAME#' => htmlspecialcharsbx($name),
548 ]
549 )
550 )
551 );
552
553 return null;
554 }
555
556 if ($sku)
557 {
558 $sku->getBarcodeCollection()->setSimpleBarcodeValue($fields['BARCODE']);
559 }
560 }
561
562 if (empty($fields['CODE']))
563 {
564 $productName = $fields['NAME'] ?? '';
565
566 if ($productName !== '')
567 {
568 $fields['CODE'] = (new \CIBlockElement())->generateMnemonicCode($productName, $iblockId);
569 }
570 }
571
572 if (isset($fields['CODE']) && \CIBlock::isUniqueElementCode($iblockId))
573 {
574 $elementRaw = ElementTable::getList([
575 'filter' => ['=CODE' => $fields['CODE']],
576 'select' => ['ID'],
577 'limit' => 1
578 ]);
579
580 if ($elementRaw->fetch())
581 {
582 $fields['CODE'] = uniqid($fields['CODE'] . '_', false);
583 }
584 }
585
586 if (!empty($fields['MEASURE_CODE']))
587 {
588 $fields['MEASURE'] = $this->getMeasureIdByCode($fields['MEASURE_CODE']);
589 }
590 else
591 {
592 $measure = MeasureTable::getRow([
593 'select' => ['ID'],
594 'filter' => ['=IS_DEFAULT' => 'Y'],
595 ]);
596 if ($measure)
597 {
598 $fields['MEASURE'] = $measure['ID'];
599 }
600 }
601
602 if (!$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT))
603 {
604 unset($fields['PRICE']);
605 }
606
607 $product->setFields($fields);
608 if ($fields['MEASURE'] > 0)
609 {
610 $sku->setField('MEASURE', $fields['MEASURE']);
611 }
612 if (Option::get('catalog', 'default_product_vat_included') === 'Y')
613 {
614 $sku->setField('VAT_INCLUDED', ProductTable::STATUS_YES);
615 }
616
617 if (isset($fields['PRICE']) && $fields['PRICE'] >= 0)
618 {
619 $basePrice = [
620 'PRICE' => (float)$fields['PRICE'],
621 ];
622
623 if (isset($fields['CURRENCY']))
624 {
625 $basePrice['CURRENCY'] = $fields['CURRENCY'];
626 }
627
628 if ($sku)
629 {
630 $sku
631 ->getPriceCollection()
632 ->setValues([
633 'BASE' => $basePrice
634 ])
635 ;
636 }
637 }
638
639 $result = $product->save();
640
641 if (!$result->isSuccess())
642 {
643 $this->addErrors($result->getErrors());
644
645 return null;
646 }
647
648 return [
649 'id' => $sku->getId(),
650 ];
651 }
652
653 public function updateSkuAction(int $id, array $updateFields, array $oldFields = []): ?array
654 {
655 if (empty($updateFields) || $id <= 0)
656 {
657 return null;
658 }
659
660 $repositoryFacade = ServiceContainer::getRepositoryFacade();
661 if (!$repositoryFacade)
662 {
663 return null;
664 }
665
666 $sku = $repositoryFacade->loadVariation($id);
667 if (!$sku)
668 {
669 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_SKU_NOT_EXIST')));
670 return null;
671 }
673 $parentProduct = $sku->getParent();
674
675 if (
676 !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_EDIT)
677 || !\CIBlockElementRights::UserHasRightTo($parentProduct->getIblockId(), $parentProduct->getId(), 'element_edit')
678 )
679 {
680 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_UPDATE')));
681
682 return null;
683 }
684
685 if (
686 !$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT)
687 || !\CIBlockElementRights::UserHasRightTo($parentProduct->getIblockId(), $parentProduct->getId(), 'element_edit_price')
688 )
689 {
690 unset($updateFields['PRICES']);
691 }
692
693 $result = $this->saveSku($sku, $updateFields, $oldFields);
694 if (!$result->isSuccess())
695 {
696 $this->addErrors($result->getErrors());
697
698 return null;
699 }
700
701 return [
702 'id' => $sku->getId(),
703 ];
704 }
705
706 public function updateProductAction(int $id, int $iblockId, array $updateFields): ?array
707 {
708 return $this->updateSkuAction($id, $updateFields);
709 }
710
711 public function saveMorePhotoAction(int $productId, int $variationId, int $iblockId, array $imageValues): ?array
712 {
713 if (
714 !$this->accessController->check(ActionDictionary::ACTION_PRODUCT_EDIT)
715 || !\CIBlockElementRights::UserHasRightTo($iblockId, $productId, 'element_edit')
716 )
717 {
718 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_NO_PERMISSIONS_FOR_UPDATE')));
719
720 return null;
721 }
722
723 $productRepository = ServiceContainer::getProductRepository($iblockId);
724 if (!$productRepository)
725 {
726 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
727
728 return null;
729 }
730
732 $product = $productRepository->getEntityById($productId);
733 if (!$product)
734 {
735 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_PRODUCT_NOT_EXIST')));
736
737 return null;
738 }
739
740 // use the head product - in case when a simple product was saved but it became sku product
742 if ($productId === $variationId)
743 {
744 $entity = $product;
745 }
746 else
747 {
748 $entity = $product->getSkuCollection()->findById($variationId);
749 }
750
751 if (!$entity)
752 {
753 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_SKU_NOT_EXIST')));
754
755 return null;
756 }
757
758 $values = [];
759
760 $property = $entity->getPropertyCollection()->findByCodeLazy(MorePhotoImage::CODE);
761 foreach ($imageValues as $key => $newImage)
762 {
763 $newImage = $this->prepareMorePhotoValue($newImage, $entity);
764 if (empty($newImage))
765 {
766 continue;
767 }
768
769 if (!$property || !$property->isActive())
770 {
771 if (empty($previewPicture))
772 {
773 $previewPicture = $newImage;
774 continue;
775 }
776
777 $detailPicture = $newImage;
778 break;
779 }
780
781 if ($key === DetailImage::CODE)
782 {
783 $detailPicture = $newImage;
784 }
785 elseif ($key === PreviewImage::CODE)
786 {
787 $previewPicture = $newImage;
788 }
789 else
790 {
791 $values[$key] = $newImage;
792 }
793 }
794
795 $entity->getImageCollection()->setValues($values);
796
797 if (isset($detailPicture) && is_array($detailPicture))
798 {
799 $entity->getImageCollection()->getDetailImage()->setFileStructure($detailPicture);
800 }
801
802 if (isset($previewPicture) && is_array($previewPicture))
803 {
804 $entity->getImageCollection()->getPreviewImage()->setFileStructure($previewPicture);
805 }
806
807 $result = $product->save();
808 if (!$result->isSuccess())
809 {
810 $this->addErrors($result->getErrors());
811
812 return [];
813 }
814
815 $this->commitPendingCollection();
816
817 return (new ImageInput($entity))->getFormattedField();
818 }
819
820 private function prepareMorePhotoValue($imageValue, BaseIblockElementEntity $entity)
821 {
822 if (empty($imageValue))
823 {
824 return null;
825 }
826
827 if (!empty($imageValue['token']))
828 {
829 return $this->prepareMorePhotoValueByToken($imageValue, $entity);
830 }
831
832 if (is_string($imageValue))
833 {
834 try
835 {
836 static $signer = null;
837 if ($signer === null)
838 {
839 $signer = new Signer;
840 }
841
842 return (int)$signer->unsign($imageValue, ImageInput::FILE_ID_SALT);
843 }
844 catch (BadSignatureException $e)
845 {
846 return null;
847 }
848 }
849
850 if (
851 is_array($imageValue)
852 && !empty($imageValue['data'])
853 && is_array($imageValue['data'])
854 )
855 {
856 return \CIBlock::makeFileArray($imageValue['data']);
857 }
858
859 if (
860 is_array($imageValue)
861 && !empty($imageValue['base64Encoded'])
862 && is_array($imageValue['base64Encoded'])
863 )
864 {
865 $content = (string)($imageValue['base64Encoded']['content'] ?? '');
866 if ($content !== '')
867 {
868 $fileName = (string)($imageValue['base64Encoded']['filename'] ?? '');
869 $fileInfo = \CRestUtil::saveFile($content, $fileName);
870
871 return $fileInfo ?: null;
872 }
873 }
874
875 return null;
876 }
877
878 private function prepareMorePhotoValueByToken(array $image, BaseIblockElementEntity $entity): ?array
879 {
880 $token = $image['token'] ?? null;
881 if (empty($token))
882 {
883 return null;
884 }
885
886 $fileId = $this->getFileIdByToken($token, $entity);
887 if ($fileId)
888 {
889 return \CIBlock::makeFileArray($fileId, false, null, ['allow_file_id' => true]);
890 }
891
892 return null;
893 }
894
895 private function getFileIdByToken(string $token, BaseIblockElementEntity $entity): ?int
896 {
897 $uploader = $this->getUploader($entity);
898 $pendingFile = $uploader->getPendingFiles([$token])->get($token);
899
900 if ($pendingFile && $pendingFile->isValid())
901 {
902 $this->addPendingFileToCollection($pendingFile);
903
904 return $pendingFile->getFileId();
905 }
906
907 return null;
908 }
909
910 private function getUploader(BaseIblockElementEntity $entity): Uploader
911 {
912 if ($this->uploader === null)
913 {
914 $fileController = new ProductController([
915 'productId' => $entity->getId(),
916 ]);
917
918 $this->uploader = (new Uploader($fileController));
919 }
920
921 return $this->uploader;
922 }
923
924 private function addPendingFileToCollection(PendingFile $pendingFile): void
925 {
926 $this->getPendingFilesCollection()->add($pendingFile);
927 }
928
929 private function commitPendingCollection(): void
930 {
931 $this->getPendingFilesCollection()->makePersistent();
932 }
933
934 private function getPendingFilesCollection(): PendingFileCollection
935 {
936 if ($this->pendingFileCollection === null)
937 {
938 $this->pendingFileCollection = new PendingFileCollection();
939 }
940
941 return $this->pendingFileCollection;
942 }
943
944 private function saveSku(BaseSku $sku, array $fields = [], array $oldFields = []): Result
945 {
946 if ($sku->isNew() && empty($fields['CODE']))
947 {
948 $productName = $fields['NAME'] ?? '';
949
950 if ($productName !== '')
951 {
952 $fields['CODE'] = $this->prepareProductCode($productName);
953 }
954 }
955
956 if (!empty($fields['MEASURE_CODE']))
957 {
958 $fields['MEASURE'] = $this->getMeasureIdByCode($fields['MEASURE_CODE']);
959 }
960
961 $sectionId = $fields['IBLOCK_SECTION_ID'] ?? null;
962 unset($fields['IBLOCK_SECTION_ID']);
963
964 $sku->setFields($fields);
965
966 if (!empty($fields['PRICES']) && is_array($fields['PRICES']))
967 {
968 $priceCollection = $sku->getPriceCollection();
969 foreach ($fields['PRICES'] as $groupId => $price)
970 {
971 $priceCollection->setValues([
972 $groupId => [
973 'PRICE' => (float)$price['PRICE'],
974 'CURRENCY' => $price['CURRENCY'] ?? null,
975 ],
976 ]);
977 }
978 }
979
980 if (isset($fields['BARCODE']))
981 {
982 $skuId = $this->getProductIdByBarcode($fields['BARCODE']);
983 if ($skuId !== null && $sku->getId() !== $skuId)
984 {
985 $result = new Result();
986
987 $elementRaw = ElementTable::getList([
988 'filter' => ['=ID' => $skuId],
989 'select' => ['NAME'],
990 'limit' => 1
991 ]);
992
993 $name = '';
994 if ($element = $elementRaw->fetch())
995 {
996 $name = $element['NAME'];
997 }
998
999 $result->addError(
1000 new Error(
1001 Loc::getMessage(
1002 'PRODUCT_SELECTOR_ERROR_BARCODE_EXIST',
1003 [
1004 '#BARCODE#' => htmlspecialcharsbx($fields['BARCODE']),
1005 '#PRODUCT_NAME#' => htmlspecialcharsbx($name),
1006 ]
1007 )
1008 )
1009 );
1010
1011 return $result;
1012 }
1013
1014 $updateBarcodeItem = null;
1015 $barcodeCollection = $sku->getBarcodeCollection();
1016 if (isset($oldFields['BARCODE']))
1017 {
1018 $updateBarcodeItem = $barcodeCollection->getItemByBarcode($oldFields['BARCODE']);
1019 }
1020
1021 if ($updateBarcodeItem)
1022 {
1023 if (empty($fields['BARCODE']))
1024 {
1025 $barcodeCollection->remove($updateBarcodeItem);
1026 }
1027 else
1028 {
1029 $updateBarcodeItem->setBarcode($fields['BARCODE']);
1030 }
1031 }
1032 else
1033 {
1034 $barcodeItem =
1035 $barcodeCollection
1036 ->create()
1037 ->setBarcode($fields['BARCODE'])
1038 ;
1039
1040 $barcodeCollection->add($barcodeItem);
1041 }
1042 }
1043
1045 $parentProduct = $sku->getParent();
1046
1047 if (isset($fields['BRANDS']) && is_array($fields['BRANDS']))
1048 {
1049 $parentProduct->getPropertyCollection()->setValues(['BRAND_FOR_FACEBOOK' => $fields['BRANDS']]);
1050 }
1051
1052 if (isset($sectionId))
1053 {
1054 $parentProduct->setField('IBLOCK_SECTION_ID', $sectionId);
1055 }
1056
1057 if (
1058 isset($fields['NAME'])
1059 && $parentProduct->getSkuCollection()->count() === 1
1060 )
1061 {
1062 $this->changeProductName($parentProduct, $fields['NAME']);
1063 }
1064
1065 return $parentProduct->save();
1066 }
1067
1068 private function changeProductName(BaseProduct $parentProduct, string $newName): void
1069 {
1070 $skuTreeEntity = ServiceContainer::make('sku.tree', [
1071 'iblockId' => $parentProduct->getIblockId(),
1072 ]);
1073 $skuTree = $skuTreeEntity->load([$parentProduct->getId()]);
1074 if (empty($skuTree))
1075 {
1076 $parentProduct->setField('NAME', $newName);
1077
1078 return;
1079 }
1080
1081 $skuTreeElement = reset($skuTree);
1082 $existingValues = $skuTreeElement['EXISTING_VALUES'] ?? null;
1083 if (!$existingValues)
1084 {
1085 $parentProduct->setField('NAME', $newName);
1086
1087 return;
1088 }
1089
1090 $hasFilledProperty = false;
1091 foreach ($existingValues as $existingValue)
1092 {
1093 $hasFilledProperty = $existingValue[0] !== 0;
1094 if ($hasFilledProperty)
1095 {
1096 break;
1097 }
1098 }
1099 if (!$hasFilledProperty)
1100 {
1101 $parentProduct->setField('NAME', $newName);
1102 }
1103 }
1104
1105 private function getMeasureIdByCode(string $code): ?int
1106 {
1107 $measure = MeasureTable::getRow([
1108 'select' => ['ID'],
1109 'filter' => ['=CODE' => $code],
1110 ]);
1111 if ($measure)
1112 {
1113 return (int) $measure['ID'];
1114 }
1115
1116 return null;
1117 }
1118
1119 private function getMeasureCodeById(string $id): ?string
1120 {
1121 $measure = MeasureTable::getRow([
1122 'select' => ['CODE'],
1123 'filter' => ['=ID' => $id],
1124 ]);
1125
1126 return $measure['CODE'] ?? null;
1127 }
1128
1129 private function prepareProductCode($name): string
1130 {
1131 return mb_strtolower(\CUtil::translit(
1132 $name,
1133 LANGUAGE_ID,
1134 [
1135 'replace_space' => '_',
1136 'replace_other' => '',
1137 ]
1138 )).'_'.random_int(0, 1000);
1139 }
1140
1142 {
1143 $productFactory = ServiceContainer::getProductFactory($iblockId);
1144 if (!$productFactory)
1145 {
1146 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
1147
1148 return null;
1149 }
1150
1151 $imageField = new ImageInput();
1152
1153 return $imageField->getFormattedField();
1154 }
1155
1156 public function getFileInputAction(int $iblockId, int $skuId = null): ?Response\Component
1157 {
1158 $productFactory = ServiceContainer::getProductFactory($iblockId);
1159 if (!$productFactory)
1160 {
1161 $this->addError(new Error(Loc::getMessage('PRODUCT_SELECTOR_ERROR_WRONG_IBLOCK_ID')));
1162
1163 return null;
1164 }
1165
1166 $repositoryFacade = ServiceContainer::getRepositoryFacade();
1167
1168 $sku = null;
1169 if ($repositoryFacade && $skuId !== null)
1170 {
1171 $sku = $repositoryFacade->loadVariation($skuId);
1172 }
1173
1174 if ($sku === null)
1175 {
1176 $sku = $productFactory->createEntity();
1177 }
1178
1179 $imageField = new ImageInput($sku);
1180 $imageField->disableAutoSaving();
1181
1182 return $imageField->getComponentResponse();
1183 }
1184
1186 {
1187 $skuTree = ServiceContainer::make('sku.tree', [
1188 'iblockId' => $iblockId,
1189 ]);
1190
1191 if ($skuTree)
1192 {
1193 return $skuTree->getTreeProperties();
1194 }
1195
1196 return [];
1197 }
1198
1199 public function getSkuSelectorItemAction(int $id, array $options): ?array
1200 {
1201 if (!Loader::includeModule('ui'))
1202 {
1203 return null;
1204 }
1205
1206 $items = [
1207 ['product', $id]
1208 ];
1209 $dialogOptions = [
1210 [
1211 'id' => 'product',
1212 'options' => $options,
1213 ],
1214 ];
1215 $selectedItems = Dialog::getSelectedItems($items, $dialogOptions)->toArray();
1216 if (!isset($selectedItems[0]))
1217 {
1218 return null;
1219 }
1220
1221 $item = $selectedItems[0];
1222 if (($item['hidden'] ?? null) === true)
1223 {
1224 return null;
1225 }
1226
1227 return $item;
1228 }
1229
1230 public function isInstalledMobileAppAction(): bool
1231 {
1232 return (bool)\CUserOptions::GetOption('mobile', 'iOsLastActivityDate')
1233 || (bool)\CUserOptions::GetOption('mobile', 'AndroidLastActivityDate')
1234 ;
1235 }
1236}
$type
Определения options.php:106
getFileInputAction(int $iblockId, int $skuId=null)
Определения productselector.php:1156
processBeforeAction(Action $action)
Определения productselector.php:84
getEmptyInputImageAction(int $iblockId)
Определения productselector.php:1141
getProductAction(int $productId, array $options=[])
Определения productselector.php:175
getSkuSelectorItemAction(int $id, array $options)
Определения productselector.php:1199
getSkuTreePropertiesAction(int $iblockId)
Определения productselector.php:1185
updateProductAction(int $id, int $iblockId, array $updateFields)
Определения productselector.php:706
const STATUS_YES
Определения product.php:66
const TYPE_SKU
Определения product.php:72
const TYPE_OFFER
Определения product.php:73
const TYPE_PRODUCT
Определения product.php:70
static getIblockProperties(int $iblockId, int $productId, array $filter=[])
Определения PropertyProduct.php:99
static getSkuProperties(int $iblockId, int $skuId, array $filter=[])
Определения PropertyProduct.php:26
getField(string $name)
Определения BaseEntity.php:119
getFrontImageCollection()
Определения BaseSku.php:76
getBarcodeCollection()
Определения BaseSku.php:167
addError(Error $error)
Определения controller.php:1070
addErrors(array $errors)
Определения controller.php:1083
Определения error.php:15
static getList(array $parameters=array())
Определения datamanager.php:431
static getSelectedItems(array $ids, array $options=[])
Определения dialog.php:489
static ConvertCurrency($valSum, $curFrom, $curTo, $valDate="")
Определения currency_rate.php:393
$options
Определения commerceml2.php:49
$content
Определения commerceml.php:144
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$entity
if(Loader::includeModule( 'bitrix24')) elseif(Loader::includeModule('intranet') &&CIntranetUtils::getPortalZone() !=='ru') $description
Определения .description.php:24
$iblockId
Определения iblock_catalog_edit.php:30
$productIblockId
Определения iblock_catalog_edit.php:242
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
$name
Определения menu_edit.php:35
string $sectionId
Определения columnfields.php:71
trait Error
Определения error.php:11
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$fileName
Определения quickway.php:305
if(empty($signedUserToken)) $key
Определения quickway.php:257
$currency
Определения template.php:266
if($params["BILLBY_ORDER_SUBJECT"]) if( $params["PAYMENT_DATE_PAY_BEFORE"]) if($params['BILLBY_PAYER_SHOW']=='Y') $currencyFormat
Определения template.php:393
$items
Определения template.php:224
$response
Определения result.php:21
$action
Определения file_dialog.php:21
$iterator
Определения yandex_run.php:610
$fields
Определения yandex_run.php:501