Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
gridvariationform.php
1<?php
2
4
19use Bitrix\Currency\Integration\IblockMoneyProperty;
20use CIBlockPropertyXmlID;
21
23{
25 protected $entity;
26
27 protected static ?array $usedHeaders = null;
28 protected static ?array $headers = null;
29
30 protected function prepareFieldName(string $name): string
31 {
32 $name = parent::prepareFieldName($name);
33
34 return static::formatFieldName($name);
35 }
36
37 public static function formatFieldName($name): string
38 {
39 return BaseForm::GRID_FIELD_PREFIX.parent::formatFieldName($name);
40 }
41
42 public static function preparePropertyName(string $name = ''): string
43 {
44 $name = parent::preparePropertyName($name);
45
46 return static::formatFieldName($name);
47 }
48
49 public function isReadOnly(): bool
50 {
51 return !$this->isAllowedEditFields();
52 }
53
54 public static function getGridCardSettingsItems(): array
55 {
56 $result = [];
57 $result['VAT_INCLUDED'] = [
58 'ITEMS' => [
59 static::formatFieldName('VAT_ID'),
60 static::formatFieldName('VAT_INCLUDED'),
61 ],
62 'TITLE' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_TITLE_VAT_INCLUDED'),
63 'DESCRIPTION' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_DESC_VAT_INCLUDED'),
64 ];
65 if (AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_PURCHASE_INFO_VIEW))
66 {
67 $result['PURCHASING_PRICE_FIELD'] = [
68 'ITEMS' => [
69 static::formatFieldName('PURCHASING_PRICE_FIELD'),
70 ],
71 'TITLE' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_TITLE_PURCHASING_PRICE_FIELD'),
72 'DESCRIPTION' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_DESC_PURCHASING_PRICE_FIELD'),
73 ];
74 }
75 $result['MEASUREMENTS'] = [
76 'ITEMS' => [
77 static::formatFieldName('HEIGHT'),
78 static::formatFieldName('LENGTH'),
79 static::formatFieldName('WIDTH'),
80 static::formatFieldName('WEIGHT'),
81 ],
82 'TITLE' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_TITLE_MEASUREMENTS'),
83 'DESCRIPTION' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_DESC_MEASUREMENTS'),
84 ];
85 $result['MEASURE_RATIO'] = [
86 'ITEMS' => [
87 static::formatFieldName('MEASURE_RATIO'),
88 ],
89 'TITLE' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_TITLE_MEASURE_RATIO'),
90 'DESCRIPTION' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_DESC_MEASURE_RATIO_MSGVER_1'),
91 ];
92
93 return $result;
94 }
95
96 public function setGridSettings(string $settingId, $selected, array $currentHeaders = []): AjaxJson
97 {
98 $headers = static::getHeaderIdsBySettingId($settingId);
99
100 if (!empty($headers))
101 {
102 $options = new \Bitrix\Main\Grid\Options($this->getVariationGridId());
103 $allUsedColumns = $options->getUsedColumns();
104
105 if (empty($allUsedColumns))
106 {
107 $allUsedColumns = $currentHeaders;
108 }
109
110 if ($selected === 'true')
111 {
112 // sort new columns by default grid column sort
113 $defaultHeaders = array_column($this->getGridHeaders(), 'id');
114 $currentHeadersInDefaultPosition = array_values(
115 array_intersect($defaultHeaders, array_merge($allUsedColumns, $headers))
116 );
117 $headers = array_values(array_intersect($defaultHeaders, $headers));
118
119 foreach ($headers as $header)
120 {
121 $insertPosition = array_search($header, $currentHeadersInDefaultPosition, true);
122 array_splice($allUsedColumns, $insertPosition, 0, $header);
123 }
124 }
125 else
126 {
127 $allUsedColumns = array_diff($allUsedColumns, $headers);
128 }
129
130 $options->setColumns(implode(',', $allUsedColumns));
131 $options->save();
132 }
133
134 return AjaxJson::createSuccess();
135 }
136
137 protected static function getHeaderIdsBySettingId(string $settingId): array
138 {
139 $headers = [];
140 switch ($settingId)
141 {
142 case 'MEASUREMENTS':
143 $headers = [
144 'WEIGHT',
145 'WIDTH',
146 'LENGTH',
147 'HEIGHT',
148 ];
149 break;
150 case 'PURCHASING_PRICE_FIELD':
151 if (AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_PURCHASE_INFO_VIEW))
152 {
153 $headers = [
154 'PURCHASING_PRICE_FIELD',
155 ];
156 }
157 break;
158 case 'MEASURE_RATIO':
159 $headers = [
160 'MEASURE_RATIO',
161 ];
162 break;
163 case 'VAT_INCLUDED':
164 $headers = [
165 'VAT_INCLUDED',
166 'VAT_ID'
167 ];
168 break;
169 }
170
171 foreach ($headers as &$id)
172 {
173 $id = static::formatFieldName($id);
174 }
175 unset($id);
176
177 return $headers;
178 }
179
180 protected function buildDescriptions(): array
181 {
182 return array_merge(
183 parent::buildDescriptions(),
185 $this->getBarcodeDescription()
186 );
187 }
188
189 protected function getPropertyDescription(Property $property): array
190 {
191 $description = parent::getPropertyDescription($property);
192
193 if ($description['editable'])
194 {
195 switch ($description['type'])
196 {
197 case 'multilist':
198 $dropdownItems = [];
199
200 if (!empty($description['data']['items']) && is_array($description['data']['items']))
201 {
202 $dropdownItems = $description['data']['items'];
203 }
204
205 $description['editable'] = [
206 'TYPE' => Types::MULTISELECT,
207 'DATA' => [
208 'ITEMS' => $dropdownItems,
209 ]
210 ];
211 break;
212 case 'list':
213 $dropdownItems = [];
214
215 if (!$description['required'])
216 {
217 $dropdownItems[] = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_NOT_SELECTED');
218 }
219
220 if (!empty($description['data']['items']) && is_array($description['data']['items']))
221 {
222 foreach ($description['data']['items'] as $item)
223 {
224 $dropdownItems[$item['VALUE']] = $item['NAME'];
225 }
226 }
227 $description['editable'] = [
228 'TYPE' => Types::DROPDOWN,
229 'items' => $dropdownItems,
230 ];
231 break;
232 case 'custom':
233 if ($description['multiple'] === true && $description['propertyCode'] !== 'MORE_PHOTO')
234 {
235 $description['editable'] = false;
236 }
237 else
238 {
239 $description['editable'] = [
240 'TYPE' => Types::CUSTOM,
241 'NAME' => $description['data']['edit'] ?? $description['name'],
242 // 'HTML' => $description['data']['edit'] ?? $description['name'],
243 ];
244 }
245 break;
246 case 'boolean':
247 $description['editable'] = ['TYPE' => Types::CHECKBOX];
248 break;
249 case 'datetime':
250 $description['editable'] = ['TYPE' => Types::DATE];
251 break;
252 case 'money':
253 $description['editable'] = [
254 'TYPE' => Types::MONEY,
255 'CURRENCY_LIST' => CurrencyManager::getSymbolList(),
256 'HTML_ENTITY' => true,
257 ];
258 break;
259 default:
260 $description['editable'] = ['TYPE' => Types::TEXT];
261 }
262
263 $nonEditableUserTypes = [
264 'ElementXmlID',
265 'employee',
266 'map_yandex',
267 'map_google',
268 'ECrm',
269 'video',
270 'HTML',
271 ];
272 if (
273 $description['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_ELEMENT
274 || $description['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_SECTION
275 || in_array($description['settings']['USER_TYPE'], $nonEditableUserTypes, true)
276 )
277 {
278 $description['editable'] = false;
279 }
280 }
281
282 return $description;
283 }
284
285 protected function getUnavailableUserTypes(): array
286 {
287 return [
288 'DiskFile',
289 'TopicID',
290 ];
291 }
292
293 public function getColumnValues(bool $allowDefaultValues = true): array
294 {
295 $values = $this->getShowedValues($allowDefaultValues);
296
297 foreach ($this->getGridHeaders() as $description)
298 {
299 $name = $description['id'];
300 if (!isset($values[$name]))
301 {
302 continue;
303 }
304
305 $currentValue = $values[$name];
306
307 switch ($description['type'])
308 {
309 case 'string':
310 case 'text':
311 if (!empty($values[$name]))
312 {
313 $values[$name] = HtmlFilter::encode($values[$name]);
314 }
315 break;
316 case 'number':
317 $values[$name] = (float)($values[$name] ?: 0);
318 break;
319 case 'multilist':
320 if (is_array($currentValue))
321 {
322 $formatted = [];
323 $items = [];
324
325 foreach ($description['data']['items'] as $item)
326 {
327 $items[$item['VALUE']] = $item['HTML'] ?? HtmlFilter::encode($item['NAME']);
328 }
329
330 foreach ($currentValue as $multipleItemValue)
331 {
332 $formatted[] = $items[$multipleItemValue];
333 }
334
335 $values[$name] = $formatted;
336 }
337 break;
338 case 'boolean':
339 $code = '';
340 if (
341 $description['id'] === static::formatFieldName('ACTIVE')
342 || $description['id'] === static::formatFieldName('AVAILABLE')
343 || $description['id'] === static::formatFieldName('VAT_INCLUDED')
344 )
345 {
346 $code = $currentValue === 'Y' ? 'YES' : 'NO';
347 }
348 else
349 {
350 $code = ($currentValue !== '') ? 'YES' : 'NO';
351 }
352 $values[$name] = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_VALUE_' . $code);
353 break;
354 case 'list':
355 if (isset($description['editable']['items']))
356 {
357 $values[$name] = HtmlFilter::encode($description['editable']['items'][$currentValue] ?? '');
358 break;
359 }
360 foreach ($description['data']['items'] as $item)
361 {
362 if ($currentValue === $item['VALUE'])
363 {
364 $values[$name] = HtmlFilter::encode($item['NAME'] ?? '');
365 break;
366 }
367 }
368 break;
369 case 'custom':
370 $values[$name] = $values[$description['data']['view']];
371 break;
372 case 'user':
373 $values[$name] = HtmlFilter::encode($values[$name . '_FORMATTED_NAME'] ?? '');
374 break;
375 case 'readOnlyVat':
376 $currentVat = (int)$values[$name];
377 $values[$name] = '';
378 if ($currentVat > 0)
379 {
380 foreach ($this->getVats() as $vat)
381 {
382 if ((int)$vat['ID'] === $currentVat)
383 {
384 $values[$name] = htmlspecialcharsbx($vat['NAME']);
385 break;
386 }
387 }
388 }
389 break;
390 case 'barcode':
391 $barcodes =
392 is_array($values[$name])
393 ? array_column($values[$name], 'BARCODE')
394 : null
395 ;
396
397 $values[$name] = $barcodes ? htmlspecialcharsbx(implode(', ', $barcodes)) : '';
398 break;
399 case 'money':
400 if (isset($description['data']['isProductProperty']) && $description['data']['isProductProperty'])
401 {
402 $separatedValues = IblockMoneyProperty::getSeparatedValues($values[$name]);
403 $amount = (float)($separatedValues['AMOUNT'] . '.' . $separatedValues['DECIMALS']);
404 $currency = $separatedValues['CURRENCY'];
405 $values[$name] = \CCurrencyLang::CurrencyFormat($amount, $currency, true);
406 }
407 break;
408 }
409
410 if (is_array($values[$name]))
411 {
412 $values[$name] = implode(', ', $values[$name]);
413 }
414 }
415
416 return $values;
417 }
418
419 public function loadGridHeaders(): array
420 {
421 $defaultWidth = 130;
422
423 $headerName = static::getHeaderName('NAME');
424
425 $headers = [
426 [
427 'id' => static::formatFieldName('NAME'),
428 'name' => $headerName['NAME'],
429 'title' => $headerName['TITLE'],
430 'sort' => 'NAME',
431 'type' => 'string',
432 'editable' =>
433 $this->isAllowedEditFields()
434 ? [
435 'TYPE' => Types::TEXT,
436 'PLACEHOLDER' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_NEW_VARIATION_PLACEHOLDER_MSGVER_1'),
437 ]
438 : false
439 ,
440 'width' => $defaultWidth,
441 'default' => false,
442 ],
443 ];
444
445 $headers = array_merge(
446 $headers,
449 ['ACTIVE', 'BARCODE', 'QUANTITY_COMMON', 'MEASURE', 'MEASURE_RATIO'],
450 $defaultWidth
451 ),
452 $this->getPurchasingPriceHeaders($defaultWidth),
453 $this->getPricesHeaders($defaultWidth),
455 [
456 'AVAILABLE', 'VAT_ID', 'VAT_INCLUDED', 'QUANTITY', 'QUANTITY_RESERVED',
457 'QUANTITY_TRACE', 'CAN_BUY_ZERO', // 'SUBSCRIBE',
458 'WEIGHT', 'WIDTH', 'LENGTH', 'HEIGHT',
459 'SHOW_COUNTER', 'CODE', 'TIMESTAMP_X', 'MODIFIED_BY',
460 'DATE_CREATE', 'XML_ID',
461 // 'BAR_CODE', 'TAGS', 'DISCOUNT', 'STORE', 'PRICE_TYPE',
462 ],
463 $defaultWidth
464 )
465 );
466
467 self::$headers = $headers;
468
469 return $headers;
470 }
471
472 public function getGridHeaders(): array
473 {
474 if (self::$headers)
475 {
476 return self::$headers;
477 }
478
479 return $this->loadGridHeaders();
480 }
481
487 public function getGridSupportedAjaxColumns(): array
488 {
489 $columns = array_fill_keys(
490 array_column($this->getGridHeaders(), 'id'),
491 true
492 );
493
494 foreach ($this->getIblockPropertiesDescriptions() as $property)
495 {
496 $name = $property['name'];
497
498 // files are not supported because new files are not sent in the request
499 $isFile = $property['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_FILE;
500 if ($isFile)
501 {
502 unset($columns[$name]);
503 }
504 }
505
506 return array_keys($columns);
507 }
508
509 protected function getProductFieldHeaders(array $fields, int $defaultWidth): array
510 {
511 $headers = [];
512
513 $numberFields = ['QUANTITY', 'QUANTITY_RESERVED', 'QUANTITY_COMMON', 'MEASURE_RATIO', 'WEIGHT', 'WIDTH', 'LENGTH', 'HEIGHT'];
514 $numberFields = array_fill_keys($numberFields, true);
515
516 $immutableFields = ['TIMESTAMP_X', 'MODIFIED_BY', 'DATE_CREATE', 'CREATED_USER_NAME', 'AVAILABLE'];
517 $immutableFields = array_fill_keys($immutableFields, true);
518
519 $defaultFields = ['QUANTITY', 'MEASURE', 'NAME', 'BARCODE'];
520 $defaultFields = array_fill_keys($defaultFields, true);
521
522 $sortableFields = [
523 'QUANTITY' =>'QUANTITY',
524 'AVAILABLE' =>'AVAILABLE',
525 'WEIGHT' =>'WEIGHT',
526 'ACTIVE' =>'ACTIVE',
527 'MEASURE' =>'MEASURE',
528 'TIMESTAMP_X' => 'TIMESTAMP_X',
529 'MODIFIED_BY' => 'MODIFIED_BY',
530 'DATE_CREATE' => 'CREATED',
531 'CREATED_USER_NAME' => 'CREATED_BY',
532 'CODE' => 'CODE',
533 'EXTERNAL_ID' => 'EXTERNAL_ID',
534 'XML_ID' => 'XML_ID',
535 'TAGS' => 'TAGS',
536 'SHOW_COUNTER' => 'SHOW_COUNTER',
537 'SHOW_COUNTER_START' => 'SHOW_COUNTER_START',
538 'PREVIEW_PICTURE' => 'HAS_PREVIEW_PICTURE',
539 'DETAIL_PICTURE' => 'HAS_DETAIL_PICTURE',
540 ];
541
542 foreach ($fields as $code)
543 {
544 $type = isset($numberFields[$code]) ? 'number' : 'string';
545
546 switch ($code)
547 {
548 case 'AVAILABLE':
549 case 'ACTIVE':
550 case 'VAT_INCLUDED':
551 $type = 'boolean';
552 break;
553
554 case 'MODIFIED_BY':
555 $type = 'user';
556 break;
557
558 case 'VAT_ID':
559 case 'MEASURE':
560 case 'QUANTITY_TRACE':
561 case 'CAN_BUY_ZERO':
562 case 'SUBSCRIBE':
563 $type = 'list';
564 break;
565 }
566
567 $editable = false;
568
569 if (!isset($immutableFields[$code]))
570 {
571 $editable = [
572 'TYPE' => Types::TEXT,
573 ];
574
575 switch ($code)
576 {
577 case 'ACTIVE':
578 $editable = [
579 'TYPE' => Types::CHECKBOX,
580 ];
581 break;
582 case 'VAT_INCLUDED':
583 $editable =
584 $this->isPricesEditable()
585 ? ['TYPE' => Types::CHECKBOX]
586 : false
587 ;
588 break;
589
590 case 'VAT_ID':
591 if (!$this->isPricesEditable())
592 {
593 $editable = false;
594 $type = 'readOnlyVat';
595
596 break;
597 }
598
599 $defaultVat = $this->getDefaultVat();
600 $vatList = [
601 $defaultVat['ID'] => $defaultVat['NAME'],
602 ];
603
604 if ($defaultVat['ID'] !== static::NOT_SELECTED_VAT_ID_VALUE && !Loader::includeModule('bitrix24'))
605 {
606 $vatList[static::NOT_SELECTED_VAT_ID_VALUE] = Loc::getMessage("CATALOG_PRODUCT_CARD_VARIATION_GRID_NOT_SELECTED");
607 }
608
609 foreach ($this->getVats() as $vat)
610 {
611 if ($vat['RATE'] === $defaultVat['RATE'] && $vat['EXCLUDE_VAT'] === $defaultVat['EXCLUDE_VAT'])
612 {
613 continue;
614 }
615
616 $vatList[$vat['ID']] = htmlspecialcharsbx($vat['NAME']);
617 }
618 $editable = [
619 'TYPE' => Types::DROPDOWN,
620 'items' => $vatList,
621 ];
622 break;
623
624 case 'MEASURE':
625 $measureList = [];
626
627 foreach ($this->getMeasures() as $measure)
628 {
629 $measureList[$measure['ID']] = htmlspecialcharsbx($measure['MEASURE_TITLE']);
630 if (empty($measureList[$measure['ID']]))
631 {
632 $measureList[$measure['ID']] = \CCatalogMeasureClassifier::getMeasureTitle(
633 $measure["CODE"],
634 'MEASURE_TITLE'
635 );
636 }
637 }
638 $editable = [
639 'TYPE' => Types::DROPDOWN,
640 'items' => $measureList,
641 ];
642 break;
643
644 case 'QUANTITY':
645 case 'QUANTITY_RESERVED':
646 case 'QUANTITY_COMMON':
647 if (State::isUsedInventoryManagement())
648 {
649 $editable = false;
650 }
651 else
652 {
653 $editable = [
654 'TYPE' => Types::NUMBER,
655 'PLACEHOLDER' => 0,
656 ];
657 }
658 break;
659
660 case 'MEASURE_RATIO':
661 $editable = [
662 'TYPE' => Types::NUMBER,
663 'PLACEHOLDER' => 0,
664 ];
665 break;
666
667 case 'BARCODE':
668 $editable = [
669 'TYPE' => Types::CUSTOM,
670 ];
671 $type = 'barcode';
672 break;
673
674 case 'QUANTITY_TRACE':
675 case 'CAN_BUY_ZERO':
676 case 'SUBSCRIBE':
677 $items = [];
678 foreach ($this->getCatalogEnumFields($code) as $field)
679 {
680 $items[$field['VALUE']] = $field['NAME'];
681 }
682
683 $editable = [
684 'TYPE' => Types::DROPDOWN,
685 'items' => $items,
686 ];
687 break;
688 }
689 }
690
691 $headerName =
692 $code === 'MODIFIED_BY'
693 ? static::getHeaderName('USER_NAME')
694 : static::getHeaderName($code)
695 ;
696
697 $sortField = $sortableFields[$code] ?? false;
698
699 $headers[] = [
700 'id' => static::formatFieldName($code),
701 'name' => $headerName['NAME'],
702 'title' => $headerName['TITLE'],
703 'sort' => $sortField,
704 'locked' => false,
705 'headerHint' => null,
706 'type' => $type,
707 'align' => $type === 'number' ? 'right' : 'left',
708 'editable' => $editable,
709 'width' => $defaultWidth,
710 'default' => isset($defaultFields[$code]),
711 ];
712 }
713
714 return $headers;
715 }
716
722 protected function getIblockPropertiesHeaders(): array
723 {
724 $headers = [];
725
726 foreach ($this->getIblockPropertiesDescriptions() as $property)
727 {
728 $isDirectory =
729 $property['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_STRING
730 && $property['settings']['USER_TYPE'] === 'directory'
731 ;
732
733 $sortField = 'PROPERTY_' . $property['propertyId'];
734 if (
735 $property['multiple']
736 || $property['propertyCode'] === 'CML2_LINK'
737 || $property['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_FILE
738 )
739 {
740 $sortField = false;
741 }
742
743 $header = [
744 'id' => $property['name'],
745 'name' => $property['title'],
746 'title' => $property['title'],
747 'type' => $property['type'],
748 'align' => $property['type'] === 'number' ? 'right' : 'left',
749 'sort' => $sortField,
750 'default' => $property['propertyCode'] === self::MORE_PHOTO,
751 'data' => $property['data'],
752 'width' => $isDirectory ? 160 : null,
753 'editable' => $property['editable'],
754 ];
755 if (!empty($property['isEnabledOfferTree']))
756 {
757 $header['hint'] = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_OFFER_TREE_HINT_MSGVER_1');
758 }
759
760 if (
761 $property['settings']['PROPERTY_TYPE'] === PropertyTable::TYPE_FILE
762 && $property['multiple'] === true
763 && $property['propertyCode'] !== 'MORE_PHOTO'
764 )
765 {
766 $header['hint'] = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_FILE_MULTIPLE_HINT_MSGVER_1');
767 }
768
769 $headers[] = $header;
770 }
771
772 return $headers;
773 }
774
781 protected function getPurchasingPriceHeaders(?int $defaultWidth): array
782 {
783 $headers = [];
784
785 if ($this->isPurchasingPriceAllowed())
786 {
787 $headerName = static::getHeaderName('PURCHASING_PRICE');
788
789 $headers[] = [
790 'id' => static::formatFieldName('PURCHASING_PRICE_FIELD'),
791 'name' => $headerName['NAME'],
792 'title' => $headerName['TITLE'],
793 'sort' => 'PURCHASING_PRICE',
794 'type' => 'money',
795 'align' => 'right',
796 'editable' =>
797 !State::isUsedInventoryManagement() && $this->isAllowedEditFields()
798 ? [
799 'TYPE' => Types::MONEY,
800 'CURRENCY_LIST' => CurrencyManager::getSymbolList(),
801 'HTML_ENTITY' => true,
802 ]
803 : false
804 ,
805 'width' => $defaultWidth,
806 'default' => false,
807 ];
808 }
809
810 return $headers;
811 }
812
819 protected function getPricesHeaders(?int $defaultWidth): array
820 {
821 $headers = [];
822
823 $currencyList = CurrencyManager::getSymbolList();
824
825 foreach (Catalog\GroupTable::getTypeList() as $priceType)
826 {
827 $columnName = $priceType['NAME_LANG'] ?? $priceType['NAME'];
828
829 $priceId = static::formatFieldName(BaseForm::PRICE_FIELD_PREFIX.$priceType['ID'].'_FIELD');
830 $headers[] = [
831 'id' => $priceId,
832 'name' => $columnName,
833 'title' => $columnName,
834 'sort' => 'SCALED_PRICE_'.$priceType['ID'],
835 'type' => 'money',
836 'align' => 'right',
837 'editable' =>
838 $this->isPricesEditable()
839 ? [
840 'TYPE' => Types::MONEY,
841 'CURRENCY_LIST' => $currencyList,
842 'HTML_ENTITY' => true,
843 ]
844 : false
845 ,
846 'locked' => !$this->isPricesEditable(),
847 'headerHint' =>
848 $this->isPricesEditable()
849 ? null
850 : Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_PRICE_EDIT_RESTRICTED_HINT')
851 ,
852 'base' => $priceType['BASE'] === 'Y',
853 'width' => $defaultWidth,
854 'default' => $priceType['BASE'] === 'Y',
855 ];
856 }
857
858 return $headers;
859 }
860
861 private function getShowedValues(bool $allowDefaultValues = true): array
862 {
863 if (!self::$usedHeaders)
864 {
865 $options = new \Bitrix\Main\Grid\Options($this->getVariationGridId());
866 self::$usedHeaders = $options->getUsedColumns();
867
868 if (!self::$usedHeaders)
869 {
870 $defaultHeaders = array_filter(
871 $this->getGridHeaders(),
872 static function ($header)
873 {
874 return ($header['default'] === true);
875 }
876 );
877
878 self::$usedHeaders = array_column($defaultHeaders, 'id');
879 }
880 }
881
883 $filteredDescriptions = array_filter(
884 $this->getDescriptions(),
885 static function ($description) use ($usedHeaders)
886 {
887 return in_array($description['name'], $usedHeaders, true);
888 }
889 );
890
891 return parent::getValues($allowDefaultValues, $filteredDescriptions);
892 }
893
894 public function getValues(bool $allowDefaultValues = true, array $descriptions = null): array
895 {
896 $values = $this->getShowedValues($allowDefaultValues);
897
898 foreach ($this->getDescriptions() as $description)
899 {
900 $name = $description['name'];
901
902 if (!isset($values[$name]))
903 {
904 continue;
905 }
906
907 switch ($description['type'])
908 {
909 case 'custom':
910 $values[$name] = $values[$description['data']['view']];
911 break;
912 case 'money':
913 $descriptionData = $description['data'];
914 $values[$name] = [
915 'PRICE' => [
916 'NAME' => $descriptionData['amount'],
917 'VALUE' => $values[$descriptionData['amount']],
918 ],
919 'CURRENCY' => [
920 'NAME' => $descriptionData['currency']['name'],
921 'VALUE' => $values[$descriptionData['currency']['name']],
922 ],
923 ];
924 break;
925 case 'boolean':
926 $descriptionData = $description['data'] ?? [];
927 $variants = $descriptionData['items'] ?? [];
928 foreach ($variants as $variant)
929 {
930 if ($values[$name] === $variant['ID'])
931 {
932 $values[$name] = $variant['NAME'];
933 break;
934 }
935 }
936 break;
937 }
938 }
939
940 return $values;
941 }
942
952 public function prepareFieldsValues(array $dirtyValues): array
953 {
954 $result = [
955 'PROPERTIES' => [],
956 'BARCODES' => [],
957 'PRICES' => [],
958 ];
959
960 $pricePrefix = self::GRID_FIELD_PREFIX . self::PRICE_FIELD_PREFIX;
961 $purchacingPricePrefix = self::GRID_FIELD_PREFIX . 'PURCHASING_PRICE';
962
963 foreach ($this->getDescriptions() as $description)
964 {
965 $name = $description['name'];
966 $value = $dirtyValues[$name] ?? null;
967 if (!isset($value))
968 {
969 continue;
970 }
971
972 if (isset($description['propertyId']))
973 {
974 $type = $description['type'] ?? null;
975 if ($type === 'multilist' && empty($value))
976 {
977 $value = [];
978 }
979
980 $propertyId = (int)$description['propertyId'];
981 $result['PROPERTIES'][$propertyId] = $value;
982 }
983 elseif (mb_strpos($name, $pricePrefix) === 0)
984 {
985 if (
986 is_array($value)
987 && isset($value['PRICE']['NAME'], $value['PRICE']['VALUE'], $value['CURRENCY']['VALUE'])
988 )
989 {
990 $priceGroupId = str_replace($pricePrefix, '', $value['PRICE']['NAME']);
991 if ($priceGroupId)
992 {
993 $result['PRICES'][$priceGroupId] = [
994 'PRICE' => (float)$value['PRICE']['VALUE'],
995 'CURRENCY' => (string)$value['CURRENCY']['VALUE'],
996 ];
997 }
998 }
999 }
1000 elseif (mb_strpos($name, $purchacingPricePrefix) === 0)
1001 {
1002 if (is_array($value) && isset($value['PRICE']['VALUE'], $value['CURRENCY']['VALUE']))
1003 {
1004 $result['PURCHASING_PRICE'] = (float)$value['PRICE']['VALUE'];
1005 $result['PURCHASING_CURRENCY'] = (string)$value['CURRENCY']['VALUE'];
1006 }
1007 }
1008 elseif (isset($description['originalName']))
1009 {
1010 $name = $description['originalName'];
1011 $result[$name] = $value;
1012 }
1013 elseif (isset($description['entity']) && $description['entity'] === 'barcode')
1014 {
1015 if (is_array($value))
1016 {
1017 array_push($result['BARCODES'], ...$value);
1018 }
1019 else
1020 {
1021 $result['BARCODES'][] = $value;
1022 }
1023 }
1024 elseif (isset($description['entity']) && $description['entity'] === 'measure_ratio')
1025 {
1026 $result['MEASURE_RATIO'] = $value;
1027 }
1028 }
1029
1030 return $result;
1031 }
1032
1033 protected function getAdditionalValues(array $values, array $descriptions = null): array
1034 {
1035 $additionalValues = parent::getAdditionalValues($values, $descriptions);
1036
1037 $numberFields = ['MEASURE_RATIO', 'QUANTITY'];
1038 foreach ($numberFields as $fieldName)
1039 {
1040 $fieldName = self::formatFieldName($fieldName);
1041 if (isset($values[$fieldName]) && $values[$fieldName] == 0)
1042 {
1043 $additionalValues[$fieldName] = null;
1044 }
1045 }
1046
1047 return $additionalValues;
1048 }
1049
1050 protected function getPropertySettings(Property $property): array
1051 {
1052 $settings = parent::getPropertySettings($property);
1053 $settings['GRID_MODE'] = true;
1054
1055 return $settings;
1056 }
1057
1058 protected function getImagePropertyViewHtml($value): string
1059 {
1060 $fileCount = 0;
1061
1062 // single scalar property
1063 if (!empty($value) && !is_array($value))
1064 {
1065 $value = [$value];
1066 }
1067
1068 if (is_array($value))
1069 {
1070 $fileCount = min(count($value), 3);
1071 $value = reset($value);
1072 }
1073
1074 $imageSrc = '';
1075
1076 if (!empty($value))
1077 {
1078 $image = \CFile::GetFileArray($value);
1079 if ($image)
1080 {
1081 $imageSrc = $image['SRC'];
1082 }
1083 }
1084
1085 switch ($fileCount)
1086 {
1087 case 3:
1088 $multipleClass = ' ui-image-input-img-block-multiple';
1089 break;
1090
1091 case 2:
1092 $multipleClass = ' ui-image-input-img-block-double';
1093 break;
1094
1095 case 0:
1096 $multipleClass = ' ui-image-input-img-block-empty';
1097 break;
1098
1099 case 1:
1100 default:
1101 $multipleClass = '';
1102 break;
1103 }
1104
1105 if ($imageSrc)
1106 {
1107 $imageSrc = " src=\"{$imageSrc}\"";
1108 }
1109
1110 return <<<HTML
1111<div class="ui-image-input-img-block{$multipleClass}">
1112 <div class="ui-image-input-img-block-inner">
1113 <div class="ui-image-input-img-item">
1114 <img class="ui-image-input-img"{$imageSrc}>
1115 </div>
1116 </div>
1117</div>
1118HTML;
1119 }
1120
1121 protected function getFilePropertyInputName(array $property): string
1122 {
1123 $inputName = $property['name'] ?? '';
1124
1125 if (isset($property['settings']['MULTIPLE']) && $property['settings']['MULTIPLE'] === 'Y')
1126 {
1127 $inputName .= '_n#IND#';
1128 }
1129
1130 return $inputName;
1131 }
1132
1133 protected function getFieldValue(array $field)
1134 {
1135 if ($field['entity'] === 'money')
1136 {
1137 return $this->getMoneyFieldValue($field);
1138 }
1139
1140 if ($field['entity'] === 'barcode')
1141 {
1142 return $this->getBarcodeValue();
1143 }
1144
1145 if (isset($field['originalName']) && $field['originalName'] === 'QUANTITY_COMMON')
1146 {
1147 return $this->getCommonQuantityFieldValue();
1148 }
1149
1150 return parent::getFieldValue($field);
1151 }
1152
1153 protected function getMoneyFieldValue(array $field)
1154 {
1155 if ($field['priceTypeId'] === 'PURCHASING_PRICE')
1156 {
1157 $price = $this->entity->getField('PURCHASING_PRICE');
1158 $currency = $this->entity->getField('PURCHASING_CURRENCY');
1159 }
1160 else
1161 {
1162 $priceItem = $this->entity
1163 ->getPriceCollection()
1164 ->findByGroupId($field['priceTypeId'])
1165 ;
1166 $price = $priceItem ? $priceItem->getPrice() : null;
1167 $currency = $priceItem ? $priceItem->getCurrency() : null;
1168 }
1169
1170 $currency = $currency ?? CurrencyManager::getBaseCurrency();
1171
1172 return \CCurrencyLang::CurrencyFormat($price, $currency, true);
1173 }
1174
1179 protected function getCommonQuantityDescription(): array
1180 {
1181 $commonQuantityName = 'QUANTITY_COMMON';
1182 return [
1183 [
1184 'entity' => 'product',
1185 'name' => $this->prepareFieldName($commonQuantityName),
1186 'originalName' => $commonQuantityName,
1187 'title' => Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_DESCRIPTION_COMMON_QUANTITY_TITLE'),
1188 'type' => 'number',
1189 'editable' => false,
1190 'required' => false,
1191 'placeholders' => null,
1192 'defaultValue' => null,
1193 'optionFlags' => 1, // showAlways
1194 ]
1195 ];
1196 }
1197
1202 protected function getCommonQuantityFieldValue(): float
1203 {
1204 $quantity = (float)$this->entity->getField('QUANTITY');
1205 $quantityReserved = (float)$this->entity->getField('QUANTITY_RESERVED');
1206 return $quantity + $quantityReserved;
1207 }
1208
1209 protected function getBarcodeDescription(): array
1210 {
1211 if (!UseStore::isUsed())
1212 {
1213 return [];
1214 }
1215
1216 $headerName = static::getHeaderName('BARCODE');
1217
1218 return [
1219 [
1220 'entity' => 'barcode',
1221 'name' => static::formatFieldName('BARCODE'),
1222 'title' => $headerName['NAME'],
1223 'type' => 'barcode',
1224 'multiple' => true,
1225 'editable' => $this->isAllowedEditFields(),
1226 'required' => false,
1227 ],
1228 ];
1229 }
1230
1234 protected function getBarcodeValue(): array
1235 {
1236 $barcodes = [];
1237 foreach ($this->entity->getBarcodeCollection() as $barcodeItem)
1238 {
1239 $barcodes[] = [
1240 'ID' => $barcodeItem->getId(),
1241 'BARCODE' => $barcodeItem->getBarcode(),
1242 ];
1243 }
1244
1245 return $barcodes;
1246 }
1247
1248 protected function getElementTableMap(): array
1249 {
1250 return ElementTable::getMap();
1251 }
1252
1253 protected static function getHeaderName(string $code): array
1254 {
1255 $headerName = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_HEADER_NAME_' . $code);
1256 $headerTitle = Loc::getMessage('CATALOG_PRODUCT_CARD_VARIATION_GRID_HEADER_TITLE_' . $code);
1257
1258 return [
1259 'NAME' => $headerName,
1260 'TITLE' => $headerTitle ?? $headerName,
1261 ];
1262 }
1263}
getCatalogEnumFields(string $fieldName)
setGridSettings(string $settingId, $selected, array $currentHeaders=[])
getAdditionalValues(array $values, array $descriptions=null)
getProductFieldHeaders(array $fields, int $defaultWidth)
getColumnValues(bool $allowDefaultValues=true)
getValues(bool $allowDefaultValues=true, array $descriptions=null)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static encode($string, $flags=ENT_COMPAT, $doubleEncode=true)