%PDF- %PDF- 403WebShell
403Webshell
Server IP : 37.220.80.31  /  Your IP : 3.15.4.52
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux 3051455-guretool.twc1.net 5.15.0-107-generic #117-Ubuntu SMP Fri Apr 26 12:26:49 UTC 2024 x86_64
User : www-root ( 1010)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/www-root/data/www/dev.artlot24.ru/bitrix/components/bitrix/catalog.productcard.details/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/www-root/data/www/dev.artlot24.ru/bitrix/components/bitrix/catalog.productcard.details/class.php
<?php

use Bitrix\Catalog\Component\BaseForm;
use Bitrix\Catalog\Component\GridVariationForm;
use Bitrix\Catalog\Component\ProductForm;
use Bitrix\Catalog\ProductTable;
use Bitrix\Catalog\v2\BaseIblockElementEntity;
use Bitrix\Catalog\v2\IoC\Dependency;
use Bitrix\Catalog\v2\IoC\ServiceContainer;
use Bitrix\Catalog\v2\Product\BaseProduct;
use Bitrix\Catalog\v2\Sku\BaseSku;
use Bitrix\Currency\Integration\IblockMoneyProperty;
use Bitrix\Iblock\PropertyTable;
use Bitrix\Iblock\Model\PropertyFeature;
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Entity\AddResult;
use Bitrix\Main\Error;
use Bitrix\Main\Errorable;
use Bitrix\Main\ErrorableImplementation;
use Bitrix\Main\ErrorCollection;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Text\HtmlFilter;
use Bitrix\UI\Toolbar\Facade\Toolbar;

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
	die();
}

