Your IP : 18.188.30.161


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/catalog/lib/controller/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/catalog/lib/controller/product.php

<?php


namespace Bitrix\Catalog\Controller;


use Bitrix\Main\Engine\Response\DataType\Page;
use Bitrix\Main\Error;
use Bitrix\Main\Result;
use Bitrix\Main\Engine\Action;
use Bitrix\Main\Engine\ActionFilter\ClosureWrapper;
use Bitrix\Main\Engine\ActionFilter\Scope;
use Bitrix\Main\SystemException;

final class Product extends Controller
{
	public function configureActions()
	{
		return [
			'getFields' => [
				'+prefilters' => [
					function()
					{
						/** @var ClosureWrapper $this */
						/** @var Action $action */
						$action = $this->getAction();
						if($action->getController()->getScope() !== \Bitrix\Main\Engine\Controller::SCOPE_REST)
						{
							throw new SystemException('the method is only available in the rest service');
						}
					}
				],
			],
			'addProperty' => [
				'+prefilters' => [new Scope(Scope::AJAX)]
			]
		];
	}
	//region Actions
	public function getFieldsByFilterAction($filter)
	{
		/** @var \Bitrix\Catalog\RestView\Product $view */
		$view = $this->getViewManager()
			->getView($this);
		$r = $view->getFieldsByFilter($filter);

		if(!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());
			return null;
		}
		else
		{
			return ['PRODUCT'=>$view->prepareFieldInfos(
				$r->getData()
			)];
		}
	}

	public function listAction($select=[], $filter=[], $order=[], $start=0)
	{
		$r = $this->checkPermissionIBlockElementList($filter['IBLOCK_ID']);
		if($r->isSuccess())
		{
			$result = [];
			$list = [];

			$select = empty($select)? array_merge(['*'], $this->getAllowedFieldsProduct()):$select;
			$order = empty($order)? ['ID'=>'ASC']:$order;

			$r = \CIBlockElement::GetList($order, $filter, false, self::getNavData($start), $select);
			while ($l = $r->Fetch())
			{
				$list[$l['ID']] = $l;
			}

			$list = $this->preparePropertyValues($list, $filter['IBLOCK_ID']);

			foreach ($list as $row)
			{
				$result[] = $row;
			}

			return new Page('PRODUCTS', $result, function() use ($filter)
			{
				$list = [];
				$r = \CIBlockElement::GetList([], $filter, false);
				while ($l = $r->Fetch())
					$list[] = $l;

				return count($list);
			});
		}
		else
		{
			$this->addErrors($r->getErrors());
			return null;
		}
	}

	public function getAction($id)
	{
		$r = $this->checkPermissionIBlockElementGet($id);
		if($r->isSuccess())
		{
			$r = $this->exists($id);
			if($r->isSuccess())
			{
				return ['PRODUCT'=>$this->get($id)];
			}
		}
		else
		{
			$this->addErrors($r->getErrors());
			return null;
		}
	}

	public function addAction($fields)
	{
		$r = $this->checkPermissionIBlockElementAdd($fields['IBLOCK_ID']);
		if($r->isSuccess())
		{
			if(isset($fields['IBLOCK_SECTION_ID']) && intval($fields['IBLOCK_SECTION_ID']>0))
			{
				$r = $this->checkPermissionIBlockElementSectionBindUpdate($fields['IBLOCK_SECTION_ID']);
			}
		}

		if($r->isSuccess())
		{
			$id = 0;
			$element = new \CIBlockElement();

			$r = $this->addValidate($fields);
			if($r->isSuccess())
			{
				$groupFields = $this->splitFieldsByEntity($fields);

				$productFields = $groupFields['productFields'];
				$propertyFields = $groupFields['propertyFields'];
				$elementFields = $groupFields['elementFields'];

				$propertyFields = $this->preparePropertyFields($propertyFields);
				$elementFieldsAdd = count($propertyFields)>0 ? array_merge($elementFields, ['PROPERTY_VALUES'=>$propertyFields]):$elementFields;

				$id = $element->Add($elementFieldsAdd);
				if($element->LAST_ERROR<>'')
				{
					$r->addError(new Error($element->LAST_ERROR));
				}
				else
				{
					$productFields['ID'] = $id;

					$r = \Bitrix\Catalog\Model\Product::add($productFields);
					if($r->isSuccess() === false)
					{
						$element::Delete($id);
					}
				}
			}
		}

		if(!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());
			return null;
		}
		else
		{
			return ['ELEMENT'=>$this->get($id)];
		}
	}

	public function updateAction($id, array $fields)
	{
		$r = $this->checkPermissionIBlockElementUpdate($id);
		if($r->isSuccess())
		{
			if(isset($fields['IBLOCK_SECTION_ID']) && intval($fields['IBLOCK_SECTION_ID']>0))
			{
				$r = $this->checkPermissionIBlockElementSectionBindUpdate($fields['IBLOCK_SECTION_ID']);
			}
		}

		if($r->isSuccess())
		{
			$element = new \CIBlockElement();

			$groupFields = $this->splitFieldsByEntity($fields);

			$productFields = $groupFields['productFields'];
			$propertyFields = $groupFields['propertyFields'];
			$elementFields = $groupFields['elementFields'];

			$propertyFields = $this->preparePropertyFields($propertyFields);

			$propertyFields = $this->fillPropertyFieldsDefaultPropertyValues($id, $fields['IBLOCK_ID'], $propertyFields);
			$propertyFields = $this->preparePropertyFieldsUpdate($propertyFields);

			$elementFieldsUpdate = count($propertyFields)>0 ? array_merge($elementFields, ['PROPERTY_VALUES'=>$propertyFields]):$elementFields;

			$r = $this->exists($id);
			if($r->isSuccess())
			{
				$r = $this->updateValidate($elementFieldsUpdate+['ID'=>$id]);
				if($r->isSuccess())
				{
					$element->Update($id, $elementFieldsUpdate);
					if($element->LAST_ERROR<>'')
					{
						$r->addError(new Error($element->LAST_ERROR));
					}
					else
					{
						$r = \Bitrix\Catalog\Model\Product::update($id, $productFields);
					}
				}
			}
		}

		if($r->isSuccess())
		{
			return ['ELEMENT'=>$this->get($id)];
		}
		else
		{
			$this->addErrors($r->getErrors());
			return null;
		}
	}

	public function deleteAction($id)
	{
		$r = $this->checkPermissionIBlockElementDelete($id);
		if($r->isSuccess())
		{
			$r = $this->exists($id);
		}
		if($r->isSuccess())
		{
			$r = \Bitrix\Catalog\Model\Product::delete($id);
			if($r->isSuccess())
			{
				if (!\CIBlockElement::Delete($id))
				{
					if ($ex = self::getApplication()->GetException())
						$r->addError(new Error($ex->GetString(), $ex->GetId()));
					else
						$r->addError(new Error('delete iBlockElement error'));
				}
			}
		}

		if($r->isSuccess())
		{
			return true;
		}
		else
		{
			$this->addErrors($r->getErrors());
			return null;
		}
	}

	public function downloadAction(array $fields)
	{
		$productId = $fields['PRODUCT_ID'];
		$fieldName = $fields['FIELD_NAME'];
		$id = $fields['FILE_ID'];
		$file = [];

		$r = $this->exists($productId);
		if($r->isSuccess())
		{
			$iblockId = $this->get($productId)['IBLOCK_ID'];

			if($this->checkFieldsDownload(['NAME'=>$fieldName, 'IBLOCK_ID'=>$iblockId]) == true)
			{
				$files = [];
				$iBlock = \CIBlock::GetArrayByID($iblockId);

				if ($productId > 0)
				{
					$element = \CIBlockElement::GetList(
						array(),
						array(
							"CATALOG_ID" => $iBlock["ID"],
							"=ID" => $productId,
							"CHECK_PERMISSIONS" => "N",
						),
						false,
						false,
						array("ID", $fieldName)
					);
					while ($res = $element->GetNext())
					{
						if (isset($res[$fieldName]))
						{
							$files[] = $res[$fieldName];
						}
						elseif (isset($res[$fieldName."_VALUE"]))
						{
							if (is_array($res[$fieldName."_VALUE"]))
							{
								$files = array_merge($files, $res[$fieldName."_VALUE"]);
							}
							else
							{
								$files[] = $res[$fieldName."_VALUE"];
							}
						}
					}
				}

				if (!in_array($id, $files))
				{
					$r->addError(new Error('Product file wrong'));
				}
				else
				{
					$file = \CFile::GetFileArray($id);
					if (is_array($file) == false)
					{
						$r->addError(new Error('Product is empty'));
					}
				}
			}
			else
			{
				$r->addError(new Error('Name file field is not available'));
			}
		}

		if($r->isSuccess())
		{
			return \Bitrix\Main\Engine\Response\BFile::createByFileId($file['ID']);
		}
		else
		{
			$this->addErrors($r->getErrors());
			return null;
		}
	}
	//endregion Actions

	protected function splitFieldsByEntity($fields)
	{
		$productFields = [];
		$elementFields = [];
		$propertyFields = [];

		foreach($fields as $name=>$value)
		{
			if(in_array($name, $this->getAllowedFieldsProduct()))
			{
				$productFields[$name] = $value;
			}
			else
			{
				if (preg_match('/^(PROPERTY_\d+)$/', $name))
				{
					$propertyFields[$name] = $value;
				}
				else
				{
					$elementFields[$name] = $value;
				}
			}
		}

		return [
			'productFields'=>$productFields,
			'propertyFields'=>$propertyFields,
			'elementFields'=>$elementFields
		];
	}

	protected function preparePropertyFields($fields)
	{
		$result = [];
		$matches = [];

		foreach($fields as $name=>$value)
		{
			if (preg_match('/^(PROPERTY_)(\d+)$/', $name, $matches))
			{
				$result[$matches[2]] = $value;
			}
		}
		return $result;
	}

	protected function preparePropertyFieldsUpdate($fields)
	{
		$result = [];

		if(count($fields)>0)
		{
			foreach ($fields as $propertyId=>$value)
			{
				$property = [];
				// single
				if(isset($value['VALUE']))
				{
					if(isset($value['VALUE_ID']))
					{
						//update
						$valueId=$value['VALUE_ID'];
						unset($value['VALUE_ID']);
						$property[$valueId]=$value;

					}
					else
					{
						//replace
						$property[]=$value;
					}
				}
				// multi
				else
				{
					if(is_array($value) && count($value)>0)
					{
						foreach ($value as $item)
						{
							if(isset($item['VALUE_ID']))
							{
								//update
								$valueId = $item['VALUE_ID'];
								unset($item['VALUE_ID']);
								$property[$valueId]=$item;
							}
							else
							{
								//replace
								$property[]=$item;
							}
						}
					}
				}

				if(count($property)>0)
				{
					$result[$propertyId]=$property;
				}
			}
		}
		return $result;
	}

	protected function fillPropertyFieldsDefaultPropertyValues($id, $iblockId, $propertyValues)
	{
		$fields = $propertyValues;

		if($id>0 && $iblockId>0)
		{
			if(count($propertyValues)>0)
			{
				$r = \CIBlockElement::GetProperty(
					$iblockId,
					$id,
					'sort', 'asc',
					array('CHECK_PERMISSIONS' => 'N')
				);
				while($property = $r->Fetch())
				{
					if($property['PROPERTY_TYPE'] !== 'F' && !array_key_exists($property['ID'], $propertyValues))
					{
						if(!array_key_exists($property['ID'], $fields['PROPERTY_VALUES']))
							$fields[$property['ID']] = [];

						$fields[$property['ID']][] = [
							'VALUE_ID' => $property['PROPERTY_VALUE_ID'],
							'VALUE' => $property['VALUE'],
							'DESCRIPTION' => $property['DESCRIPTION']
						];
					}
				}
			}
		}
		return $fields;
	}

	protected function exists($id)
	{
		$r = new Result();
		if(isset($this->get($id)['ID']) == false)
			$r->addError(new Error('Product is not exists'));

		return $r;
	}

	protected function get($id)
	{
		$r = \CIBlockElement::GetList(
			[],
			['ID'=>$id],
			false,
			false,
			array_merge(['*'], $this->getAllowedFieldsProduct())
		);

		$row = $r->Fetch();

		if($row)
		{
			$id = $row['ID'];
			$result = $this->preparePropertyValues([$id=>$row], $row['IBLOCK_ID']);
			return $result[$id];
		}

		return [];
	}

	protected function addValidate($fields)
	{
		return $this->checkFields($fields);
	}

	protected function updateValidate($fields)
	{
		return $this->checkFields($fields);
	}

	protected function checkFields($fields)
	{
		$r = new Result();

		if(isset($fields['SECTION_ID']))
		{
			$section = \CIBlockSection::GetByID($fields['SECTION_ID'])->Fetch();
			if(isset($section['ID']) == false)
				$r->addError(new Error('Section is not exists'));
		}
		if(isset($fields['MODIFIED_BY']))
		{
			$user = \CUser::GetByID($fields['MODIFIED_BY'])->Fetch();
			if(isset($user['ID']) == false)
				$r->addError(new Error('User modifiedBy is not exists'));
		}
		if(isset($fields['CREATED_BY']))
		{
			$user = \CUser::GetByID($fields['CREATED_BY'])->Fetch();
			if(isset($user['ID']) == false)
				$r->addError(new Error('User createdBy is not exists'));
		}
		if(isset($fields['PURCHASING_CURRENCY']))
		{
			$currency = \CCurrency::GetByID($fields['PURCHASING_CURRENCY']);
			if(isset($currency['CURRENCY']) == false)
				$r->addError(new Error('Currency purchasingCurrency is not exists'));
		}
		if(isset($fields['VAT_ID']))
		{
			$user = \CCatalogVat::GetByID($fields['VAT_ID'])->Fetch();
			if(isset($user['ID']) == false)
				$r->addError(new Error('VAT vatId is not exists'));
		}

		return $r;
	}

	protected function preparePropertyValues($list, $iblockId)
	{
		if($iblockId>0)
		{
			\CIBlockElement::GetPropertyValuesArray(
				$propertyValues,
				$iblockId,
				['ID'=>array_keys($list)],
				[],
				['USE_PROPERTY_ID' => 'Y']
			);

			foreach ($list as $k=>&$v)
			{
				if(isset($propertyValues[$k]))
				{
					foreach ($propertyValues[$k] as $propId=>$fields)
					{
						$value = null;

						if(isset($fields['PROPERTY_VALUE_ID']))
						{
							if($fields['PROPERTY_TYPE'] === 'L')
							{
								if($fields['MULTIPLE'] === 'Y')
								{
									foreach ($fields['PROPERTY_VALUE_ID'] as $i=>$item)
									{
										$value[] = [
											'VALUE'=>$fields['VALUE_ENUM_ID'][$i],
											'VALUE_ID'=>$fields['PROPERTY_VALUE_ID'][$i]
										];
									}
								}
								else
								{
									$value = [
										'VALUE'=>$fields['VALUE_ENUM_ID'],
										'VALUE_ID'=>$fields['PROPERTY_VALUE_ID']
									];
								}
							}
							else
							{
								if($fields['MULTIPLE'] === 'Y')
								{
									foreach ($fields['PROPERTY_VALUE_ID'] as $i=>$item)
									{
										$value[] = [
											'VALUE'=>$fields['VALUE'][$i],
											'VALUE_ID'=>$fields['PROPERTY_VALUE_ID'][$i]
										];
									}
								}
								else
								{
									$value = [
										'VALUE'=>$fields['VALUE'],
										'VALUE_ID'=>$fields['PROPERTY_VALUE_ID']
									];
								}
							}
						}

						$v['PROPERTY_'.$propId] = $value;
					}
				}
			}
		}

		return $list;
	}

	protected function checkPermissionEntity($name, $arguments=[])
	{
		$name = mb_strtolower($name); //for ajax mode

		if($name == 'getfieldsbyfilter'
			|| $name == 'download'
		)
		{
			$r = $this->checkReadPermissionEntity();
		}
		else
		{
			$r = parent::checkPermissionEntity($name);
		}

		return $r;
	}

	protected function getAllowedFieldsProduct()
	{
		return [
			'TYPE',
			'AVAILABLE',
			'BUNDLE',
			'QUANTITY',
			'QUANTITY_RESERVED',
			'QUANTITY_TRACE',
			'CAN_BUY_ZERO',
			'SUBSCRIBE',
			'VAT_ID',
			'VAT_INCLUDED',
			'PURCHASING_PRICE',
			'PURCHASING_CURRENCY',
			'BARCODE_MULTI',
			'WEIGHT',
			'LENGTH',
			'WIDTH',
			'HEIGHT',
			'MEASURE',
			'RECUR_SCHEME_LENGTH',
			'RECUR_SCHEME_TYPE',
			'TRIAL_PRICE_ID',
			'WITHOUT_ORDER',
			'QUANTITY_TRACE_RAW',
			'PAYMENT_TYPE',
			'SUBSCRIBE_RAW',
			'CAN_BUY_ZERO_RAW'
		];
	}

	protected function checkFieldsDownload($fields)
	{
		$name = $fields['NAME'];
		$iblockId = $fields['IBLOCK_ID'];

		if ($name === "DETAIL_PICTURE")
			return true;
		elseif ($name === "PREVIEW_PICTURE")
			return true;
		elseif ($name === "PICTURE")
			return true;
		elseif (!preg_match("/^PROPERTY_(.+)\$/", $name, $match))
			return false;
		else
		{
			$db_prop = \CIBlockProperty::GetPropertyArray($match[1], $iblockId);
			if(is_array($db_prop) && $db_prop["PROPERTY_TYPE"] === "F")
				return true;
		}
		return false;
	}

	public function addPropertyAction($fields)
	{
		$r = $this->checkPermissionIBlockModify($fields['IBLOCK_ID']);
		if(!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());
			return null;
		}

		$iblockProperty = new \CIBlockProperty();

		$propertyFields = array(
			'ACTIVE' => 'Y',
			'IBLOCK_ID' => $fields['IBLOCK_ID'],
			'NAME' => $fields['NAME'],
			'SORT' => $fields['SORT'] ?? 100,
			'CODE' => $fields['CODE'] ?? '',
			'MULTIPLE' => ($fields['MULTIPLE'] === 'Y') ? 'Y' : 'N',
			'IS_REQUIRED'=> ($fields['IS_REQUIRED'] === 'Y') ? 'Y' : 'N',
			'SECTION_PROPERTY'=> 'N',
		);

		$newID = (int)($iblockProperty->Add($propertyFields));
		if ($newID === 0)
		{
			$this->addError(new \Bitrix\Main\Error($iblockProperty->LAST_ERROR));
			return null;
		}

		return [
			'ID' => $newID,
			'CONTROL_ID' => 'PROPERTY_'.$newID
		];
	}

	//region checkPermissionController
	protected function checkModifyPermissionEntity()
	{
		return $this->checkReadPermissionEntity();
	}

	protected function checkReadPermissionEntity()
	{
		$r = new Result();

		if (!static::getGlobalUser()->CanDoOperation('catalog_read') && !static::getGlobalUser()->CanDoOperation('catalog_price') && !static::getGlobalUser()->CanDoOperation('catalog_view'))
		{
			$r->addError(new Error('Access Denied', 200040300010));
		}
		return $r;
	}
	//endregion checkPermissionController

	//region checkPermissionIBlock
	protected function checkPermissionIBlockElementAdd($iblockId)
	{
		//return $this->checkPermissionIBlockElementList($iblockId);
		return $this->checkPermissionIBlockElementModify($iblockId, 0);
	}

	protected function checkPermissionIBlockElementUpdate($elementId)
	{
		$iblockId = \CIBlockElement::GetIBlockByID($elementId);
		return $this->checkPermissionIBlockElementModify($iblockId, $elementId);
	}

	protected function checkPermissionIBlockModify($iblockId)
	{
		$r = new Result();

		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockRights::UserHasRightTo($iblockId, $iblockId, self::IBLOCK_EDIT);
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300040));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementModify($iblockId, $elementId)
	{
		$r = new Result();

		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_EDIT); //access edit
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300043));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementDelete($elementId)
	{
		$r = new Result();

		$iblockId = \CIBlockElement::GetIBlockByID($elementId);
		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_DELETE); //access delete
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300040));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementGet($elementId)
	{
		$r = new Result();

		$iblockId = \CIBlockElement::GetIBlockByID($elementId);
		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_READ); //access read
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300040));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementList($iblockId)
	{
		$r = new Result();

		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockRights::UserHasRightTo($iblockId, $iblockId, self::IBLOCK_READ);
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300030));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementSectionBindModify($iblockId, $iblockSectionId)
	{
		$r = new Result();

		$arIBlock = \CIBlock::GetArrayByID($iblockId);
		if($arIBlock)
			$bBadBlock = !\CIBlockSectionRights::UserHasRightTo($iblockId, $iblockSectionId, self::IBLOCK_ELEMENT_SECTION_BIND); //access update
		else
			$bBadBlock = true;

		if($bBadBlock)
		{
			$r->addError(new Error('Access Denied', 200040300050));
		}
		return $r;
	}

	protected function checkPermissionIBlockElementSectionBindUpdate($iblockSectionId)
	{
		$iblockId = $this->getIBlockBySectionId($iblockSectionId);
		return $this->checkPermissionIBlockElementSectionBindModify($iblockId, $iblockSectionId);
	}

	protected function getIBlockBySectionId($id)
	{
		$iblockId = 0;

		$section = \CIBlockSection::GetByID($id);
		if ($res = $section->GetNext())
		{
			$iblockId = $res["IBLOCK_ID"];
		}

		return $iblockId;
	}
	//endregion
}