Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/modules/catalog/lib/v2/Integration/JS/ProductForm/
Upload File :
Current File : /var/www/homesaver/www/bitrix/modules/catalog/lib/v2/Integration/JS/ProductForm/BasketItem.php

<?php

namespace Bitrix\Catalog\v2\Integration\JS\ProductForm;

use Bitrix\Catalog\v2\Price\BasePrice;
use Bitrix\Catalog\v2\Product\BaseProduct;
use Bitrix\Catalog\v2\Sku\BaseSku;
use Bitrix\Catalog\Component\ImageInput;
use Bitrix\Catalog\v2\IoC\ServiceContainer;
use Bitrix\Catalog\v2\Property\Property;
use Bitrix\Catalog\Access\AccessController;
use Bitrix\Catalog\Access\ActionDictionary;
use Bitrix\Catalog\Url\ShopBuilder;
use Bitrix\Catalog\VatTable;
use Bitrix\Iblock\PropertyEnumerationTable;
use Bitrix\Iblock\PropertyTable;
use Bitrix\Main\Loader;
use Bitrix\Sale\Internals;
use Bitrix\Iblock\Url\AdminPage\BuilderManager;
use Bitrix\Main\Web\Json;

class BasketItem
{
	private const DISCOUNT_TYPE_MONETARY = 1;
	private const DISCOUNT_TYPE_PERCENTAGE = 2;
	private const BRAND_PROPERTY_CODE = 'BRAND_FOR_FACEBOOK';

	private $fields;
	private $detailUrlType;
	private $id;
	private $priceGroupId;

	/** @var BaseSku $sku */
	private $sku;

	/** @var BasePrice $priceItem */
	private $priceItem;

	public function __construct()
	{
		$this->id = uniqid('', true);
		$this->fields = [
			'innerId' => $this->id,
			'productId' => 0,
			'skuId' => 0,
			'type' => null,
			'code' => '',
			'name' => '',
			'sort' => 0,
			'module' => '',
			'catalogPrice' => null,
			'basePrice' => 0,
			'price' => 0,
			'priceExclusive' => 0,
			'isCustomPrice' => 'Y',
			'discountType' => self::DISCOUNT_TYPE_PERCENTAGE,
			'quantity' => 1,
			'measureCode' => 0,
			'measureName' => '',
			'measureRatio' => 1,
			'discountRate' => 0,
			'discount' => 0,
			'taxId' => 0,
			'taxIncluded' => 'N',
			'additionalFields' => [],
			'properties' => [],
			'brands' => '',
			'weight' => 0,
			'dimensions' => [],
		];

		$this->setDetailUrlManagerType(ShopBuilder::TYPE_ID);

		$basePriceGroup = \CCatalogGroup::GetBaseGroup();
		if ($basePriceGroup)
		{
			$this->setPriceGroupId((int)$basePriceGroup['ID']);
		}
	}

	private function getField($name)
	{
		return $this->fields[$name] ?? '';
	}

	private function getEncodedSkuTree(): string
	{
		if (!$this->sku || $this->sku->isSimple())
		{
			return '';
		}

		/** @var BaseProduct $product */
		$product = $this->sku->getParent();
		$skuTree = ServiceContainer::make('sku.tree', ['iblockId' => $product->getIblockId()]);

		if (!$skuTree)
		{
			return '';
		}

		$skuTreeItems = $skuTree->loadJsonOffers([
			$product->getId() => $this->sku->getId(),
		]);

		if (!$skuTreeItems[$product->getId()][$this->sku->getId()])
		{
			return '';
		}

		return Json::encode($skuTreeItems[$product->getId()][$this->sku->getId()]);
	}

	private function getImageInputField(): ?array
	{
		if (!$this->sku)
		{
			return null;
		}

		$variationImageField = new ImageInput($this->sku);

		return $variationImageField->getFormattedField();
	}

	private function getSum(): float
	{
		return (float)$this->getField('priceExclusive') * (float)$this->getField('quantity');
	}