class CatalogProductDetailsComponent
	extends \CBitrixComponent
	implements Controllerable, Errorable
{
	use ErrorableImplementation;

	private $iblockId;
	private $productId;
	/** @var \Bitrix\Catalog\Component\ProductForm */
	private $form;
	/** @var \Bitrix\Catalog\v2\Product\BaseProduct */
	private $product;
	/** @var \Bitrix\Catalog\v2\Product\BaseProduct */
	private $copyProduct;

	public function __construct($component = null)
	{
		parent::__construct($component);
		$this->errorCollection = new ErrorCollection();
	}

	protected function showErrors()
	{
		foreach ($this->getErrors() as $error)
		{
			ShowError($error);
		}
	}

	public function configureActions()
	{
		return [];
	}

	protected function listKeysSignedParameters()
	{
		return [
			'PRODUCT_ID',
			'IBLOCK_ID',
			'PATH_TO',
			'COPY_PRODUCT_ID',
		];
	}

	public function onPrepareComponentParams($params)
	{
		if (isset($params['PRODUCT_ID']))
		{
			$this->setProductId($params['PRODUCT_ID']);
		}

		if (isset($params['IBLOCK_ID']))
		{
			$this->setIblockId($params['IBLOCK_ID']);
		}

		$externalFields = $this->request->get('external_fields') ?? [];
		if (!empty($externalFields) && is_array($externalFields))
		{
			$params['EXTERNAL_FIELDS'] = $externalFields;
		}

		return parent::onPrepareComponentParams($params);
	}

	public function executeComponent()
	{
		if ($this->checkModules() && $this->checkPermissions() && $this->checkRequiredParameters())
		{
			$product = $this->getProduct();

			if ($product)
			{
				$this->initializeExternalProductFields($product);

				$this->initializeProductFields($product);
				$this->placePageTitle($product);

				$this->errorCollection->clear();
				$this->includeComponentTemplate();
			}
		}

		$this->showErrors();
	}

	protected function checkModules()
	{
		if (!Loader::includeModule('catalog'))
		{
			$this->errorCollection[] = new \Bitrix\Main\Error('Module "catalog" is not installed.');

			return false;
		}

		return true;
	}

	protected function checkPermissions(): bool
	{
		if (!\Bitrix\Catalog\Config\State::isProductCardSliderEnabled())
		{
			$this->errorCollection[] = new \Bitrix\Main\Error('New product card feature disabled.');

			return false;
		}

		return true;
	}

	protected function checkRequiredParameters()
	{
		if (!$this->hasIblockId())
		{
			$this->errorCollection[] = new \Bitrix\Main\Error('Iblock id not found.');

			return false;
		}

		return true;
	}

	private function getApplication()
	{
		global $APPLICATION;

		return $APPLICATION;
	}

	protected function setIblockId(int $iblockId): self
	{
		$this->iblockId = $iblockId;

		return $this;
	}

	protected function getIblockId(): int
	{
		return $this->iblockId;
	}

	private function hasIblockId(): bool
	{
		return $this->getIblockId() > 0;
	}

	protected function setProductId(int $productId): self
	{
		$this->productId = $productId;

		return $this;
	}

	protected function getProductId(): int
	{
		return $this->productId;
	}

	private function hasProductId(): bool
	{
		return $this->getProductId() > 0;
	}

	protected function placePageTitle(BaseProduct $product): void
	{
		$title = $product->isNew() ? Loc::getMessage('CPD_NEW_PRODUCT_TITLE') : HtmlFilter::encode($product->getName());
		$this->getApplication()->setTitle($title);
	}

	protected function createProduct()
	{
		$product = null;
		$productFactory = ServiceContainer::getProductFactory($this->getIblockId());

		if ($productFactory)
		{
			/** @var BaseProduct $product */
			$product = $productFactory
				->createEntity()
				->setActive(true)
			;
		}

		if ($product === null)
		{
			$this->errorCollection[] = new \Bitrix\Main\Error(sprintf(
				'Could not create product for iblock {%s}.', $this->getIblockId()
			));
		}

		$copyProductId = (int)($this->arParams['COPY_PRODUCT_ID'] ?? 0);
		if ($copyProductId > 0)
		{
			$this->copyProduct = $this->loadProduct($copyProductId);
			if ($this->copyProduct)
			{
				$fields = $this->copyProduct->getFields();
				unset($fields['ID'], $fields['IBLOCK_ID'], $fields['PREVIEW_PICTURE'], $fields['DETAIL_PICTURE']);
				$product->setFields($fields);
				$product->getSectionCollection()->setValues(
					$this->copyProduct->getSectionCollection()->getValues()
				);

				$propertyValues = [];
				foreach ($this->copyProduct->getPropertyCollection() as $property)
				{
					$propertyValues[$property->getId()] = $property->getPropertyValueCollection()->toArray();
				}
				$product->getPropertyCollection()->setValues($propertyValues);
			}
		}
		else
		{
			$iblockSectionId = $this->request->get('IBLOCK_SECTION_ID');
			if (!empty($iblockSectionId))
			{
				$product->getSectionCollection()->setValues([$iblockSectionId]);
			}
		}

		return $product;
	}

	protected function loadProduct($productId): ?BaseProduct
	{
		$product = null;

		$repositoryFacade = ServiceContainer::getRepositoryFacade();
		$variation = $repositoryFacade->loadVariation($productId);

		if ($variation === null)
		{
			Toolbar::deleteFavoriteStar();

			global $APPLICATION;
			$APPLICATION->IncludeComponent(
				"bitrix:catalog.notfounderror",
				"",
				[
					'ERROR_MESSAGE' => Loc::getMessage('CPD_NOT_FOUND_ERROR_TITLE'),
				]
			);

			return null;
		}

		return $variation->getParent();
	}

	protected function getProduct(): ?BaseProduct
	{
		if ($this->product === null)
		{
			if ($this->hasProductId())
			{
				$this->product = $this->loadProduct($this->getProductId());
			}
			else
			{
				$this->product = $this->createProduct();
			}
		}

		return $this->product;
	}

	protected function initializeExternalProductFields(BaseProduct $product): void
	{
		$fields = $this->arParams['EXTERNAL_FIELDS'] ?? [];

		if (empty($fields))
		{
			return;
		}

		$product->setFields($fields);

		if ($product->getSkuCollection()->isEmpty())
		{
			$product->getSkuCollection()->create();
		}

		foreach ($product->getSkuCollection() as $sku)
		{
			$sku->setFields($fields);

			if (isset($fields['PRICE']) || isset($fields['CURRENCY']))
			{
				$sku->getPriceCollection()->setValues([
					'BASE' => [
						'PRICE' => $fields['PRICE'] ?? null,
						'CURRENCY' => $fields['CURRENCY'] ?? null,
					],
				])
				;
				break;
			}
		}
	}

	protected function initializeProductFields(BaseProduct $product): void
	{
		$this->arResult['PRODUCT_ENTITY'] = $product;
		$this->arResult['PRODUCT_FIELDS'] = $product->getFields();
		$this->arResult['SIMPLE_PRODUCT'] = $product->isSimple();
		$this->arResult['IS_NEW_PRODUCT'] = $product->isNew();

		$this->arResult['UI_ENTITY_FIELDS'] = $this->getForm()->getDescriptions();
		$this->arResult['UI_ENTITY_CONFIG'] = $this->getForm()->getConfig();

		$this->arResult['UI_ENTITY_DATA'] = $this->getForm()->getValues($product->isNew());

		$this->arResult['UI_ENTITY_CONTROLLERS'] = $this->getForm()->getControllers();
		$this->arResult['UI_CREATION_PROPERTY_URL'] = $this->getCreationPropertyUrl();
		$this->arResult['UI_CREATION_SKU_PROPERTY_URL'] = $this->getCreationSkuPropertyLink();

		$this->arResult['VARIATION_GRID_ID'] = $this->getForm()->getVariationGridId();
		$this->arResult['CARD_SETTINGS'] = $this->getForm()->getCardSettings();
	}

	protected function getProductDetailUrl(): string
	{
		$productDetailsTemplate = (string)($this->arParams['PATH_TO']['PRODUCT_DETAILS'] ?? '');

		if ($productDetailsTemplate === '')
		{
			return '';
		}

		return str_replace(
			['#IBLOCK_ID#', '#PRODUCT_ID#'],
			[$this->getIblockId(), $this->getProductId()],
			$this->arParams['PATH_TO']['PRODUCT_DETAILS']
		);
	}

	protected function getCreationPropertyUrl(): string
	{
		return "/shop/settings/iblock_edit_property/?lang=".LANGUAGE_ID."&IBLOCK_ID=".urlencode($this->getIblockId())."&ID=n0&publicSidePanel=Y&newProductCard=Y";
	}

	protected function getCreationSkuPropertyLink()
	{
		return str_replace(
			'#IBLOCK_ID#',
			$this->getForm()->getVariationIblockId(),
			$this->arParams['PATH_TO']['PROPERTY_CREATOR']
		);
	}

	private function parseIsSkuProduct(array $fields, BaseProduct $product): bool
	{
		$skuGridId = $this->getForm()->getVariationGridId();
		$skuFields = $fields[$skuGridId] ?? [];

		if (count($skuFields) > 1)
		{
			return true;
		}

		foreach ($skuFields as $id => $sku)
		{
			if (is_numeric($id) && $this->getProductId() !== $id)
			{
				return true;
			}

			if (!is_numeric($id) && !$product->isNew())
			{
				return true;
			}

			$propertyPrefix = GridVariationForm::preparePropertyName();
			$morePhotoName = GridVariationForm::preparePropertyName(BaseForm::MORE_PHOTO);

			foreach ($sku as $name => $value)
			{
				if (
					!empty($value)
					&& $name !== $morePhotoName
					&& mb_substr($name, -7) !== '_custom'
					&& mb_strpos($name, $propertyPrefix) === 0
				)
				{
					return true;
				}
			}
		}

		return false;
	}

	private function parseSkuFields(&$fields)
	{
		$skuGridId = $this->getForm()->getVariationGridId();

		$skuFields = $fields[$skuGridId] ?? [];
		unset($fields['ID'], $fields[$skuGridId]);

		foreach ($fields as $name => $field)
		{
			if (mb_strpos($name, BaseForm::GRID_FIELD_PREFIX) === 0)
			{
				unset($fields[$name]);
			}
		}

		$prefixLength = mb_strlen(BaseForm::GRID_FIELD_PREFIX);

		$oldProductName = isset($fields['NAME']) ? $this->product->getName() : null;
		foreach ($skuFields as $id => $sku)
		{
			foreach ($sku as $name => $value)
			{
				if (mb_strpos($name, BaseForm::GRID_FIELD_PREFIX) === 0)
				{
					unset($skuFields[$id][$name]);
					$originalName = mb_substr($name, $prefixLength);

					// It is necessary that the unchanged default name of variation does not remove new one,
					// which will be setted in BaseProduct::setField
					if ($originalName === 'NAME' && $oldProductName === $value)
					{
						continue;
					}

					$skuFields[$id][$originalName] = $value;
				}
			}
		}

		return $skuFields;
	}

	private function parseSectionFields(&$fields)
	{
		$sectionFields = $fields['IBLOCK_SECTION'] ?? null;
		unset($fields['IBLOCK_SECTION']);

		return $sectionFields;
	}

	private function prepareSkuPictureFields(&$fields)
	{
		$pictureFieldNames = ['DETAIL_PICTURE', 'PREVIEW_PICTURE'];

		foreach ($pictureFieldNames as $name)
		{
			$customName = $name.'_custom';

			if (!empty($fields[$name.'_custom']['isFile']))
			{
				unset($fields[$name.'_custom']['isFile']);

				$fileProps = $this->prepareDetailPictureFromGrid($fields[$customName]);

				if ($fileProps)
				{
					$fields[$name] = $fileProps;
				}

				unset($fields[$customName]);
			}
		}
	}

	private function parsePropertyFields(&$fields)
	{
		$propertyFields = [];
		$prefixLength = mb_strlen(BaseForm::PROPERTY_FIELD_PREFIX);
		$propertyCollection = $this->product->getPropertyCollection();

		foreach ($fields as $name => $field)
		{
			if (
				mb_strpos($name, BaseForm::PROPERTY_FIELD_PREFIX) === 0
				&& mb_substr($name, -7) !== '_custom'
			)
			{
				$index = mb_substr($name, $prefixLength);

				$property = $propertyCollection->findById((int)$index);
				if ($property === null)
				{
					$property = $propertyCollection->findByCode($index);
				}

				$propertyType = null;
				if ($property !== null)
				{
					$propertyType = $property->getPropertyType();
				}

				// grid file properties
				if (!empty($fields[$name.'_custom']['isFile']))
				{
					unset($fields[$name.'_custom']['isFile']);
					$field = $this->prepareFilePropertyFromGrid($fields[$name.'_custom']);
					unset($fields[$name.'_custom']);
				}
				// editor file properties
				elseif ($propertyType === PropertyTable::TYPE_FILE)
				{
					$descriptions = $fields[$name.'_descr'] ?? [];
					$deleted = $fields[$name.'_del'] ?? [];
					$field = $this->prepareFilePropertyFromEditor($fields[$name], $descriptions, $deleted);
					if (empty($field))
					{
						$field = '';
					}
					unset($fields[$name.'_descr']);
				}
				elseif (Loader::includeModule('currency'))
				{
					if (isset($field['AMOUNT'], $field['CURRENCY']))
					{
						if (is_array($field['AMOUNT']) && is_array($field['CURRENCY']))
						{
							$moneyValues = [];
							$valuesCount = count($field['AMOUNT']);
							for ($valueIndex = 0; $valueIndex < $valuesCount; $valueIndex++)
							{
								$moneyValues[] = IblockMoneyProperty::getUnitedValue(
									$field['AMOUNT'][$valueIndex],
									$field['CURRENCY'][$valueIndex]
								);
							}
							$field = $moneyValues;
						}
						else
						{
							$field = IblockMoneyProperty::getUnitedValue($field['AMOUNT'], $field['CURRENCY']);
						}
					}
					elseif (isset($field['PRICE']['VALUE'], $field['CURRENCY']['VALUE']))
					{
						$field = IblockMoneyProperty::getUnitedValue(
							$field['PRICE']['VALUE'],
							$field['CURRENCY']['VALUE']
						);
					}
				}

				$propertyFields[$index] = $field;

				unset($fields[$name]);
			}
		}

		return $propertyFields;
	}

	private function prepareDescriptionFields(&$fields): void
	{
		$descriptionFieldNames = ['DETAIL_TEXT', 'PREVIEW_TEXT'];

		foreach ($descriptionFieldNames as $name)
		{
			if (isset($fields[$name]) && is_string($fields[$name]))
			{
				$fields[$name] = $this->sanitize(htmlspecialchars_decode($fields[$name]));
				$fields[$name.'_TYPE'] = 'html';
			}
		}
	}

	private function sanitize(string $html): string
	{
		static $sanitizer = null;

		if ($sanitizer === null)
		{
			$sanitizer = new \CBXSanitizer;
			$sanitizer->setLevel(\CBXSanitizer::SECURE_LEVEL_LOW);
		}

		return $sanitizer->sanitizeHtml($html);
	}

	private function preparePictureFields(&$fields): void
	{
		$pictureFieldNames = ['DETAIL_PICTURE', 'PREVIEW_PICTURE'];

		foreach ($pictureFieldNames as $name)
		{
			if (isset($fields[$name]))
			{
				$description = $fields[$name.'_descr'] ?? null;
				$delete = $fields[$name.'_del'] ?? false;
				$fields[$name] = \CIBlock::makeFileArray($fields[$name], $delete, $description);
				unset($fields[$name.'_descr'], $fields[$name.'_del']);
			}
		}
	}

	private function checkCompatiblePictureFields(BaseIblockElementEntity $entity, array &$propertyFields): void
	{
		if (!isset($propertyFields[BaseForm::MORE_PHOTO]) || !is_array($propertyFields[BaseForm::MORE_PHOTO]))
		{
			return;
		}

		$previewPicture = $entity->getField('PREVIEW_PICTURE');
		$detailPicture = $entity->getField('DETAIL_PICTURE');

		if ($previewPicture || $detailPicture)
		{
			$previewFound = false;
			$detailFound = false;

			foreach ($propertyFields[BaseForm::MORE_PHOTO] as $key => $propertyField)
			{
				if (is_numeric($propertyField['VALUE']))
				{
					$value = (int)$propertyField['VALUE'];

					if ($value === $previewPicture)
					{
						$previewFound = true;
						unset($propertyFields[BaseForm::MORE_PHOTO][$key]);
					}

					if ($value === $detailPicture)
					{
						$detailFound = true;
						unset($propertyFields[BaseForm::MORE_PHOTO][$key]);
					}

					if ($previewFound && $detailFound)
					{
						break;
					}
				}
			}

			if ($previewPicture && !$previewFound)
			{
				$entity->setField('PREVIEW_PICTURE', \CIBlock::makeFileArray(null, true));
			}

			if ($detailPicture && !$detailFound)
			{
				$entity->setField('DETAIL_PICTURE', \CIBlock::makeFileArray(null, true));
			}
		}
	}

	private function prepareProductCode(&$fields): void
	{
		$productName = $fields['NAME'] ?? '';

		if ($productName !== '')
		{
			$fields['CODE'] = (new CIBlockElement())->generateMnemonicCode($productName, $this->getIblockId());
		}
	}

	private function prepareDetailPictureFromGrid($propertyFields)
	{
		$fileProp = [];

		foreach ($propertyFields as $key => $value)
		{
			if (isset($propertyFields[$key.'_descr']) && (is_array($value) || is_numeric($value)))
			{
				$description = $propertyFields[$key.'_descr'] ?? null;
				$delete = $propertyFields[$key.'_del'] ?? false;
				$fileProp[] = \CIBlock::makeFilePropArray($value, $delete, $description);
			}
		}

		if (empty($fileProp))
		{
			$fileProp[] = \CIBlock::makeFilePropArray([], true);
		}

		return reset($fileProp)['VALUE'] ?? null;
	}

	private function prepareFilePropertyFromGrid($propertyFields)
	{
		$fileProp = [];
		$counter = 0;

		foreach ($propertyFields as $key => $value)
		{
			$description = $propertyFields[$key.'_descr'] ?? null;

			if (is_array($value))
			{
				$fileProp[] = \CIBlock::makeFilePropArray($value, false, $description);
			}
			elseif (is_numeric($value))
			{
				if ($this->product->isNew())
				{
					$fileArray = CIBlock::makeFileArray(
						$value,
						false,
						$description,
						['allow_file_id' => true]
					);
					$fileArray['COPY_FILE'] = 'Y';
					$fileProp['n'.$counter++] = $fileArray;
				}
				elseif ($description !== null)
				{
					$fileProp[] = [
						'VALUE' => $value,
						'DESCRIPTION' => $description,
					];
				}
			}
		}

		return $fileProp;
	}

	private function prepareFilePropertyFromEditor($propertyFields, $descriptions, $deleted)
	{
		if ($deleted !== null && !is_array($deleted))
		{
			$deleted = [$deleted];
			$propertyFields = [$propertyFields];
			$descriptions = [$descriptions];
		}

		if ($descriptions !== null && !is_array($descriptions))
		{
			$descriptions = [$descriptions];
			$propertyFields = [$propertyFields];
		}

		if (!is_array($propertyFields))
		{
			$propertyFields = [$propertyFields];
		}

		if ($deleted)
		{
			foreach ($deleted as $key => $value)
			{
				if ($value === 'Y')
				{
					unset($propertyFields[$key], $descriptions[$key]);
				}
				else
				{
					$propertyValueKey = array_search($value, $propertyFields, true);
					if ($propertyValueKey !== false)
					{
						unset($propertyFields[$propertyValueKey]);
					}

					$propertyDescriptionKey = array_search($value, $descriptions, true);
					if ($propertyDescriptionKey !== false)
					{
						unset($descriptions[$propertyDescriptionKey]);
					}
				}
			}
		}

		if (empty($propertyFields))
		{
			return null;
		}

		foreach ($propertyFields as $key => $value)
		{
			$propertyFields[$key.'_descr'] = $descriptions[$key] ?? '';
		}

		return $this->prepareFilePropertyFromGrid($propertyFields);
	}

	private function parsePriceFields(&$fields)
	{
		$priceFields = [];

		foreach ($fields as $name => $value)
		{
			if (mb_strpos($name, BaseForm::PRICE_FIELD_PREFIX) === 0)
			{
				$index = str_replace(BaseForm::PRICE_FIELD_PREFIX, '', $name);
				if (!empty($index))
				{
					$priceFields[$index]['PRICE'] = $value;
				}

				unset($fields[$name]);
			}

			if (mb_strpos($name, BaseForm::CURRENCY_FIELD_PREFIX) === 0)
			{
				$index = str_replace(BaseForm::CURRENCY_FIELD_PREFIX, '', $name);
				if (!empty($index))
				{
					$priceFields[$index]['CURRENCY'] = $value;
				}

				unset($fields[$name]);
			}
		}

		return $priceFields;
	}

	private function parseMeasureRatioFields(&$fields)
	{
		$measureRatio = $fields['MEASURE_RATIO'] ?? null;
		unset($fields['MEASURE_RATIO']);

		return $measureRatio;
	}

	private function prepareFileFields(&$fields)
	{
		$files = $_FILES['data'];
		if (!empty($files))
		{
			CFile::ConvertFilesToPost($files, $fields);
			foreach ($fields as $key => $field)
			{
				if (is_array($field) && array_key_exists('FILE', $field))
				{
					$fields[$key] = [
						$fields[$key],
					];
				}
			}
		}
	}

	public function saveAction()
	{
		$fields = $this->request->get('data') ?: [];

		$this->prepareFileFields($fields);

		if (
			empty($fields)
			|| !$this->checkModules()
			|| !$this->checkPermissions()
			|| !$this->checkRequiredParameters()
		)
		{
			return null;
		}

		$product = $this->getProduct();

		if ($product === null)
		{
			return null;
		}

		$isSkuProduct = $this->parseIsSkuProduct($fields, $product);
		if (!$isSkuProduct && $product->isNew())
		{
			$product->setType(ProductTable::TYPE_PRODUCT);
		}

		$skuFields = $this->parseSkuFields($fields);
		$propertyFields = $this->parsePropertyFields($fields);
		$this->checkCompatiblePictureFields($product, $propertyFields);
		$sectionFields = $this->parseSectionFields($fields);

		$convertedSku = null;
		if ($isSkuProduct && $product->isSimple())
		{
			$convertedSku = $this->convertSimpleProductToSku($product);
		}

		$this->prepareDescriptionFields($fields);
		$this->preparePictureFields($fields);

		// if (
		// 	// (!isset($fields['CODE']) || $fields['CODE'] === '')
		// 	// && $product->isNew()
		// )
		{
			$this->prepareProductCode($fields);
		}

		$product->setFields($fields);

		if ($sectionFields !== null)
		{
			$product->getSectionCollection()->setValues($sectionFields);
		}

		if (!empty($propertyFields))
		{
			$product->getPropertyCollection()->setValues($propertyFields);
		}

		$notifyAboutNewVariation = false;

		if (!empty($skuFields))
		{
			$skuFields = array_reverse($skuFields, true);

			foreach ($skuFields as $skuId => $skuField)
			{
				$sku = null;

				if (is_numeric($skuId))
				{
					$skuId = (int)$skuId;

					// probably simple sku came with product id
					if ($convertedSku)
					{
						$sku = $convertedSku;
					}
					else
					{
						/** @var \Bitrix\Catalog\v2\Sku\BaseSku $sku */
						$sku = $product->getSkuCollection()->findById($skuId);
					}
				}
				elseif ($product->isNew() && $product->isSimple())
				{
					$sku = $product->getSkuCollection()->getIterator()[0] ?? null;
				}

				if ($sku === null)
				{
					$notifyAboutNewVariation = true;

					$sku = $this->createSkuItem($product, (int)$skuField['COPY_SKU_ID']);
				}

				$this->fillSku($sku, $skuField);
			}
		}

		return $this->saveInternal($product, $notifyAboutNewVariation);
	}

	private function convertSimpleProductToSku(BaseProduct $product): ?BaseSku
	{
		/** @var \Bitrix\Catalog\v2\Converter\ProductConverter $converter */
		$converter = ServiceContainer::get(Dependency::PRODUCT_CONVERTER);
		$result = $converter->convert($product, $converter::SKU_PRODUCT);
		if (!$result->isSuccess())
		{
			return null;
		}

		return $result->getData()['CONVERTED_SKU'] ?? null;
	}

	private function fillSku(BaseSku $sku, array $fields = []): void
	{
		$product = $sku->getParent();
		$this->prepareSkuPictureFields($fields);
		$skuPropertyFields = $this->parsePropertyFields($fields);
		$this->checkCompatiblePictureFields($sku, $skuPropertyFields);
		$skuPriceFields = $this->parsePriceFields($fields);
		$skuMeasureRatioField = $this->parseMeasureRatioFields($fields);

		if (!empty($fields))
		{
			if (isset($fields['NAME']) && $fields['NAME'] === '' && $product)
			{
				$fields['NAME'] = $product->getName();
			}

			if (isset($fields['PURCHASING_PRICE']) && $fields['PURCHASING_PRICE'] === '')
			{
				$fields['PURCHASING_PRICE'] = null;
			}

			$sku->setFields($fields);
		}

		if (!empty($skuPropertyFields))
		{
			// fix: two MORE_PHOTO fields overwrite each other (editor and grid)
			if (
				isset($propertyFields[BaseForm::MORE_PHOTO], $skuPropertyFields[BaseForm::MORE_PHOTO])
				&& $product
				&& $product->isSimple()
			)
			{
				$skuPropertyFields[BaseForm::MORE_PHOTO] = array_merge(
					$propertyFields[BaseForm::MORE_PHOTO],
					$skuPropertyFields[BaseForm::MORE_PHOTO]
				);
			}

			$sku->getPropertyCollection()->setValues($skuPropertyFields);
		}

		if (!empty($skuPriceFields))
		{
			$sku->getPriceCollection()->setValues($skuPriceFields);
		}

		if (!empty($skuMeasureRatioField))
		{
			$sku->getMeasureRatioCollection()->setDefault($skuMeasureRatioField);
		}
	}

	private function createSkuItem(BaseProduct $product, int $copySkuId = null): BaseSku
	{
		/** @var BaseSku $sku */
		$sku = $product->getSkuCollection()
			->create()
			->setActive(true)
		;

		if ($this->copyProduct && $copySkuId > 0)
		{
			$copySku = $this->copyProduct->getSkuCollection()->findById($copySkuId);
			if ($copySku)
			{
				$fields = $copySku->getFields();
				unset($fields['ID'], $fields['IBLOCK_ID'], $fields['PREVIEW_PICTURE'], $fields['DETAIL_PICTURE']);
				$sku->setFields($fields);

				$propertyValues = [];
				foreach ($copySku->getPropertyCollection() as $property)
				{
					$propertyValues[$property->getId()] = $property->getPropertyValueCollection()->toArray();
				}

				if (!empty($propertyValues))
				{
					$sku->getPropertyCollection()->setValues($propertyValues);
				}

				$sku->getPriceCollection()->setValues($copySku->getPriceCollection()->getValues());

				$measureRatio = $copySku->getMeasureRatioCollection()->findDefault();
				if ($measureRatio)
				{
					$sku->getMeasureRatioCollection()->setDefault($measureRatio->getRatio());
				}
			}
		}

		return $sku;
	}

	private function saveInternal(BaseProduct $product, bool $notifyAboutNewVariation = false): ?array
	{
		global $DB;
		$DB->StartTransaction();

		$result = $product->save();

		if (!$result->isSuccess())
		{
			$DB->Rollback();
			$this->errorCollection->add($result->getErrors());

			return null;
		}

		$DB->Commit();

		$redirect = !$this->hasProductId();
		$this->setProductId($product->getId());

		$response = [
			'ENTITY_ID' => $product->getId(),
			'ENTITY_DATA' => $this->getForm()->getValues(false),
			'NOTIFY_ABOUT_NEW_VARIATION' => $redirect ? false : $notifyAboutNewVariation,
			'IS_SIMPLE_PRODUCT' => $product->isSimple(),
		];

		if ($redirect)
		{
			$response['REDIRECT_URL'] = $this->getProductDetailUrl();
		}

		return $response;
	}

	public function refreshLinkedPropertiesAction(array $sectionIds = []): ?array
	{
		if ($this->checkModules() && $this->checkPermissions() && $this->checkRequiredParameters())
		{
			$product = $this->getProduct();

			if ($product)
			{
				$product->getSectionCollection()->setValues($sectionIds);
			}

			return [
				'ENTITY_FIELDS' => $this->getForm()->getIblockPropertiesDescriptions(),
				'ENTITY_VALUES' => $this->getForm()->getValues(),
			];
		}

		return null;
	}

	public function addPropertyAction(array $fields = []): ?array
	{
		if ($this->checkModules() && $this->checkPermissions() && $this->checkRequiredParameters())
		{
			$fields['IBLOCK_ID'] = $this->getIblockId();
			$result = self::addProperty($fields);
			if (!$result->isSuccess())
			{
				$this->errorCollection->add($result->getErrors());

				return null;
			}

			$newID = $result->getId();
			$descriptions = $this->getForm()->getIblockPropertiesDescriptions();
			foreach ($descriptions as $property)
			{
				if ((int)$property['propertyId'] === $newID)
				{
					break;
				}
			}

			$additionalValues = [];
			if (!empty($property))
			{
				if (!empty($property['defaultValue']))
				{
					$additionalValues[$property['name']] = $property['defaultValue'];
				}

				if ($property['multiple'] === true && !is_array($additionalValues[$property['name']]))
				{
					$additionalValues[$property['name']] = [];
				}

				if ($property['type'] === 'custom' && is_array($property['data']))
				{
					$values = $this->getForm()->getValues();
					foreach (['edit', 'view'] as $keyType)
					{
						$customDataName = $property['data'][$keyType];
						if (!empty($customDataName))
						{
							$additionalValues[$customDataName] = $values[$customDataName];
						}
					}
				}
			}

			return [
				'PROPERTY_FIELDS' => $property ?? null,
				'ADDITIONAL_VALUES' => $additionalValues,
			];
		}

		return null;
	}

	public function updatePropertyAction(array $fields = []): array
	{
		$resultFields = [];
		if ($this->checkModules() && $this->checkPermissions() && $this->checkRequiredParameters())
		{
			$id = str_replace(\Bitrix\Catalog\Component\ProductForm::PROPERTY_FIELD_PREFIX, '', $fields['CODE']);
			$result = self::updateProperty($id, $fields);
			if (!$result->isSuccess())
			{
				$this->errorCollection->add($result->getErrors());

				return [];
			}

			$id = (int)$result->getData()['ID'];
			$descriptions = $this->getForm()->getIblockPropertiesDescriptions();
			foreach ($descriptions as $property)
			{
				if ($property['propertyId'] === $id)
				{
					$resultFields = $property;
					break;
				}
			}
		}

		return [
			'PROPERTY_FIELDS' => $resultFields,
		];
	}

	public static function updateProperty($code, array $fields = []): \Bitrix\Main\Result
	{
		$result = new \Bitrix\Main\Result();

		$property = self::getPropertyByCode($code);
		if (empty($property))
		{
			$result->addError(new \Bitrix\Main\Error('Property not found.'));

			return $result;
		}

		$result->setData($property);
		$id = $property['ID'];

		if (!CIBlockRights::UserHasRightTo($property['IBLOCK_ID'], $property['IBLOCK_ID'], 'iblock_edit'))
		{
			$result->addError(new \Bitrix\Main\Error('User has no rights to edit property.'));

			return $result;
		}

		$updateFields = [
			'NAME' => $fields['NAME'],
		];

		if (!empty($fields['MULTIPLE']))
		{
			$updateFields['MULTIPLE'] = ($fields['MULTIPLE'] === 'Y') ? 'Y' : 'N';
		}

		if (!empty($fields['IS_REQUIRED']))
		{
			$updateFields['IS_REQUIRED'] = ($fields['IS_REQUIRED'] === 'Y') ? 'Y' : 'N';
		}

		if (!empty($fields['IS_PUBLIC']))
		{
			$features = [
				[
					'MODULE_ID' => 'iblock',
					'FEATURE_ID' => PropertyFeature::FEATURE_ID_LIST_PAGE_SHOW,
					'IS_ENABLED' => ($fields['IS_PUBLIC'] === 'Y') ? 'Y' : 'N',
				],
				[
					'MODULE_ID' => 'iblock',
					'FEATURE_ID' => PropertyFeature::FEATURE_ID_DETAIL_PAGE_SHOW,
					'IS_ENABLED' => ($fields['IS_PUBLIC'] === 'Y') ? 'Y' : 'N',
				],
			];

			\Bitrix\Iblock\Model\PropertyFeature::updateFeatures($id, $features);
		}

		if ($fields['USER_TYPE'] === 'Date' || $fields['USER_TYPE'] === 'DateTime')
		{
			$updateFields['USER_TYPE'] = $fields['USER_TYPE'];
		}

		if ($fields['PROPERTY_TYPE'] === PropertyTable::TYPE_LIST)
		{
			$updateFields['VALUES'] = is_array($fields['VALUES']) ? $fields['VALUES'] : [];
			if (empty($updateFields['VALUES']))
			{
				return $result->addError(
					new \Bitrix\Main\Error(Loc::getMessage('CPD_ERROR_EMPTY_LIST_ITEMS'))
				);
			}
			$updateFields['VALUES'] = array_column($updateFields['VALUES'], null, 'ID');
		}

		$iblockProperty = new \CIBlockProperty();
		$resultId = $iblockProperty->Update($id, $updateFields);
		if (!$resultId)
		{
			$result->addError(new \Bitrix\Main\Error($iblockProperty->LAST_ERROR));

			return $result;
		}

		$tableName = $property['USER_TYPE_SETTINGS']['TABLE_NAME'];
		if ($property['USER_TYPE'] === 'directory'
			&& !empty($tableName)
			&& Loader::includeModule('highloadblock')
		)
		{
			self::updateDirectoryValues($tableName, $fields['VALUES'] ?? []);
		}

		return $result;
	}

	private static function getPropertyByCode($code): array
	{
		if (is_numeric($code))
		{
			$propertyRaw = \CIBlockProperty::GetByID($code);
			if ($property = $propertyRaw->Fetch())
			{
				return $property;
			}
		}

		$propertyRaw = \CIBlockProperty::GetList([], ['CODE' => $code]);
		if ($property = $propertyRaw->Fetch())
		{
			return $property;
		}

		return [];
	}

	private static function updateDirectoryValues($tableName, array $values = [])
	{
		$hlblock = \Bitrix\Highloadblock\HighloadBlockTable::getRow([
			'filter' => [
				'=TABLE_NAME' => $tableName,
			],
		]);

		if ($hlblock)
		{
			$files = [];
			$entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlblock);
			$entityClass = $entity->getDataClass();

			$recordRaws = $entityClass::getList();
			$recordsByXmlId = [];
			foreach ($recordRaws as $record)
			{
				$recordsByXmlId[$record['UF_XML_ID']] = $record;
			}

			$activeItems = array_column($values, 'XML_ID');
			$activeItems = array_diff($activeItems, ['']);
			$itemsForRemoving = array_diff_key($recordsByXmlId, array_flip($activeItems));

			foreach ($itemsForRemoving as $removeItem)
			{
				if ((int)($removeItem['UF_FILE']) > 0)
				{
					\CFile::Delete((int)$removeItem['UF_FILE']);
				}
				if ((int)($removeItem['ID']) > 0)
				{
					$entityClass::delete((int)$removeItem['ID']);
				}
			}

			if (!empty($_FILES['FILES']))
			{
				CFile::ConvertFilesToPost($_FILES['FILES'], $files);
			}

			foreach ($values as $value)
			{
				$xmlId = $value['XML_ID'];
				$sortValue = $value['SORT'];
				if (empty($xmlId))
				{
					$addFields = [
						'UF_NAME' => $value['VALUE'],
						'UF_SORT' => $value['SORT'],
					];

					if (isset($files[$sortValue]))
					{
						$addFields['UF_FILE'] = $files[$sortValue];
					}

					if (empty($addFields['UF_NAME']) && empty($addFields['UF_FILE']))
					{
						continue;
					}

					$addFields['UF_XML_ID'] = !empty($item['XML_ID']) ? $item['XML_ID'] : md5(mt_rand());
					if (empty($addFields['UF_NAME']))
					{
						$addFields['UF_NAME'] = Loc::getMessage('CPD_NEW_LIST_ELEMENT_EMPTY_NAME');
					}
					$entityClass::add($addFields);
				}
				else
				{
					$updateFields = [];
					if (!empty($files[$sortValue]))
					{
						$updateFields['UF_FILE'] = $files[$sortValue];
						\CFile::Delete($recordsByXmlId[$xmlId]['UF_FILE']);
					}

					if (!empty($value['VALUE']) && $value['VALUE'] !== $recordsByXmlId[$xmlId]['UF_NAME'])
					{
						$updateFields['UF_NAME'] = $value['VALUE'];
					}

					if (!empty($updateFields))
					{
						$entityClass::update($recordsByXmlId[$xmlId]['ID'], $updateFields);
					}
				}
			}
		}
	}

	public static function addProperty(array $fields): AddResult
	{
		$result = new AddResult();
		$iblockProperty = new \CIBlockProperty();

		$iblockId = (int)$fields['IBLOCK_ID'];
		if ($iblockId <= 0)
		{
			return $result->addError(new \Bitrix\Main\Error('Empty iblock ID'));
		}

		if (!CIBlockRights::UserHasRightTo($iblockId, $iblockId, 'iblock_edit'))
		{
			return $result->addError(new \Bitrix\Main\Error('User has no rights to edit property.'));
		}

		if ($fields['USER_TYPE'] === 'directory')
		{
			$addDictionaryResult = self::addDictionary($fields);
			if (!$addDictionaryResult->isSuccess())
			{
				return $addDictionaryResult;
			}

			$addDictionaryData = $addDictionaryResult->getData();
			$fields['LIST_TYPE'] = 'L';
			$fields['USER_TYPE_SETTINGS'] = [
				'size' => '1',
				'width' => '0',
				'group' => 'N',
				'multiple' => 'N',
				'TABLE_NAME' => $addDictionaryData['TABLE_NAME'],
			];
		}

		if (!isset($fields['CODE']) || $fields['CODE'] === '')
		{
			$fields['CODE'] = CUtil::translit(
				$fields['NAME'],
				LANGUAGE_ID,
				[
					'replace_space' => '_',
					'replace_other' => '',
				]
			);

			if (isset($fields['CODE'][0]) && is_numeric($fields['CODE'][0]))
			{
				$fields['CODE'] = 'PROP_'.$fields['CODE'];
			}

			$fields['CODE'] .= '_'.\Bitrix\Main\Security\Random::getString(6);
			$fields['CODE'] = mb_strtoupper($fields['CODE']);
		}

		$propertyFields = [
			'IBLOCK_ID' => $fields['IBLOCK_ID'],
			'NAME' => $fields['NAME'],
			'SORT' => $fields['SORT'] ?? 500,
			'CODE' => $fields['CODE'],
			'MULTIPLE' => ($fields['MULTIPLE'] === 'Y') ? 'Y' : 'N',
			'IS_REQUIRED' => ($fields['IS_REQUIRED'] === 'Y') ? 'Y' : 'N',
			'PROPERTY_TYPE' => $fields['PROPERTY_TYPE'],
			'USER_TYPE' => $fields['USER_TYPE'] ?? '',
			'LIST_TYPE' => ($fields['LIST_TYPE'] === PropertyTable::CHECKBOX) ? PropertyTable::CHECKBOX : PropertyTable::LISTBOX,
		];

		if ($fields['PROPERTY_TYPE'] === PropertyTable::TYPE_LIST)
		{
			if (empty($fields['VALUES']) || !is_array($fields['VALUES']))
			{
				return $result->addError(
					new \Bitrix\Main\Error(Loc::getMessage('CPD_ERROR_EMPTY_LIST_ITEMS'))
				);
			}

			$i = 1;
			foreach ($fields['VALUES'] as $value)
			{
				unset($value['ID']);
				$propertyFields['VALUES'][$i++] = $value;
			}
		}

		if (isset($fields['USER_TYPE_SETTINGS']))
		{
			$propertyFields['USER_TYPE_SETTINGS'] = $fields['USER_TYPE_SETTINGS'];
		}

		if (isset($fields['FEATURES']))
		{
			$propertyFields['FEATURES'] = $fields['FEATURES'];
		}

		if (!empty($fields['IS_PUBLIC']))
		{
			$propertyFields['FEATURES'] = $propertyFields['FEATURES'] ?? [];
			$propertyFields['FEATURES'][] = [
				'MODULE_ID' => 'iblock',
				'FEATURE_ID' => PropertyFeature::FEATURE_ID_DETAIL_PAGE_SHOW,
				'IS_ENABLED' => ($fields['IS_PUBLIC'] === 'Y') ? 'Y' : 'N',
			];
			$propertyFields['FEATURES'][] = [
				'MODULE_ID' => 'iblock',
				'FEATURE_ID' => PropertyFeature::FEATURE_ID_LIST_PAGE_SHOW,
				'IS_ENABLED' => ($fields['IS_PUBLIC'] === 'Y') ? 'Y' : 'N',
			];
		}

		$newId = (int)($iblockProperty->Add($propertyFields));
		if ($newId === 0)
		{
			return $result->addError(new Error($iblockProperty->LAST_ERROR));
		}

		$result->setId($newId);

		return $result;
	}

	private static function addDictionary(array $fields): AddResult
	{
		$result = new AddResult();
		if (!Loader::includeModule('highloadblock'))
		{
			return $result->addError(
				new \Bitrix\Main\Error('Module "highloadblock" is not installed.')
			);
		}

		$tableId = uniqid();
		$translitName = CUtil::translit(
			$fields['NAME'],
			LANGUAGE_ID,
			[
				'replace_space' => '',
				'replace_other' => '',
			]
		);
		$chunks = array_map(
			static function ($string) {
				return mb_strtoupper(mb_substr($string, 0, 1)).mb_substr($string, 1);
			},
			['Property', $translitName, $tableId]
		);
		$dictionaryName = implode('', $chunks);
		$tableName = CIBlockPropertyDirectory::createHighloadTableName($tableId);
		$data = [
			'NAME' => $dictionaryName,
			'TABLE_NAME' => $tableName,
		];

		$dictionaryItems = [];
		$values = $fields['VALUES'] ?? [];

		$files = [];
		if (!empty($_FILES['FILES']))
		{
			CFile::ConvertFilesToPost($_FILES['FILES'], $files);
		}

		foreach ($values as $item)
		{
			$newFields = [
				'UF_NAME' => $item['VALUE'],
				'UF_SORT' => $item['SORT'],
			];

			if (isset($files[$item['SORT']]))
			{
				$newFields['UF_FILE'] = $files[$item['SORT']];
			}

			if (empty($newFields['UF_NAME']) && empty($newFields['UF_FILE']))
			{
				continue;
			}

			$newFields['UF_XML_ID'] = !empty($item['XML_ID']) ? $item['XML_ID'] : md5(mt_rand());
			if (empty($newFields['UF_NAME']))
			{
				$newFields['UF_NAME'] = Loc::getMessage('CPD_NEW_LIST_ELEMENT_EMPTY_NAME');
			}

			$dictionaryItems[] = $newFields;
		}

		if (empty($dictionaryItems))
		{
			return $result->addError(
				new \Bitrix\Main\Error(Loc::getMessage('CPD_ERROR_EMPTY_DIRECTORY_ITEMS'))
			);
		}

		$addResult = Bitrix\Highloadblock\HighloadBlockTable::add($data);
		if (!$addResult->isSuccess())
		{
			return $addResult->addError(
				new \Bitrix\Main\Error(Loc::getMessage('CPD_ERROR_ADD_HIGHLOAD_BLOCK'))
			);
		}

		$highloadBlockID = $addResult->getId();
		$obUserField = new CUserTypeEntity();
		$columnSorting = 100;
		$highloadColumns = ['UF_NAME', 'UF_XML_ID', 'UF_SORT', 'UF_FILE', 'UF_DEF'];
		foreach ($highloadColumns as $column)
		{
			$fieldMandatory = 'N';
			switch ($column)
			{
				case 'UF_NAME':
				case 'UF_XML_ID':
					$fieldType = 'string';
					$fieldMandatory = 'Y';
					break;
				case 'UF_SORT':
					$fieldType = 'integer';
					break;
				case 'UF_FILE':
					$fieldType = 'file';
					break;
				case 'UF_DEF':
					$fieldType = 'boolean';
					break;
				default:
					$fieldType = 'string';
			}

			$arUserField = [
				"ENTITY_ID" => "HLBLOCK_".$highloadBlockID,
				"FIELD_NAME" => $column,
				"USER_TYPE_ID" => $fieldType,
				"XML_ID" => "",
				"SORT" => $columnSorting,
				"MULTIPLE" => "N",
				"MANDATORY" => $fieldMandatory,
				"SHOW_FILTER" => "N",
				"SHOW_IN_LIST" => "Y",
				"EDIT_IN_LIST" => "Y",
				"IS_SEARCHABLE" => "N",
				"SETTINGS" => [],
			];

			$obUserField->Add($arUserField);
			$columnSorting += 100;
		}

		$entity = Bitrix\Highloadblock\HighloadBlockTable::compileEntity($highloadBlockID);
		$entityDataClass = $entity->getDataClass();

		foreach ($dictionaryItems as $item)
		{
			$entityDataClass::add($item);
		}

		return $result->setData([
			'TABLE_NAME' => $tableName,
		]);
	}

	public function setCardSettingAction(string $settingId, $selected): Bitrix\Main\Engine\Response\AjaxJson
	{
		if (!$this->checkModules() || !$this->checkPermissions() || !$this->checkRequiredParameters())
		{
			return Bitrix\Main\Engine\Response\AjaxJson::createError($this->errorCollection);
		}

		$selected = $selected === 'true';
		$settings = $this->getForm()->getCardSettings();

		foreach ($settings as $item)
		{
			if ($item['id'] === $settingId && $item['action'] === 'card' && $item['checked'] !== $selected)
			{
				$config = $this->getForm()->getCardUserConfig();
				$config[$item['id']] = $selected;
				$this->getForm()->saveCardUserConfig($config);
			}
		}

		return Bitrix\Main\Engine\Response\AjaxJson::createSuccess();
	}

	public function setGridSettingAction(string $settingId, $selected, array $currentHeaders = []): Bitrix\Main\Engine\Response\AjaxJson
	{
		if (!$this->checkModules() || !$this->checkPermissions() || !$this->checkRequiredParameters())
		{
			return Bitrix\Main\Engine\Response\AjaxJson::createError($this->errorCollection);
		}

		$headers = [];

		if ($settingId === 'MEASUREMENTS')
		{
			$headers = ['WEIGHT', 'WIDTH', 'LENGTH', 'HEIGHT'];
		}
		elseif ($settingId === 'PURCHASING_PRICE_FIELD')
		{
			$headers = ['PURCHASING_PRICE_FIELD'];
		}
		elseif ($settingId === 'MEASURE_RATIO')
		{
			$headers = ['MEASURE_RATIO'];
		}
		elseif ($settingId === 'VAT_INCLUDED')
		{
			$headers = ['VAT_INCLUDED', 'VAT_ID'];
		}

		if (!empty($headers))
		{
			$gridVariationForm = null;
			$productFactory = ServiceContainer::getProductFactory($this->getIblockId());
			if ($productFactory)
			{
				$newProduct = $productFactory->createEntity();
				$emptyVariation = $newProduct->getSkuCollection()->create();
				$gridVariationForm = new GridVariationForm($emptyVariation);
			}

			if (!$gridVariationForm)
			{
				return Bitrix\Main\Engine\Response\AjaxJson::createError($this->errorCollection);
			}

			foreach ($headers as &$header)
			{
				$header = $gridVariationForm::formatFieldName($header);
			}

			unset($header);

			$options = new \Bitrix\Main\Grid\Options($gridVariationForm->getVariationGridId());
			$allUsedColumns = $options->getUsedColumns();

			if (empty($allUsedColumns))
			{
				$allUsedColumns = $currentHeaders;
			}

			if ($selected === 'true')
			{
				// sort new columns by default grid column sort
				$defaultHeaders = array_column($gridVariationForm->getGridHeaders(), 'id');
				$currentHeadersInDefaultPosition = array_values(
					array_intersect($defaultHeaders, array_merge($allUsedColumns, $headers))
				);
				$headers = array_values(array_intersect($defaultHeaders, $headers));

				foreach ($headers as $header)
				{
					$insertPosition = array_search($header, $currentHeadersInDefaultPosition, true);
					array_splice($allUsedColumns, $insertPosition, 0, $header);
				}
			}
			else
			{
				$allUsedColumns = array_diff($allUsedColumns, $headers);
			}

			$options->setColumns(implode(',', $allUsedColumns));
			$options->save();
		}

		return Bitrix\Main\Engine\Response\AjaxJson::createSuccess();
	}

	private function getForm()
	{
		if ($this->form === null)
		{
			$this->form = new ProductForm($this->getProduct(), $this->arParams);
		}

		return $this->form;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit