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