| Current Path : /var/www/homesaver/www/bitrix/components/bitrix/catalog.productcard.details/ |
| Current File : /var/www/homesaver/www/bitrix/components/bitrix/catalog.productcard.details/class.php |
<?php
use Bitrix\Catalog\Component\BaseForm;
use Bitrix\Catalog\Component\GridVariationForm;
use Bitrix\Catalog\Component\GridServiceForm;
use Bitrix\Catalog\Component\ProductForm;
use Bitrix\Catalog\Component\ServiceForm;
use Bitrix\Catalog\Component\StoreAmount;
use Bitrix\Catalog\Access\ActionDictionary;
use Bitrix\Catalog\Access\AccessController;
use Bitrix\Catalog\Access\Model\StoreDocument;
use Bitrix\Catalog\Config\Feature;
use Bitrix\Catalog\Config\State;
use Bitrix\Catalog\Integration\AI\Settings;
use Bitrix\Catalog\ProductTable;
use Bitrix\Catalog\Restriction\ToolAvailabilityManager;
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\ElementTable;
use Bitrix\Iblock\PropertyTable;
use Bitrix\Iblock\Model\PropertyFeature;
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Engine\Response\AjaxJson;
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\ORM;
use Bitrix\Main\Text\HtmlFilter;
use Bitrix\Main\UI\Extension;
use Bitrix\Main\UI\FileInputUtility;
use Bitrix\UI\Toolbar\Facade\Toolbar;
use Bitrix\Catalog\v2\Barcode\Barcode;
use Bitrix\Catalog\StoreDocumentTable;
use Bitrix\Iblock\Component\Property\ComponentLinksBuilder;
use Bitrix\Main\Web\Uri;
use Bitrix\Catalog\Store\EnableWizard\Manager;
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
die();
}
class CatalogProductDetailsComponent
extends \CBitrixComponent
implements Controllerable, Errorable
{
use ErrorableImplementation;
private int $iblockId = 0;
private int $productId = 0;
private int $productTypeId = 0;
private int $copyProductId = 0;
private bool $isCopy = false;
/** @var ProductForm|ServiceForm */
private $form;
/** @var StoreAmount */
private $storeAmount;
/** @var BaseProduct */
private $product;
/** @var BaseProduct */
private $copyProduct;
public function __construct($component = null)
{
parent::__construct($component);
$this->errorCollection = new ErrorCollection();
}
protected function showErrors()
{
foreach ($this->getErrors() as $error)
{
$this->includeErrorComponent($error->getMessage());
}
}
protected function includeErrorComponent(string $errorMessage, string $description = null): void
{
Toolbar::deleteFavoriteStar();
global $APPLICATION;
$APPLICATION->IncludeComponent(
"bitrix:ui.info.error",
"",
[
'TITLE' => $errorMessage,
'DESCRIPTION' => $description,
'IS_HTML' => 'Y',
]
);
}
public function configureActions()
{
return [];
}
protected function listKeysSignedParameters()
{
return [
'PRODUCT_ID',
'IBLOCK_ID',
'PRODUCT_TYPE_ID',
'PATH_TO',
'COPY_PRODUCT_ID',
'BUILDER_CONTEXT',
'SCOPE',
];
}
public function onPrepareComponentParams($params)
{
if (
!$this->checkModules()
)
{
$this->showErrors();
return null;
}
if (isset($params['IBLOCK_ID']))
{
$this->setIblockId((int)$params['IBLOCK_ID']);
}
if (isset($params['PRODUCT_ID']))
{
$this->setProductId((int)$params['PRODUCT_ID']);
if ($this->hasProductId())
{
unset($params['PRODUCT_TYPE_ID']);
}
}
if (isset($params['COPY_PRODUCT_ID']))
{
$this->setCopyProductId((int)$params['COPY_PRODUCT_ID']);
if (!$this->hasCopyProductId())
{
unset($params['COPY_PRODUCT_ID']);
}
}
if (isset($params['PRODUCT_TYPE_ID']))
{
$this->setProductTypeId((int)$params['PRODUCT_TYPE_ID']);
$currentTypeId = $this->getProductTypeId();
if ($currentTypeId > 0)
{
$params['PRODUCT_TYPE_ID'] = $currentTypeId;
}
else
{
unset($params['PRODUCT_TYPE_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->showErrors();
return;
}
if (!$this->isProductTypeSupported())
{
return;
}
if (
$this->checkBasePermissions()
&& $this->checkRequiredParameters()
)
{
$product = $this->getProduct();
if ($product)
{
if (!$product->isNew() || $this->checkAddPermissions())
{
$this->initializeExternalProductFields($product);
$this->initializeProductFields($product);
$this->placePageTitle($product);
$this->errorCollection->clear();
$this->includeComponentTemplate();
}
}
}
$this->showErrors();
}
protected function checkModules(): bool
{
if (!Loader::includeModule('catalog'))
{
$this->errorCollection[] = new \Bitrix\Main\Error('Module "catalog" is not installed.');
return false;
}
return true;
}
/**
* Returns a list of product types that the component can display.
*
* @return array
*/
protected function getAllowedProductTypes(): array
{
$iblockInfo = ServiceContainer::getIblockInfo($this->getIblockId());
if (!$iblockInfo)
{
return [];
}
if ($iblockInfo->canHaveSku())
{
return [
ProductTable::TYPE_PRODUCT,
ProductTable::TYPE_SKU,
ProductTable::TYPE_OFFER,
ProductTable::TYPE_SERVICE,
];
}
return [
ProductTable::TYPE_PRODUCT,
ProductTable::TYPE_SERVICE,
ProductTable::TYPE_EMPTY_SKU,
];
}
protected function checkLimitedProductTypes(int $productTypeId): bool
{
if ($productTypeId !== ProductTable::TYPE_SERVICE)
{
return true;
}
if (Feature::isCatalogServicesEnabled())
{
return true;
}
if (Loader::includeModule('bitrix24'))
{
Extension::load('ui.info-helper');
$this->includeErrorComponent(Loc::getMessage(
'CPD_ERROR_CATALOG_SERVICES_LIMIT_TARIFF',
['#LINK#' => Feature::getCatalogServicesHelpLink()['LINK']]
));
}
else
{
$this->includeErrorComponent(Loc::getMessage('CPD_ERROR_CATALOG_SERVICES_LIMIT_EDITION'));
}
return false;
}
protected function checkAllowedProductTypes(int $productTypeId): bool
{
if (in_array($productTypeId, $this->getAllowedProductTypes(), true))
{
return true;
}
$row = $this->getElementRow($this->getProductId());
if ($row === null)
{
return true;
}
$row['ID'] = (int)$row['ID'];
$row['TYPE'] = (int)$row['TYPE'];
$row['IBLOCK_ID'] = (int)$row['IBLOCK_ID'];
$this->showProductTypeNotSupportedError($row);
return false;
}
protected function isProductTypeSupported(): bool
{
if (!$this->hasProductId())
{
return true;
}
$productTypeId = $this->getProductTypeId();
if ($productTypeId === 0)
{
return true;
}
if (!$this->checkAllowedProductTypes($productTypeId))
{
return false;
}
if (!$this->checkLimitedProductTypes($productTypeId))
{
return false;
}
return true;
}
protected function showProductTypeNotSupportedError(array $row): void
{
$productTypes = ProductTable::getProductTypes(true);
if (isset($productTypes[$row['TYPE']]))
{
$errorMessage = $this->getFormedErrorMessage($row, $productTypes[$row['TYPE']]);
if (!empty($errorMessage))
{
$this->includeErrorComponent($errorMessage);
}
}
else
{
$this->includeErrorComponent(Loc::getMessage('CPD_ERROR_UNKNOWN_PRODUCT_TYPE'));
}
}
private function getFormedErrorMessage(array $row, string $productType): string
{
$title = $this->formatProductTypeName($productType);
if (
Loader::includeModule('crm')
&& !Loader::includeModule('bitrix24')
&& \Bitrix\Main\Config\Option::get('catalog', 'product_card_slider_enabled') === 'Y'
)
{
$builder = new \Bitrix\Catalog\Url\ShopBuilder();
$builder->setIblockId($row['IBLOCK_ID']);
$builder->setSliderMode(false);
$builder->setUrlParams([
\Bitrix\Catalog\Url\ShopBuilder::OPEN_SETTINGS_PARAM => 1,
]);
$url = $builder->getElementListUrl(0);
if ($url && $this->checkProductSliderEnablePermissions())
{
$link = '<a href="'
. $url
. '" target="_top" class="ui-link-solid">'
. Loc::getMessage('CPD_SETS_ENABLE_PRODUCT_SLIDER_LINK')
. '</a>'
;
}
else
{
$link = '';
}
return Loc::getMessage('CPD_ERROR_NOT_SUPPORTED_PRODUCT_TYPE_BUS', ['#TYPE#' => $title, '#LINK#' => $link]);
}
else
{
$builder = new \Bitrix\Catalog\Url\ShopBuilder();
$builder->setIblockId($row['IBLOCK_ID']);
$url = $builder->getElementListUrl(0);
if ($url)
{
$link = '<a href="'
. $url
. '" target="_top" class="ui-link-solid">'
. Loc::getMessage('CPD_SETS_NOT_SUPPORTED_LINK')
. '</a>'
;
return Loc::getMessage('CPD_ERROR_NOT_SUPPORTED_PRODUCT_TYPE', ['#TYPE#' => $title, '#LINK#' => $link]);
}
}
return '';
}
private function checkProductSliderEnablePermissions(): bool
{
$accessController = \Bitrix\Catalog\Access\AccessController::getCurrent();
return
(
$accessController->check(ActionDictionary::ACTION_CATALOG_READ)
&& $accessController->check(ActionDictionary::ACTION_CATALOG_SETTINGS_ACCESS)
)
;
}
protected function checkBasePermissions(): bool
{
if (!AccessController::getCurrent()->check(ActionDictionary::ACTION_CATALOG_READ))
{
$this->errorCollection[] = new \Bitrix\Main\Error(Loc::getMessage('CPD_ACCESS_DENIED_ERROR_TITLE'));
return false;
}
$form = $this->getForm();
if ($form === null)
{
return false;
}
if (!$form->isCardAllowed())
{
$this->errorCollection[] = new \Bitrix\Main\Error('New product card feature disabled.');
return false;
}
return true;
}
protected function checkEditPermissions(): bool
{
if (!AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_EDIT))
{
$this->errorCollection[] = new \Bitrix\Main\Error(Loc::getMessage('CPD_EDIT_PRODUCT_DENIED_ERROR_TITLE'));
return false;
}
return true;
}
public function checkStoreViewPermissions(): bool
{
return AccessController::getCurrent()->check(ActionDictionary::ACTION_STORE_VIEW);
}
protected function checkAddPermissions(): bool
{
if (!AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_ADD))
{
$this->errorCollection[] = new \Bitrix\Main\Error(Loc::getMessage('CPD_ADD_PRODUCT_DENIED_ERROR_TITLE'));
return false;
}
return true;
}
protected function checkDeletePermissions(): bool
{
if (!AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_DELETE))
{
$this->errorCollection[] = new \Bitrix\Main\Error(Loc::getMessage('CPD_ACCESS_DENIED_ERROR_TITLE'));
return false;
}
return true;
}
protected function checkRequiredParameters(): bool
{
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
{
$productTypeId = 0;
if ($productId > 0)
{
$row = $this->getElementRow($productId);
if ($row !== null)
{
$productTypeId = (int)($row['TYPE'] ?? 0);
}
else
{
$productId = 0;
}
}
$this->productId = $productId;
$this->productTypeId = $productTypeId;
return $this;
}
protected function getProductId(): int
{
return $this->productId;
}
private function hasProductId(): bool
{
return $this->getProductId() > 0;
}
protected function getProductTypeId(): int
{
return $this->productTypeId;
}
protected function setProductTypeId(int $productTypeId): self
{
if ($this->productTypeId > 0)
{
return $this;
}
if (!in_array($productTypeId, $this->getAllowedProductTypes(), true))
{
return $this;
}
$this->productTypeId = $productTypeId;
return $this;
}
protected function hasProductTypeid(): bool
{
return $this->getProductTypeId() > 0;
}
protected function isServiceType(): bool
{
return $this->getProductTypeId() === ProductTable::TYPE_SERVICE;
}
protected function isProductType(): bool
{
$productTypeId = $this->getProductTypeId();
return (
$productTypeId === ProductTable::TYPE_PRODUCT
|| $productTypeId === ProductTable::TYPE_SET
|| $productTypeId === ProductTable::TYPE_SKU
);
}
protected function isVariationType(): bool
{
return $this->getProductTypeId() === ProductTable::TYPE_OFFER;
}
protected function setCopyProductId(int $copyProductId): self
{
if ($this->hasProductId())
{
$copyProductId = 0;
}
if ($copyProductId > 0)
{
$row = $this->getElementRow($copyProductId);
if ($row !== null)
{
$productTypeId = (int)($row['TYPE'] ?? 0);
if ($productTypeId > 0)
{
$this->setProductTypeId($productTypeId);
}
}
else
{
$copyProductId = 0;
}
}
$this->copyProductId = $copyProductId;
$this->isCopy = $this->copyProductId > 0;
return $this;
}
protected function getCopyProductId(): int
{
return $this->copyProductId;
}
protected function hasCopyProductId(): bool
{
return $this->getCopyProductId() > 0;
}
protected function isCopy(): bool
{
return $this->isCopy;
}
protected function placePageTitle(BaseProduct $product): void
{
if ($product->isNew())
{
$title = $this->isServiceType()
? Loc::getMessage('CPD_NEW_SERVICE_TITLE')
: Loc::getMessage('CPD_NEW_PRODUCT_TITLE')
;
}
else
{
$title = HtmlFilter::encode($product->getName());
}
$this->getApplication()->setTitle($title);
}
protected function createProduct(): ?BaseProduct
{
$isCopy = $this->isCopy();
$existsProductType = !$isCopy && $this->hasProductTypeid();
$product = null;
$productFactory = ServiceContainer::getProductFactory($this->getIblockId());
if ($productFactory)
{
/** @var BaseProduct $product */
$product = $productFactory
->createEntity()
->setActive(true)
;
if ($existsProductType)
{
$product->setType($this->getProductTypeId());
}
}
if ($product === null)
{
$this->errorCollection[] = new \Bitrix\Main\Error(sprintf(
'Could not create product for iblock {%s}.', $this->getIblockId()
));
}
if (!AccessController::getCurrent()->check(ActionDictionary::ACTION_PRODUCT_PUBLIC_VISIBILITY_SET))
{
$product->setField('UF_PRODUCT_MAPPING', []);
}
if (!$existsProductType)
{
$skuRepository = ServiceContainer::getSkuRepository($this->getIblockId());
$productTypeId = $skuRepository ? ProductTable::TYPE_SKU : ProductTable::TYPE_PRODUCT;
$this->setProductTypeId($productTypeId);
}
if ($isCopy)
{
$copyProductId = $this->getCopyProductId();
$this->copyProduct = $this->loadProduct($copyProductId);
if ($this->copyProduct)
{
$fields = $this->copyProduct->getFields();
unset(
$fields['ID'],
$fields['IBLOCK_ID'],
$fields['XML_ID'],
$fields['PREVIEW_PICTURE'],
$fields['DETAIL_PICTURE'],
$fields['QUANTITY'],
$fields['QUANTITY_RESERVED'],
$fields['DATE_CREATE'],
$fields['CREATED_BY'],
);
if ($fields['TYPE'] === ProductTable::TYPE_EMPTY_SKU)
{
unset($fields['TYPE']);
}
$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
{
$repositoryFacade = ServiceContainer::getRepositoryFacade();
$product = $repositoryFacade->loadProduct($productId);
if ($product)
{
return $product;
}
$variation = $repositoryFacade->loadVariation($productId);
if ($variation === null)
{
$this->includeErrorComponent(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['PRODUCT_FIELDS']['ID'] = $this->arResult['PRODUCT_FIELDS']['ID'] ?? null;
$this->arResult['SIMPLE_PRODUCT'] = $product->isSimple();
$this->arResult['IS_NEW_PRODUCT'] = $product->isNew();
$this->arResult['UI_GUID'] = $this->isServiceType()
? 'CATALOG_SERVICE_CARD'
: 'CATALOG_PRODUCT_CARD'
;
$this->arResult['UI_ENTITY_FIELDS'] = $this->getForm()->getDescriptions();
$this->arResult['UI_ENTITY_CONFIG'] = $this->getForm()->getConfig();
$this->arResult['UI_ENTITY_READ_ONLY'] = $this->getForm()->isReadOnly();
$this->arResult['UI_ENTITY_CARD_SETTINGS_EDITABLE'] = $this->getForm()->isCardSettingsEditable();
$this->arResult['UI_ENTITY_ENABLE_SETTINGS_FOR_ALL'] = $this->getForm()->isEnabledSetSettingsForAll();
$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['TAB_LIST'] = $this->getTabList();
$this->arResult['VARIATION_GRID_ID'] = $this->getForm()->getVariationGridId();
$this->arResult['VARIATION_GRID_COMPONENT_NAME'] = $this->getForm()->getVariationGridJsComponentName();
$this->arResult['STORE_AMOUNT_GRID_ID'] = $this->getStoreAmount()->getStoreAmountGridId();
$this->arResult['CARD_SETTINGS'] = $this->getForm()->getCardSettings();
$this->arResult['HIDDEN_FIELDS'] = $this->getForm()->getHiddenFields();
$this->arResult['IS_WITH_ORDERS_MODE'] = Loader::includeModule('crm') && \CCrmSaleHelper::isWithOrdersMode();
$this->arResult['IS_INVENTORY_MANAGEMENT_USED'] = State::isUsedInventoryManagement();
$this->arResult['IS_INVENTORY_MANAGEMENT_TOOL_ENABLED'] = ToolAvailabilityManager::getInstance()->checkInventoryManagementAvailability();
$this->arResult['CREATE_DOCUMENT_BUTTON'] = $this->getCreateDocumentButton();
$this->arResult['PRODUCT_TYPE_NAME'] = $this->getProductTypeName($product);
$this->arResult['DROPDOWN_TYPES'] = $this->getDropdownTypes($product);
$this->arResult['DISABLED_HTML_CONTROLS'] = $this->getDisabledHtmlControls();
$this->arResult['CHTML_EDITOR_PARAMS'] = $this->getChtmlEditorParams();
$this->arResult['IS_COPILOT_ENABLED'] = Settings::isTextProductCardAvailable();
}
/**
* Returns tab list for entity card
*
* @return array
*/
protected function getTabList(): array
{
return [
'MAIN' => true,
'BALANCE' => !$this->isServiceType(),
'SEO' => false,
];
}
/**
* The button for creating a document with rights.
*
* @return array|null
*/
private function getCreateDocumentButton(): ?array
{
if (
!State::isUsedInventoryManagement()
|| Manager::isOnecMode()
|| !AccessController::getCurrent()->check(ActionDictionary::ACTION_CATALOG_READ)
|| !AccessController::getCurrent()->check(ActionDictionary::ACTION_INVENTORY_MANAGEMENT_ACCESS)
)
{
return null;
}
$popupItems = $this->getCreateDocumentButtonPopupItems();
if (empty($popupItems))
{
return null;
}
$mainButton = [
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON'),
];
if (ToolAvailabilityManager::getInstance()->checkInventoryManagementAvailability())
{
$row = reset($popupItems);
$mainButton['link'] = $row['link'];
}
else
{
$mainButton['click'] = 'BX.Catalog.ProductCard.openInventoryManagementToolDisabledSlider';
}
return [
'PARAMS' => [
'className' => 'ui-btn-primary',
'mainButton' => $mainButton,
],
'POPUP_ITEMS' => $popupItems,
];
}
protected function getCreateDocumentButtonPopupItems(): array
{
$productId = $this->getProductId();
$isService = $this->isServiceType();
$baseLink = new Uri('/shop/documents/details/0/');
$baseLink->addParams([
'preselectedProductId' => $productId,
'inventoryManagementSource' => 'product',
'focusedTab' => 'tab_products',
]);
$result = [];
if (!$isService)
{
$documents = [
[
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON_POPUP_ADJUSTMENT'),
'type' => StoreDocumentTable::TYPE_ARRIVAL,
],
[
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON_POPUP_SHIPMENT'),
'type' => StoreDocumentTable::TYPE_SALES_ORDERS,
],
[
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON_POPUP_MOVING'),
'type' => StoreDocumentTable::TYPE_MOVING,
],
[
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON_POPUP_DEDUCT'),
'type' => StoreDocumentTable::TYPE_DEDUCT,
],
];
}
else
{
$documents = [
[
'text' => Loc::getMessage('CPD_CREATE_DOCUMENT_BUTTON_POPUP_SHIPMENT'),
'type' => StoreDocumentTable::TYPE_SALES_ORDERS,
],
];
}
$isInventoryManagementAvailable = ToolAvailabilityManager::getInstance()->checkInventoryManagementAvailability();
foreach ($documents as $item)
{
$type = $item['type'];
$can = AccessController::getCurrent()->check(
ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY,
StoreDocument::createFromArray([
'DOC_TYPE' => $type,
])
);
if (!$can)
{
continue;
}
if ($isInventoryManagementAvailable)
{
if ($type === StoreDocumentTable::TYPE_SALES_ORDERS)
{
$link = new Uri('/shop/documents/details/sales_order/0/?DOCUMENT_TYPE=W&inventoryManagementSource=product');
$link->addParams([
'preselectedProductId' => $productId,
'focusedTab' => 'tab_products',
]);
}
else
{
$link = (clone $baseLink)->addParams([
'DOCUMENT_TYPE' => $type,
]);
}
$result[] = [
'text' => $item['text'],
'link' => (string)$link,
];
}
else
{
$result[] = [
'text' => $item['text'],
'onclick' => 'showInventoryManagementToolDisabledSlider',
];
}
}
return $result;
}
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
{
if (Loader::includeModule('iblock'))
{
return (new ComponentLinksBuilder)->getActionCreateUrl($this->getIblockId());
}
return '';
}
protected function getCreationSkuPropertyLink()
{
return str_replace(
'#IBLOCK_ID#',
$this->getForm()->getVariationIblockId(),
$this->arParams['PATH_TO']['PROPERTY_CREATOR']
);
}
private static function isNumericId($id): bool
{
if (is_int($id))
{
return true;
}
if (is_string($id))
{
$typedId = (int)$id;
if ((string)$typedId === $id)
{
return true;
}
}
return false;
}
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)
{
$isNumeric = static::isNumericId($id);
if ($isNumeric && $this->getProductId() !== $id)
{
return true;
}
if (!$isNumeric && !$product->isNew())
{
return true;
}
$propertyPrefix = GridVariationForm::preparePropertyName();
$morePhotoName = GridVariationForm::preparePropertyName(BaseForm::MORE_PHOTO);
foreach ($sku as $name => $value)
{
if (
!empty($value)
&& $name !== $morePhotoName
&& !str_ends_with($name, '_custom')
&& str_starts_with($name, $propertyPrefix)
)
{
return true;
}
}
}
return false;
}
private function parseSkuFields(&$fields): array
{
$skuGridId = $this->getForm()->getVariationGridId();
$skuFields = $fields[$skuGridId] ?? [];
unset($fields['ID'], $fields[$skuGridId]);
$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 (str_starts_with($name, BaseForm::GRID_FIELD_PREFIX))
{
unset($skuFields[$id][$name]);
$originalName = mb_substr($name, $prefixLength);
if ($originalName === 'BARCODE_custom')
{
$originalName = 'BARCODE';
}
// 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;
}
}
}
foreach ($fields as $name => $field)
{
if (str_starts_with($name, BaseForm::GRID_FIELD_PREFIX))
{
unset($fields[$name]);
}
}
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, $entity, $isSku): array
{
$propertyFields = [];
$prefixLength = mb_strlen(BaseForm::PROPERTY_FIELD_PREFIX);
foreach ($fields as $name => $field)
{
if (
str_starts_with($name, BaseForm::PROPERTY_FIELD_PREFIX)
&& !str_ends_with($name, '_custom')
&& !str_ends_with($name, '_del')
&& !str_ends_with($name, '_descr')
&& !str_ends_with($name, '_uploader_deleted')
)
{
$index = mb_substr($name, $prefixLength);
$propertyCollection = $entity->getPropertyCollection();
$property = $propertyCollection->findById((int)$index);
if ($property === null)
{
$property = $propertyCollection->findByCode($index);
}
$propertyType = null;
if ($property !== null)
{
$propertyType = $property->getPropertyType();
}
// grid file properties
if (
$propertyType === PropertyTable::TYPE_FILE
&& $isSku
)
{
if ($this->form->isImageProperty($property->getSettings()))
{
$field = $this->parseGridImagePropertyValues(
$fields[$name.'_custom'],
$this->getSkuPropertySavedValues($entity, $index)
);
}
else
{
$field = \Bitrix\Main\UI\FileInputUtility::instance()->checkFiles(
BaseForm::GRID_FIELD_PREFIX . BaseForm::PROPERTY_FIELD_PREFIX . $index . '_uploader',
$this->parseFilePropertyValues($fields[$name.'_custom'])
);
if ($this->copyProduct)
{
$field = $this->prepareFileValuesForCopy($field, $this->getSkuPropertySavedValues($entity, $index));
}
}
if (empty($field))
{
$field = '';
}
unset($fields[$name.'_custom']);
}
// editor file properties
elseif ($propertyType === PropertyTable::TYPE_FILE)
{
$isMultiple = $property->isMultiple();
$isImageProperty = $this->form->isImageProperty($property->getSettings());
if ($isImageProperty)
{
$defaultDescription = $isMultiple ? [] : null;
$description = $fields[$name . '_descr'] ?? $defaultDescription;
if (!$isMultiple)
{
$field = [$field];
$description = [$description];
}
else
{
if (!is_array($field) || array_key_exists('tmp_name', $field))
{
$field = [$field];
$description = [$description];
}
}
if (isset($fields[$name . '_del']))
{
if (is_array($fields[$name . '_del']))
{
$field = array_diff_key($field, $fields[$name . '_del']);
}
else
{
$field = [];
}
}
$field = $this->parseEditorImagePropertyValues($field, $description, $this->getPropertySavedValues($index));
unset($fields[$name . '_del'], $fields[$name . '_descr']);
}
else
{
if (!$isMultiple || !is_array($field))
{
$field = [$field];
}
if (isset($fields[$name . '_del']))
{
if (is_array($fields[$name . '_del']))
{
$deleteFiles = $fields[$name . '_del'];
foreach (array_keys($field) as $fileIndex)
{
if (in_array($field[$fileIndex], $deleteFiles))
{
unset($field[$fileIndex]);
}
}
unset($deleteFiles);
}
else
{
$field = [];
}
}
$field = \Bitrix\Main\UI\FileInputUtility::instance()->checkFiles(
BaseForm::PROPERTY_FIELD_PREFIX . $index . '_uploader',
$field
);
if ($this->copyProduct)
{
$field = $this->prepareFileValuesForCopy($field, $this->getPropertySavedValues($index));
}
unset($fields[$name . '_del'], $fields[$name . '_uploader_deleted']);
}
if (empty($field))
{
$field = '';
}
}
elseif (isset($property) && $property->getListType() === PropertyTable::CHECKBOX)
{
$variant = \Bitrix\Iblock\PropertyEnumerationTable::getRow([
'select' => ['ID', 'PROPERTY_ID', 'VALUE'],
'filter' => [
'=PROPERTY_ID' => $index,
],
]);
if ($variant && $field === $variant['VALUE'])
{
$field = $variant['ID'];
}
}
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 prepareFileValuesForCopy(array $values, array $savedValues): array
{
$preparedValues = [];
foreach ($values as $value)
{
if (in_array($value, $savedValues))
{
$fileArray = CIBlock::makeFileArray(
$value,
false,
null,
['allow_file_id' => true]
);
$fileArray['COPY_FILE'] = 'Y';
$preparedValues[] = $fileArray;
}
else
{
$preparedValues[] = $value;
}
}
return $preparedValues;
}
private function parseFilePropertyValues(array $fields): array
{
$fileIds = [];
foreach($fields as $fieldKey => $fieldValue)
{
if (
$fieldKey === 'isFile'
|| str_ends_with($fieldKey, '_deleted[')
)
{
continue;
}
$fileIds[] = $fieldValue;
}
return $fileIds;
}
private function getSkuPropertySavedValues($sku, $index): array
{
if ($sku->isNew())
{
return [];
}
$skuId = $sku->getId();
static $propertySavedValues = [];
if (isset($propertySavedValues[$skuId][$index]))
{
return $propertySavedValues[$skuId][$index];
}
$propertySavedValues[$skuId] ??= [];
$propertySavedValues[$skuId][$index] = [];
if ($index === BaseForm::MORE_PHOTO)
{
$property = $sku->getPropertyCollection()->findByCode(BaseForm::MORE_PHOTO);
}
else
{
$property = $sku->getPropertyCollection()->findById((int)$index);
}
if (!$property)
{
return $propertySavedValues[$skuId][$index];
}
$propertyValues = $property->getPropertyValueCollection()->getValues();
if ($propertyValues)
{
$propertySavedValues[$skuId][$index] = is_array($propertyValues) ? $propertyValues : [$propertyValues];
}
else
{
$propertySavedValues[$skuId][$index] = [];
}
return $propertySavedValues[$skuId][$index];
}
private function getPropertySavedValues(string $index): array
{
if (!$this->copyProduct && $this->product->isNew())
{
return [];
}
static $propertySavedValues = [];
if (isset($propertySavedValues[$index]))
{
return $propertySavedValues[$index];
}
$propertySavedValues[$index] = [];
$product = $this->copyProduct ?? $this->product;
if ($index === BaseForm::MORE_PHOTO)
{
$property = $product->getPropertyCollection()->findByCode(BaseForm::MORE_PHOTO);
}
else
{
$property = $product->getPropertyCollection()->findById((int)$index);
}
if (!$property)
{
return $propertySavedValues[$index];
}
$propertyValues = $property->getPropertyValueCollection()->getValues();
if ($propertyValues)
{
$propertySavedValues[$index] = is_array($propertyValues) ? $propertyValues : [$propertyValues];
}
else
{
$propertySavedValues[$index] = [];
}
return $propertySavedValues[$index];
}
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);
$sanitizer->ApplyDoubleEncode(false);
}
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 prepareCatalogFields(&$fields): void
{
if ($this->form->isQuantityTraceSettingDisabled())
{
unset($fields['QUANTITY_TRACE']);
}
}
private function prepareDateFields(&$fields): void
{
if (isset($fields['ACTIVE_FROM']) && $fields['ACTIVE_FROM'] !== '')
{
$date = \Bitrix\Main\Type\DateTime::createFromUserTime($fields['ACTIVE_FROM']);
$date->disableUserTime();
$fields['ACTIVE_FROM'] = $date;
}
if (isset($fields['ACTIVE_TO']) && $fields['ACTIVE_TO'] !== '')
{
$date = \Bitrix\Main\Type\DateTime::createFromUserTime($fields['ACTIVE_TO']);
$date->disableUserTime();
$fields['ACTIVE_TO'] = $date;
}
}
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_array($propertyField))
{
$currentValue = $propertyField['VALUE'] ?? null;
}
else
{
$currentValue = $propertyField;
}
if (is_numeric($currentValue))
{
$value = (int)$currentValue;
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));
}
}
}
/**
* Only for new products.
*
* @param $fields
* @return void
*/
private function prepareProductCode(&$fields): void
{
$productName = $fields['NAME'] ?? '';
$productCode = $fields['CODE'] ?? '';
$config = [
'CHECK_UNIQUE' => 'Y',
'CHECK_SIMILAR' => 'Y',
];
if ($productCode === '')
{
if ($productName !== '')
{
$fields['CODE'] = (new CIBlockElement())->createMnemonicCode(
[
'NAME' => $productName,
'IBLOCK_ID' => $this->getIblockId()
],
$config
);
}
}
else
{
$fields['CODE'] = (new CIBlockElement())->getUniqueMnemonicCode(
$productCode,
null,
$this->getIblockId(),
$config
);
}
}
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 parseEditorImagePropertyValues(array $values, array $descriptions, array $savedValues): array
{
$parsedValues = [];
foreach ($values as $key => $value)
{
$description = $descriptions[$key] ?? null;
if (is_array($value))
{
$parsedValues[] = \CIBlock::makeFilePropArray($value, false, $description);
}
elseif (is_numeric($value))
{
if (is_array($savedValues) && !in_array($value, $savedValues))
{
continue;
}
if ($this->product->isNew())
{
$fileArray = CIBlock::makeFileArray(
$value,
false,
$description,
['allow_file_id' => true]
);
$fileArray['COPY_FILE'] = 'Y';
$parsedValues[] = $fileArray;
}
else
{
$parsedValues[] = [
'VALUE' => $value,
'DESCRIPTION' => $description ?? '',
];
}
}
}
return $parsedValues;
}
private function parseGridImagePropertyValues(array $propertyFields, array $savedValues): array
{
$fileProp = [];
foreach ($propertyFields as $key => $value)
{
if (
str_ends_with($key, '_deleted[')
|| str_ends_with($key, '_del')
|| str_ends_with($key, '_descr')
|| isset($propertyFields[$key . '_del'])
)
{
continue;
}
$description = $propertyFields[$key.'_descr'] ?? null;
if (is_array($value))
{
$fileProp[] = \CIBlock::makeFilePropArray($value, false, $description);
}
elseif (is_numeric($value))
{
if (is_array($savedValues) && !in_array($value, $savedValues))
{
continue;
}
if ($this->product->isNew())
{
$fileArray = CIBlock::makeFileArray(
$value,
false,
$description,
['allow_file_id' => true]
);
$fileArray['COPY_FILE'] = 'Y';
$fileProp[] = $fileArray;
}
else
{
$fileProp[] = [
'VALUE' => $value,
'DESCRIPTION' => $description ?? '',
];
}
}
}
return $fileProp;
}
private function parsePriceFields(&$fields): array
{
$priceFields = [];
foreach ($fields as $name => $value)
{
if (str_starts_with($name, BaseForm::PRICE_FIELD_PREFIX))
{
$index = str_replace(BaseForm::PRICE_FIELD_PREFIX, '', $name);
if (!empty($index))
{
if (is_string($value))
{
str_replace(',', '.', $value);
}
$priceFields[$index]['PRICE'] = $value;
}
unset($fields[$name]);
}
if (str_starts_with($name, BaseForm::CURRENCY_FIELD_PREFIX))
{
$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] = [
$field,
];
}
}
}
}
public function loadAction(): ?array
{
if ($this->checkModules()
&& $this->checkBasePermissions()
&& $this->checkRequiredParameters()
)
{
$product = $this->getProduct();
if ($product)
{
$result = [
'ENTITY_ID' => $product->getId(),
'ENTITY_DATA' => $this->getEntityDataForResponse(),
// special edition
'ENTITY_FIELDS' => $this->getForm()->getDescriptions(),
];
return $result;
}
}
return null;
}
public function saveAction()
{
$fields = $this->request->get('data') ?: [];
$this->prepareFileFields($fields);
if (
empty($fields)
|| !$this->checkModules()
|| !$this->checkBasePermissions()
|| !$this->checkRequiredParameters()
)
{
return null;
}
$product = $this->getProduct();
if ($product === null)
{
return null;
}
if ($product->isNew())
{
if (!$this->checkAddPermissions())
{
return null;
}
}
elseif (!$this->checkEditPermissions())
{
return null;
}
$isSkuProduct = $this->parseIsSkuProduct($fields, $product);
$skuFields = $this->parseSkuFields($fields);
$propertyFields = $this->parsePropertyFields( $fields, $product, false);
$this->checkCompatiblePictureFields($product, $propertyFields);
$sectionFields = $this->parseSectionFields($fields);
$convertedSku = null;
if ($isSkuProduct && $product->allowConvertToSku())
{
$convertedSku = $this->convertSimpleProductToSku($product);
}
$this->prepareDescriptionFields($fields);
$this->preparePictureFields($fields);
$this->prepareCatalogFields($fields);
$this->prepareDateFields($fields);
if ($product->isNew())
{
$this->prepareProductCode($fields);
}
if (!$this->getForm()->isVisibilityEditable())
{
unset($fields['UF_PRODUCT_MAPPING']);
}
$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 (static::isNumericId($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())
{
$sku =
$product->isSimple()
? $product->getSkuCollection()->getFirst()
: $product->getSkuCollection()->create()
;
}
if ($sku === null)
{
$notifyAboutNewVariation = true;
$sku = $this->createSkuItem($product, (int)($skuField['COPY_SKU_ID'] ?? 0));
}
$this->fillSku($sku, $skuField);
}
}
return $this->saveInternal($product, $notifyAboutNewVariation);
}
private function convertSimpleProductToSku(BaseProduct $product): ?BaseSku
{
$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
{
/** @var BaseProduct $product */
$product = $sku->getParent();
$this->prepareSkuPictureFields($fields);
$skuPropertyFields = $this->parsePropertyFields($fields, $sku, true);
$this->checkCompatiblePictureFields($sku, $skuPropertyFields);
$skuPriceFields = $this->parsePriceFields($fields);
$skuMeasureRatioField = $this->parseMeasureRatioFields($fields);
if (!$this->getForm()->isPurchasingPriceAllowed())
{
unset(
$fields['PURCHASING_PRICE'],
$fields['PURCHASING_CURRENCY'],
);
}
if (!empty($fields))
{
if (isset($fields['NAME']) && $fields['NAME'] === '' && $product)
{
$fields['NAME'] = $product->getName();
}
if (isset($fields['PURCHASING_PRICE']))
{
if (is_string($fields['PURCHASING_PRICE']))
{
$fields['PURCHASING_PRICE'] = str_replace(
',', '.', trim($fields['PURCHASING_PRICE'])
);
}
if ($fields['PURCHASING_PRICE'] === '')
{
$fields['PURCHASING_PRICE'] = null;
}
}
$sku->setFields($fields);
if (isset($fields['BARCODE']))
{
$barcodeCollection = $sku->getBarcodeCollection();
$barcodeCollection->remove(...$barcodeCollection);
if (is_array($fields['BARCODE']))
{
foreach ($fields['BARCODE'] as $barcode)
{
if ($barcode === '')
{
continue;
}
$exist = false;
/** @var Barcode $deleteItem */
foreach ($barcodeCollection->getRemovedItems() as $deleteItem)
{
if ($deleteItem->getBarcode() === $barcode)
{
$barcodeCollection->clearRemoved($deleteItem);
$exist = true;
break;
}
}
if (!$exist)
{
$barcodeItem = $barcodeCollection->create();
$barcodeItem->setBarcode($barcode);
$barcodeCollection->add($barcodeItem);
}
}
}
else
{
$barcodeCollection->setSimpleBarcodeValue($fields['BARCODE']);
}
}
}
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) && $this->getForm()->isPricesEditable())
{
$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)
{
/** @var BaseSku $copySku */
$copySku = $this->copyProduct->getSkuCollection()->findById($copySkuId);
if ($copySku)
{
$fields = $copySku->getFields();
unset(
$fields['ID'],
$fields['IBLOCK_ID'],
$fields['XML_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
{
$result = $product->save();
if (!$result->isSuccess())
{
$this->errorCollection->add($result->getErrors());
return null;
}
$redirect = !$this->hasProductId();
$this->setProductId($product->getId());
$response = [
'ENTITY_ID' => $product->getId(),
'ENTITY_DATA' => $this->getEntityDataForResponse(),
'NOTIFY_ABOUT_NEW_VARIATION' => $redirect ? false : $notifyAboutNewVariation,
'IS_SIMPLE_PRODUCT' => $product->isSimple(),
];
if ($redirect)
{
$response['REDIRECT_URL'] = $this->getProductDetailUrl();
}
return $response;
}
private function getEntityDataForResponse(): array
{
$entityData = $this->getForm()->getValues(false);
foreach ($entityData as $key => $field)
{
if ($field instanceof \Bitrix\Main\Type\DateTime)
{
$entityData[$key] = $field->toString();
}
}
return $entityData;
}
public function refreshLinkedPropertiesAction(array $sectionIds = []): ?array
{
if (
$this->checkModules()
&& $this->checkBasePermissions()
&& $this->checkEditPermissions()
&& $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->checkBasePermissions()
&& $this->checkEditPermissions()
&& $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->checkBasePermissions()
&& $this->checkEditPermissions()
&& $this->checkRequiredParameters()
)
{
$id = str_replace(BaseForm::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 = [
'IBLOCK_ID' => $property['IBLOCK_ID'],
'NAME' => $fields['NAME'],
'USER_TYPE_SETTINGS' => null,
'SMART_FILTER' => null,
'DEFAULT_VALUE' => null,
];
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 (isset($fields['USER_TYPE']))
{
if (
$fields['USER_TYPE'] === CIBlockPropertyDate::USER_TYPE
|| $fields['USER_TYPE'] === CIBlockPropertyDateTime::USER_TYPE
|| $fields['USER_TYPE'] === CIBlockPropertySKU::USER_TYPE
)
{
$updateFields['USER_TYPE'] = $fields['USER_TYPE'];
}
}
if (isset($fields['PROPERTY_TYPE']) && $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'))
);
}
if (count($updateFields['VALUES']) === 1 && $updateFields['VALUES'][0]['VALUE'] === 'Y')
{
$variant = \Bitrix\Iblock\PropertyEnumerationTable::getRow([
'select' => ['ID', 'PROPERTY_ID', 'VALUE'],
'filter' => [
'=PROPERTY_ID' => $id,
],
]);
unset($updateFields['VALUES'][0]);
$updateFields['VALUES'][$variant['ID']] = ['VALUE' => 'Y'];
}
else
{
$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'] ?? null;
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 (isset($fields['USER_TYPE']) && $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']);
}
$listType = (isset($fields['LIST_TYPE']) && $fields['LIST_TYPE'] === PropertyTable::CHECKBOX)
? PropertyTable::CHECKBOX
: PropertyTable::LISTBOX;
$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' => $listType,
'SMART_FILTER' => null,
'USER_TYPE_SETTINGS' => null,
'DEFAULT_VALUE' => null,
];
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';
}
$userField = [
"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($userField);
$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): AjaxJson
{
if (
!$this->checkModules()
|| !$this->checkBasePermissions()
|| !$this->checkRequiredParameters()
)
{
return 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 AjaxJson::createSuccess();
}
public function setGridSettingAction(string $settingId, $selected, array $currentHeaders = []): AjaxJson
{
if (
!$this->checkModules()
|| !$this->checkBasePermissions()
|| !$this->checkRequiredParameters()
)
{
return AjaxJson::createError($this->errorCollection);
}
$gridVariationForm = null;
$productFactory = ServiceContainer::getProductFactory($this->getIblockId());
if ($productFactory)
{
$newProduct = $productFactory->createEntity();
$emptyVariation = $newProduct->getSkuCollection()->create();
/** @var GridVariationForm|GridServiceForm $gridVariationClassName */
$gridVariationClassName = $this->getForm()->getVariationGridClassName();
$gridVariationForm = new $gridVariationClassName($emptyVariation);
}
if (!$gridVariationForm)
{
$this->errorCollection[] = new Error('Grid variation form not found');
return AjaxJson::createError($this->errorCollection);
}
return $gridVariationForm->setGridSettings($settingId, $selected, $currentHeaders);
}
/**
* @return null|ProductForm|ServiceForm
*/
private function getForm()
{
if ($this->form === null)
{
$product = $this->getProduct();
if ($product !== null)
{
switch ($product->getType())
{
case ProductTable::TYPE_SERVICE:
$this->form = new ServiceForm($product, $this->arParams);
break;
default:
$this->form = new ProductForm($product, $this->arParams);
break;
}
}
}
return $this->form;
}
private function getStoreAmount(): StoreAmount
{
if ($this->storeAmount === null)
{
$this->storeAmount = new StoreAmount($this->getProductId());
}
return $this->storeAmount;
}
private function getElementRow(int $id): ?array
{
return ElementTable::getRow([
'runtime' => [
new ORM\Fields\Relations\Reference(
'TMP_PRODUCT',
'Bitrix\Catalog\ProductTable',
['=this.ID' => 'ref.ID']
),
],
'select' => [
'ID',
'IBLOCK_ID',
'TYPE' => 'TMP_PRODUCT.TYPE',
],
'filter' => [
'=ID' => $id,
],
]);
}
private function getProductTypeName(BaseProduct $product): string
{
$entityName = ProductTable::getTradingEntityNameByType($product->getType());
return ($entityName === null
? ''
: $this->formatProductTypeName($entityName)
);
}
private function getDropdownTypes(BaseProduct $product): array
{
if (!Feature::isCatalogServicesEnabled())
{
return [];
}
$iblockInfo = ServiceContainer::getIblockInfo($this->getIblockId());
if (!$iblockInfo)
{
return [];
}
$result = [];
$dropdownTypes = [
$iblockInfo->canHaveSku() ? ProductTable::TYPE_SKU : ProductTable::TYPE_PRODUCT,
ProductTable::TYPE_SERVICE,
];
if (
$product->isNew()
&& !$this->isCopy()
&& in_array($product->getType(), $dropdownTypes, true)
)
{
foreach ($dropdownTypes as $dropdownType)
{
$title = ProductTable::getTradingEntityNameByType($dropdownType);
if ($title !== null)
{
$result[$dropdownType] = $this->formatProductTypeName($title);
}
}
}
return $result;
}
private function getDisabledHtmlControls(): array
{
return [
'Code',
'Quote',
];
}
private function getChtmlEditorParams(): array
{
return [
'normalBodyWidth' => 600,
];
}
private function formatProductTypeName(string $productTypeName): string
{
return mb_strtoupper(mb_substr($productTypeName, 0, 1)) . mb_substr($productTypeName, 1);
}
}