	private function getDetailUrl(): string
	{
		if (!$this->sku || $this->sku->isNew())
		{
			return '';
		}

		$parent = $this->sku->getParent();
		$urlBuilder = BuilderManager::getInstance()->getBuilder($this->detailUrlType);
		if (!$urlBuilder || !$parent)
		{
			return '';
		}

		$urlBuilder->setIblockId($parent->getIblockId());

		return $urlBuilder->getElementDetailUrl($parent->getId());
	}

	public function getFields(): array
	{
		return $this->fields;
	}

	public function getId(): string
	{
		return $this->id;
	}

	public function getSkuId(): ?int
	{
		if ($this->sku)
		{
			return $this->sku->getId();
		}

		return null;
	}

	public function getPriceItem(): ?BasePrice
	{
		return $this->priceItem;
	}

	public function setSku(BaseSku $sku): self
	{
		$this->sku = $sku;
		if ($sku->getParent())
		{
			$this->fields['productId'] = $sku->getParent()->getId();
		}
		$this->fields['skuId'] = $sku->getId();
		$this->fields['module'] = 'catalog';

		$this->fillFieldsFromSku();

		return $this;
	}

	public function removeSku(): self
	{
		$this->sku = null;
		$this->priceItem = null;
		$this->fields['productId'] = '';
		$this->fields['skuId'] = '';
		$this->fields['module'] = '';
		$this->fields['properties'] = [];

		return $this;
	}

	private function fillFieldsFromSku(): void
	{
		$this->setName($this->sku->getName());
		$this->setType($this->sku->getType());
		$this->fillProperties();
		$this->fillBrands();
		$this->fillMeasureFields();
		$this->fillTaxFields();
		$this->fillPriceFields();
		$this->fillDeliveryFields();
	}

	private function fillProperties(): void
	{
		$properties = [];
		foreach ($this->sku->getPropertyCollection() as $property)
		{
			$formattedValues = $this->getFormattedProperty($property);
			if ($formattedValues === null)
			{
				continue;
			}
			$properties[] = $formattedValues;
		}

		$this->fields['properties'] = $properties;
	}

	private function fillBrands(): void
	{
		/** @var BaseProduct $product */
		$product = $this->sku->getParent();
		if (!$product)
		{
			return;
		}

		$property = $product->getPropertyCollection()->findByCodeLazy(self::BRAND_PROPERTY_CODE);
		if (!$property)
		{
			return;
		}

		$userType = \CIBlockProperty::GetUserType($property->getUserType());
		$userTypeMethod = $userType['GetUIEntityEditorProperty'];
		$propertySettings = $property->getSettings();
		$propertyValues = $property->getPropertyValueCollection()->getValues();
		$description = $userTypeMethod($propertySettings, $propertyValues);
		$propertyBrandItems = $description['data']['items'];

		$selectedBrandItems = [];

		foreach ($propertyBrandItems as $propertyBrandItem)
		{
			if (in_array($propertyBrandItem['VALUE'], $propertyValues, true))
			{
				$selectedBrandItems[] = $propertyBrandItem;
			}
		}

		$this->fields['brands'] = $selectedBrandItems;
	}

