19use Bitrix\Currency\Integration\IblockMoneyProperty;
20use CIBlockPropertyXmlID;
32 $name = parent::prepareFieldName($name);
34 return static::formatFieldName($name);
44 $name = parent::preparePropertyName($name);
46 return static::formatFieldName($name);
57 $result[
'VAT_INCLUDED'] = [
59 static::formatFieldName(
'VAT_ID'),
60 static::formatFieldName(
'VAT_INCLUDED'),
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'),
65 if (AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_PURCHASE_INFO_VIEW))
67 $result[
'PURCHASING_PRICE_FIELD'] = [
69 static::formatFieldName(
'PURCHASING_PRICE_FIELD'),
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'),
75 $result[
'MEASUREMENTS'] = [
77 static::formatFieldName(
'HEIGHT'),
78 static::formatFieldName(
'LENGTH'),
79 static::formatFieldName(
'WIDTH'),
80 static::formatFieldName(
'WEIGHT'),
82 'TITLE' =>
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_TITLE_MEASUREMENTS'),
83 'DESCRIPTION' =>
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_SETTINGS_DESC_MEASUREMENTS'),
85 $result[
'MEASURE_RATIO'] = [
87 static::formatFieldName(
'MEASURE_RATIO'),
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'),
98 $headers = static::getHeaderIdsBySettingId($settingId);
103 $allUsedColumns = $options->getUsedColumns();
105 if (empty($allUsedColumns))
107 $allUsedColumns = $currentHeaders;
110 if ($selected ===
'true')
114 $currentHeadersInDefaultPosition = array_values(
115 array_intersect($defaultHeaders, array_merge($allUsedColumns,
$headers))
121 $insertPosition = array_search($header, $currentHeadersInDefaultPosition,
true);
122 array_splice($allUsedColumns, $insertPosition, 0, $header);
127 $allUsedColumns = array_diff($allUsedColumns,
$headers);
130 $options->setColumns(implode(
',', $allUsedColumns));
134 return AjaxJson::createSuccess();
150 case 'PURCHASING_PRICE_FIELD':
151 if (AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_PURCHASE_INFO_VIEW))
154 'PURCHASING_PRICE_FIELD',
158 case 'MEASURE_RATIO':
173 $id = static::formatFieldName($id);
183 parent::buildDescriptions(),
191 $description = parent::getPropertyDescription($property);
193 if ($description[
'editable'])
195 switch ($description[
'type'])
200 if (!empty($description[
'data'][
'items']) && is_array($description[
'data'][
'items']))
202 $dropdownItems = $description[
'data'][
'items'];
205 $description[
'editable'] = [
206 'TYPE' => Types::MULTISELECT,
208 'ITEMS' => $dropdownItems,
215 if (!$description[
'required'])
217 $dropdownItems[] =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_NOT_SELECTED');
220 if (!empty($description[
'data'][
'items']) && is_array($description[
'data'][
'items']))
222 foreach ($description[
'data'][
'items'] as $item)
224 $dropdownItems[$item[
'VALUE']] = $item[
'NAME'];
227 $description[
'editable'] = [
228 'TYPE' => Types::DROPDOWN,
229 'items' => $dropdownItems,
233 if ($description[
'multiple'] ===
true && $description[
'propertyCode'] !==
'MORE_PHOTO')
235 $description[
'editable'] =
false;
239 $description[
'editable'] = [
240 'TYPE' => Types::CUSTOM,
241 'NAME' => $description[
'data'][
'edit'] ?? $description[
'name'],
247 $description[
'editable'] = [
'TYPE' => Types::CHECKBOX];
250 $description[
'editable'] = [
'TYPE' => Types::DATE];
253 $description[
'editable'] = [
254 'TYPE' => Types::MONEY,
255 'CURRENCY_LIST' => CurrencyManager::getSymbolList(),
256 'HTML_ENTITY' =>
true,
260 $description[
'editable'] = [
'TYPE' => Types::TEXT];
263 $nonEditableUserTypes = [
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)
278 $description[
'editable'] =
false;
295 $values = $this->getShowedValues($allowDefaultValues);
299 $name = $description[
'id'];
300 if (!isset($values[$name]))
305 $currentValue = $values[$name];
307 switch ($description[
'type'])
311 if (!empty($values[$name]))
317 $values[$name] = (float)($values[$name] ?: 0);
320 if (is_array($currentValue))
325 foreach ($description[
'data'][
'items'] as $item)
330 foreach ($currentValue as $multipleItemValue)
332 $formatted[] = $items[$multipleItemValue];
335 $values[$name] = $formatted;
341 $description[
'id'] === static::formatFieldName(
'ACTIVE')
342 || $description[
'id'] === static::formatFieldName(
'AVAILABLE')
343 || $description[
'id'] === static::formatFieldName(
'VAT_INCLUDED')
346 $code = $currentValue ===
'Y' ?
'YES' :
'NO';
350 $code = ($currentValue !==
'') ?
'YES' :
'NO';
352 $values[$name] =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_VALUE_' . $code);
355 if (isset($description[
'editable'][
'items']))
357 $values[$name] =
HtmlFilter::encode($description[
'editable'][
'items'][$currentValue] ??
'');
360 foreach ($description[
'data'][
'items'] as $item)
362 if ($currentValue === $item[
'VALUE'])
370 $values[$name] = $values[$description[
'data'][
'view']];
376 $currentVat = (int)$values[$name];
380 foreach ($this->getVats() as $vat)
382 if ((
int)$vat[
'ID'] === $currentVat)
384 $values[$name] = htmlspecialcharsbx($vat[
'NAME']);
392 is_array($values[$name])
393 ? array_column($values[$name],
'BARCODE')
397 $values[$name] = $barcodes ? htmlspecialcharsbx(implode(
', ', $barcodes)) :
'';
400 if (isset($description[
'data'][
'isProductProperty']) && $description[
'data'][
'isProductProperty'])
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);
410 if (is_array($values[$name]))
412 $values[$name] = implode(
', ', $values[$name]);
423 $headerName = static::getHeaderName(
'NAME');
427 'id' => static::formatFieldName(
'NAME'),
428 'name' => $headerName[
'NAME'],
429 'title' => $headerName[
'TITLE'],
435 'TYPE' => Types::TEXT,
436 'PLACEHOLDER' =>
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_NEW_VARIATION_PLACEHOLDER_MSGVER_1'),
440 'width' => $defaultWidth,
449 [
'ACTIVE',
'BARCODE',
'QUANTITY_COMMON',
'MEASURE',
'MEASURE_RATIO'],
456 'AVAILABLE',
'VAT_ID',
'VAT_INCLUDED',
'QUANTITY',
'QUANTITY_RESERVED',
457 'QUANTITY_TRACE',
'CAN_BUY_ZERO',
458 'WEIGHT',
'WIDTH',
'LENGTH',
'HEIGHT',
459 'SHOW_COUNTER',
'CODE',
'TIMESTAMP_X',
'MODIFIED_BY',
460 'DATE_CREATE',
'XML_ID',
489 $columns = array_fill_keys(
496 $name = $property[
'name'];
499 $isFile = $property[
'settings'][
'PROPERTY_TYPE'] === PropertyTable::TYPE_FILE;
502 unset($columns[$name]);
506 return array_keys($columns);
513 $numberFields = [
'QUANTITY',
'QUANTITY_RESERVED',
'QUANTITY_COMMON',
'MEASURE_RATIO',
'WEIGHT',
'WIDTH',
'LENGTH',
'HEIGHT'];
514 $numberFields = array_fill_keys($numberFields,
true);
516 $immutableFields = [
'TIMESTAMP_X',
'MODIFIED_BY',
'DATE_CREATE',
'CREATED_USER_NAME',
'AVAILABLE'];
517 $immutableFields = array_fill_keys($immutableFields,
true);
519 $defaultFields = [
'QUANTITY',
'MEASURE',
'NAME',
'BARCODE'];
520 $defaultFields = array_fill_keys($defaultFields,
true);
523 'QUANTITY' =>
'QUANTITY',
524 'AVAILABLE' =>
'AVAILABLE',
527 'MEASURE' =>
'MEASURE',
528 'TIMESTAMP_X' =>
'TIMESTAMP_X',
529 'MODIFIED_BY' =>
'MODIFIED_BY',
530 'DATE_CREATE' =>
'CREATED',
531 'CREATED_USER_NAME' =>
'CREATED_BY',
533 'EXTERNAL_ID' =>
'EXTERNAL_ID',
534 'XML_ID' =>
'XML_ID',
536 'SHOW_COUNTER' =>
'SHOW_COUNTER',
537 'SHOW_COUNTER_START' =>
'SHOW_COUNTER_START',
538 'PREVIEW_PICTURE' =>
'HAS_PREVIEW_PICTURE',
539 'DETAIL_PICTURE' =>
'HAS_DETAIL_PICTURE',
542 foreach ($fields as $code)
544 $type = isset($numberFields[$code]) ?
'number' :
'string';
560 case 'QUANTITY_TRACE':
569 if (!isset($immutableFields[$code]))
572 'TYPE' => Types::TEXT,
579 'TYPE' => Types::CHECKBOX,
585 ? [
'TYPE' => Types::CHECKBOX]
594 $type =
'readOnlyVat';
599 $defaultVat = $this->getDefaultVat();
601 $defaultVat[
'ID'] => $defaultVat[
'NAME'],
604 if ($defaultVat[
'ID'] !== static::NOT_SELECTED_VAT_ID_VALUE && !Loader::includeModule(
'bitrix24'))
606 $vatList[static::NOT_SELECTED_VAT_ID_VALUE] =
Loc::getMessage(
"CATALOG_PRODUCT_CARD_VARIATION_GRID_NOT_SELECTED");
609 foreach ($this->getVats() as $vat)
611 if ($vat[
'RATE'] === $defaultVat[
'RATE'] && $vat[
'EXCLUDE_VAT'] === $defaultVat[
'EXCLUDE_VAT'])
616 $vatList[$vat[
'ID']] = htmlspecialcharsbx($vat[
'NAME']);
619 'TYPE' => Types::DROPDOWN,
627 foreach ($this->getMeasures() as $measure)
629 $measureList[$measure[
'ID']] = htmlspecialcharsbx($measure[
'MEASURE_TITLE']);
630 if (empty($measureList[$measure[
'ID']]))
632 $measureList[$measure[
'ID']] = \CCatalogMeasureClassifier::getMeasureTitle(
639 'TYPE' => Types::DROPDOWN,
640 'items' => $measureList,
645 case 'QUANTITY_RESERVED':
646 case 'QUANTITY_COMMON':
647 if (State::isUsedInventoryManagement())
654 'TYPE' => Types::NUMBER,
660 case 'MEASURE_RATIO':
662 'TYPE' => Types::NUMBER,
669 'TYPE' => Types::CUSTOM,
674 case 'QUANTITY_TRACE':
680 $items[$field[
'VALUE']] = $field[
'NAME'];
684 'TYPE' => Types::DROPDOWN,
692 $code ===
'MODIFIED_BY'
693 ? static::getHeaderName(
'USER_NAME')
694 : static::getHeaderName($code)
697 $sortField = $sortableFields[$code] ??
false;
700 'id' => static::formatFieldName($code),
701 'name' => $headerName[
'NAME'],
702 'title' => $headerName[
'TITLE'],
703 'sort' => $sortField,
705 'headerHint' =>
null,
707 'align' => $type ===
'number' ?
'right' :
'left',
708 'editable' => $editable,
709 'width' => $defaultWidth,
710 'default' => isset($defaultFields[$code]),
729 $property[
'settings'][
'PROPERTY_TYPE'] === PropertyTable::TYPE_STRING
730 && $property[
'settings'][
'USER_TYPE'] ===
'directory'
733 $sortField =
'PROPERTY_' . $property[
'propertyId'];
735 $property[
'multiple']
736 || $property[
'propertyCode'] ===
'CML2_LINK'
737 || $property[
'settings'][
'PROPERTY_TYPE'] === PropertyTable::TYPE_FILE
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,
751 'data' => $property[
'data'],
752 'width' => $isDirectory ? 160 :
null,
753 'editable' => $property[
'editable'],
755 if (!empty($property[
'isEnabledOfferTree']))
757 $header[
'hint'] =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_OFFER_TREE_HINT_MSGVER_1');
761 $property[
'settings'][
'PROPERTY_TYPE'] === PropertyTable::TYPE_FILE
762 && $property[
'multiple'] ===
true
763 && $property[
'propertyCode'] !==
'MORE_PHOTO'
766 $header[
'hint'] =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_FILE_MULTIPLE_HINT_MSGVER_1');
787 $headerName = static::getHeaderName(
'PURCHASING_PRICE');
790 'id' => static::formatFieldName(
'PURCHASING_PRICE_FIELD'),
791 'name' => $headerName[
'NAME'],
792 'title' => $headerName[
'TITLE'],
793 'sort' =>
'PURCHASING_PRICE',
799 'TYPE' => Types::MONEY,
800 'CURRENCY_LIST' => CurrencyManager::getSymbolList(),
801 'HTML_ENTITY' =>
true,
805 'width' => $defaultWidth,
823 $currencyList = CurrencyManager::getSymbolList();
827 $columnName = $priceType[
'NAME_LANG'] ?? $priceType[
'NAME'];
832 'name' => $columnName,
833 'title' => $columnName,
834 'sort' =>
'SCALED_PRICE_'.$priceType[
'ID'],
840 'TYPE' => Types::MONEY,
841 'CURRENCY_LIST' => $currencyList,
842 'HTML_ENTITY' =>
true,
850 :
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_PRICE_EDIT_RESTRICTED_HINT')
852 'base' => $priceType[
'BASE'] ===
'Y',
853 'width' => $defaultWidth,
854 'default' => $priceType[
'BASE'] ===
'Y',
861 private function getShowedValues(
bool $allowDefaultValues =
true): array
863 if (!self::$usedHeaders)
866 self::$usedHeaders = $options->getUsedColumns();
868 if (!self::$usedHeaders)
870 $defaultHeaders = array_filter(
872 static function ($header)
874 return ($header[
'default'] ===
true);
878 self::$usedHeaders = array_column($defaultHeaders,
'id');
883 $filteredDescriptions = array_filter(
887 return in_array($description[
'name'],
$usedHeaders,
true);
891 return parent::getValues($allowDefaultValues, $filteredDescriptions);
896 $values = $this->getShowedValues($allowDefaultValues);
900 $name = $description[
'name'];
902 if (!isset($values[$name]))
907 switch ($description[
'type'])
910 $values[$name] = $values[$description[
'data'][
'view']];
913 $descriptionData = $description[
'data'];
916 'NAME' => $descriptionData[
'amount'],
917 'VALUE' => $values[$descriptionData[
'amount']],
920 'NAME' => $descriptionData[
'currency'][
'name'],
921 'VALUE' => $values[$descriptionData[
'currency'][
'name']],
926 $descriptionData = $description[
'data'] ?? [];
927 $variants = $descriptionData[
'items'] ?? [];
928 foreach ($variants as $variant)
930 if ($values[$name] === $variant[
'ID'])
932 $values[$name] = $variant[
'NAME'];
961 $purchacingPricePrefix = self::GRID_FIELD_PREFIX .
'PURCHASING_PRICE';
965 $name = $description[
'name'];
966 $value = $dirtyValues[$name] ??
null;
972 if (isset($description[
'propertyId']))
974 $type = $description[
'type'] ??
null;
975 if ($type ===
'multilist' && empty($value))
980 $propertyId = (int)$description[
'propertyId'];
981 $result[
'PROPERTIES'][$propertyId] = $value;
983 elseif (mb_strpos($name, $pricePrefix) === 0)
987 && isset($value[
'PRICE'][
'NAME'], $value[
'PRICE'][
'VALUE'], $value[
'CURRENCY'][
'VALUE'])
990 $priceGroupId = str_replace($pricePrefix,
'', $value[
'PRICE'][
'NAME']);
993 $result[
'PRICES'][$priceGroupId] = [
994 'PRICE' => (float)$value[
'PRICE'][
'VALUE'],
995 'CURRENCY' => (
string)$value[
'CURRENCY'][
'VALUE'],
1000 elseif (mb_strpos($name, $purchacingPricePrefix) === 0)
1002 if (is_array($value) && isset($value[
'PRICE'][
'VALUE'], $value[
'CURRENCY'][
'VALUE']))
1004 $result[
'PURCHASING_PRICE'] = (float)$value[
'PRICE'][
'VALUE'];
1005 $result[
'PURCHASING_CURRENCY'] = (string)$value[
'CURRENCY'][
'VALUE'];
1008 elseif (isset($description[
'originalName']))
1010 $name = $description[
'originalName'];
1011 $result[$name] = $value;
1013 elseif (isset($description[
'entity']) && $description[
'entity'] ===
'barcode')
1015 if (is_array($value))
1017 array_push($result[
'BARCODES'], ...$value);
1021 $result[
'BARCODES'][] = $value;
1024 elseif (isset($description[
'entity']) && $description[
'entity'] ===
'measure_ratio')
1026 $result[
'MEASURE_RATIO'] = $value;
1035 $additionalValues = parent::getAdditionalValues($values,
$descriptions);
1037 $numberFields = [
'MEASURE_RATIO',
'QUANTITY'];
1038 foreach ($numberFields as $fieldName)
1041 if (isset($values[$fieldName]) && $values[$fieldName] == 0)
1043 $additionalValues[$fieldName] =
null;
1047 return $additionalValues;
1052 $settings = parent::getPropertySettings($property);
1053 $settings[
'GRID_MODE'] =
true;
1063 if (!empty($value) && !is_array($value))
1068 if (is_array($value))
1070 $fileCount = min(count($value), 3);
1071 $value = reset($value);
1078 $image = \CFile::GetFileArray($value);
1081 $imageSrc = $image[
'SRC'];
1088 $multipleClass =
' ui-image-input-img-block-multiple';
1092 $multipleClass =
' ui-image-input-img-block-double';
1096 $multipleClass =
' ui-image-input-img-block-empty';
1101 $multipleClass =
'';
1107 $imageSrc =
" src=\"{$imageSrc}\"";
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}>
1123 $inputName = $property[
'name'] ??
'';
1125 if (isset($property[
'settings'][
'MULTIPLE']) && $property[
'settings'][
'MULTIPLE'] ===
'Y')
1127 $inputName .=
'_n#IND#';
1135 if ($field[
'entity'] ===
'money')
1140 if ($field[
'entity'] ===
'barcode')
1145 if (isset($field[
'originalName']) && $field[
'originalName'] ===
'QUANTITY_COMMON')
1150 return parent::getFieldValue($field);
1155 if ($field[
'priceTypeId'] ===
'PURCHASING_PRICE')
1157 $price = $this->entity->getField(
'PURCHASING_PRICE');
1158 $currency = $this->entity->getField(
'PURCHASING_CURRENCY');
1162 $priceItem = $this->entity
1163 ->getPriceCollection()
1164 ->findByGroupId($field[
'priceTypeId'])
1166 $price = $priceItem ? $priceItem->getPrice() :
null;
1167 $currency = $priceItem ? $priceItem->getCurrency() :
null;
1170 $currency = $currency ?? CurrencyManager::getBaseCurrency();
1172 return \CCurrencyLang::CurrencyFormat($price, $currency,
true);
1181 $commonQuantityName =
'QUANTITY_COMMON';
1184 'entity' =>
'product',
1186 'originalName' => $commonQuantityName,
1187 'title' =>
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_DESCRIPTION_COMMON_QUANTITY_TITLE'),
1189 'editable' =>
false,
1190 'required' =>
false,
1191 'placeholders' =>
null,
1192 'defaultValue' =>
null,
1204 $quantity = (float)$this->entity->getField(
'QUANTITY');
1205 $quantityReserved = (float)$this->entity->getField(
'QUANTITY_RESERVED');
1206 return $quantity + $quantityReserved;
1216 $headerName = static::getHeaderName(
'BARCODE');
1220 'entity' =>
'barcode',
1221 'name' => static::formatFieldName(
'BARCODE'),
1222 'title' => $headerName[
'NAME'],
1223 'type' =>
'barcode',
1226 'required' =>
false,
1237 foreach ($this->entity->getBarcodeCollection() as $barcodeItem)
1240 'ID' => $barcodeItem->getId(),
1241 'BARCODE' => $barcodeItem->getBarcode(),
1255 $headerName =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_HEADER_NAME_' . $code);
1256 $headerTitle =
Loc::getMessage(
'CATALOG_PRODUCT_CARD_VARIATION_GRID_HEADER_TITLE_' . $code);
1259 'NAME' => $headerName,
1260 'TITLE' => $headerTitle ?? $headerName,
static getMessage($code, $replace=null, $language=null)
static encode($string, $flags=ENT_COMPAT, $doubleEncode=true)