	private function getFormattedProperty(Property $property): ?array
	{
		$propertyKeys = array_flip(['ID', 'NAME', 'CODE', 'SORT', 'XML_ID']);
		$formattedValues = $property->getPropertyValueCollection()->toArray();
		if (empty($formattedValues))
		{
			return null;
		}

		$enumValueMap = [];
		if ($property->getPropertyType() === PropertyTable::TYPE_LIST)
		{
			$enumIds = array_column($formattedValues, 'VALUE');
			$enumSettings = PropertyEnumerationTable::getList([
				'select' => ['ID', 'VALUE'],
				'filter' => [
					'=ID' => $enumIds,
				],
			])
				->fetchAll()
			;

			$enumValueMap = array_column($enumSettings, 'VALUE', 'ID');
		}

		$propertySettings = $property->getSettings();
		foreach ($formattedValues as $propertyValueId => $valueInfo)
		{
			$value = $valueInfo['VALUE'];

			if ($property->getPropertyType() === PropertyTable::TYPE_LIST)
			{
				$value = $enumValueMap[$value] ?? $value;
			}

			$displayProperty = array_merge(
				$propertySettings,
				[
					'DESCRIPTION' => $valueInfo['DESCRIPTION'] ?? null,
					'~DESCRIPTION' => $valueInfo['DESCRIPTION'] ?? null,
					'VALUE' => $value,
					'~VALUE' => $value,
				]
			);

			$displayProperty = \CIBlockFormatProperties::GetDisplayValue([], $displayProperty);

			$formattedValues[$propertyValueId]['DISPLAY_VALUE'] = $displayProperty['DISPLAY_VALUE'];
		}

		$propertySettings = array_intersect_key($propertySettings, $propertyKeys);
		$propertySettings['PROPERTY_VALUES'] = $formattedValues;

		return $propertySettings;
	}

	private function fillMeasureFields(): void
	{
		$measureId = (int)$this->sku->getField('MEASURE');
		$filter =
			$measureId > 0
				? ['=ID' => $this->sku->getField('MEASURE')]
				: ['=IS_DEFAULT' => 'Y']
		;

		$measureRow = \CCatalogMeasure::getList(
			['CODE' => 'ASC'],
			$filter,
			false,
			['nTopCount' => 1],
			['CODE', 'SYMBOL', 'SYMBOL_INTL']
		);

		if ($measure = $measureRow->Fetch())
		{
			$name = $measure['SYMBOL'] ?? $measure['SYMBOL_INTL'];
			$this
				->setMeasureCode((int)$measure['CODE'])
				->setMeasureName($name)
			;
		}

		$ratioItem = $this->sku->getMeasureRatioCollection()->findDefault();
		if ($ratioItem)
		{
			$this->setMeasureRatio((float)$ratioItem->getRatio());
		}
	}

	private function fillTaxFields(): void
	{
		$taxId = $this->sku->getField('VAT_ID');
		if (empty($taxId))
		{
			$taxId = $this->sku->getIblockInfo()->getVatId();
		}

		$tax = $taxId ? VatTable::getRowById($taxId) : null;

		$this
			->setTaxId((int)$taxId)
			->setTaxRate($tax ? $tax['RATE'] : null)
			->setTaxIncluded($this->sku->getField('VAT_INCLUDED'))
		;
	}

	private function fillPriceFields(): void
	{
		if (!$this->priceGroupId)
		{
			return;
		}

		$this->priceItem = $this->sku->getPriceCollection()->findByGroupId($this->priceGroupId);
		if ($this->priceItem)
		{
			$price = (float)$this->priceItem->getPrice();
			$this
				->setPrice($price)
				->setBasePrice($price)
				->setPriceExclusive($price)
			;
		}
	}

	private function fillDeliveryFields(): void
	{
		$this->fields['weight'] = $this->sku->getField('WEIGHT');

		$this->fields['dimensions'] = [
			'LENGTH' => $this->sku->getField('LENGTH'),
			'WIDTH' => $this->sku->getField('WIDTH'),
			'HEIGHT' => $this->sku->getField('HEIGHT'),
		];
	}

	private function hasEditRights(): bool
	{
		global $USER;

		if (!$this->sku || !$USER instanceof \CUser)
		{
			return false;
		}

		return
			\CIBlockElementRights::UserHasRightTo($this->sku->getIblockId(), $this->sku->getId(), 'element_edit')
			&& \CIBlockElementRights::UserHasRightTo($this->sku->getIblockId(), $this->sku->getId(), 'element_edit_price')
			&& !AccessController::getCurrent()->check(ActionDictionary::ACTION_PRICE_EDIT)
		;
	}

	public function getCatalogPrice(): ?float
	{
		if (!$this->priceItem)
		{
			return null;
		}

		return (float)$this->priceItem->getPrice();
	}

	public function setQuantity(float $value): self
	{
		$this->fields['quantity'] = $value;

		return $this;
	}

	public function setId(string $value): self
	{
		$this->id = $value;
		$this->fields['innerId'] = $value;

		return $this;
	}

	public function setName(string $value = null): self
	{
		$this->fields['name'] = $value;

		return $this;
	}

	public function setCode(string $value): self
	{
		$this->fields['code'] = $value;

		return $this;
	}

	public function setType(?int $value): self
	{
		$this->fields['type'] = $value;

		return $this;
	}

	public function setSort(int $value): self
	{
		$this->fields['sort'] = $value;

		return $this;
	}

	public function setDiscountType(int $value): self
	{
		$this->fields['discountType'] =
			$value === self::DISCOUNT_TYPE_MONETARY
				? self::DISCOUNT_TYPE_MONETARY
				: self::DISCOUNT_TYPE_PERCENTAGE;

		return $this;
	}

	public function setCustomPriceType(string $value = null): self
	{
		$this->fields['isCustomPrice'] = ($value === 'N') ? 'N' : 'Y';

		return $this;
	}

	public function setBasePrice(float $value): self
	{
		$this->fields['basePrice'] = $value > 0 ? $value : 0;

		return $this;
	}

	public function setPrice(float $value): self
	{
		$this->fields['price'] = $value > 0 ? $value : 0;

		return $this;
	}

	public function setPriceExclusive(float $value): self
	{
		$this->fields['priceExclusive'] = $value > 0 ? $value : 0;

		return $this;
	}

	public function setMeasureCode(int $code): self
	{
		if ($code > 0)
		{
			$this->fields['measureCode'] = $code;
		}

		return $this;
	}

	public function setMeasureName($name = null): self
	{
		$this->fields['measureName'] = $name;

		return $this;
	}

	public function setMeasureRatio(float $ratio): self
	{
		$this->fields['measureRatio'] = $ratio > 0 ? $ratio : 1;

		return $this;
	}

	public function setDiscountRate(float $value): self
	{
		$this->fields['discountRate'] = $value;

		return $this;
	}

	public function setDiscountValue(float $value): self
	{
		$this->fields['discount'] = $value;

		return $this;
	}

	public function addAdditionalField(string $name, $value): self
	{
		$this->fields['additionalFields'][$name] = $value;

		return $this;
	}

	public function setTaxIncluded(string $value = null): self
	{
		$this->fields['taxIncluded'] = ($value === 'N') ? 'N' : 'Y';

		return $this;
	}

	public function setTaxId(int $value): self
	{
		$this->fields['taxId'] = $value;

		return $this;
	}

	public function setTaxRate(?float $value): self
	{
		$this->fields['taxRate'] = $value;

		return $this;
	}

	public function clearAdditionalFields(): self
	{
		$this->fields['additionalFields'] = [];

		return $this;
	}

	public function setPriceGroupId(int $groupId): self
	{
		if ($groupId > 0)
		{
			$this->priceGroupId = $groupId;
		}

		return $this;
	}

	public function setDetailUrlManagerType(string $type): self
	{
		$this->detailUrlType = $type;

		return $this;
	}

	public function getResult(): array
	{
		return [
			'selectorId' => $this->id,
			'offerId' => $this->sku ? $this->sku->getId() : null,
			'fields' => $this->fields,
			'skuTree' => $this->getEncodedSkuTree(),
			'showDiscount' => !empty($this->getField('discount')) ? 'Y' : 'N',
			'image' => $this->getImageInputField(),
			'sum' => $this->getSum(),
			'catalogPrice' => $this->getCatalogPrice(),
			'detailUrl' => $this->getDetailUrl(),
			'discountSum' => $this->getField('discountSum'),
			'hasEditRights' => $this->hasEditRights(),
		];
	}
}