Your IP : 3.17.128.236


Current Path : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/sale/lib/basket/
Upload File :
Current File : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/sale/lib/basket/baserefreshstrategy.php

<?php

namespace Bitrix\Sale\Basket;

use Bitrix\Currency\CurrencyManager;
use Bitrix\Main;
use Bitrix\Main\Config\Option;
use Bitrix\Main\Type\DateTime;
use Bitrix\Sale\BasketBase;
use Bitrix\Sale\BasketItem;
use Bitrix\Sale\BasketItemBase;
use Bitrix\Sale\EventActions;
use Bitrix\Sale\Fuser;
use Bitrix\Sale\Internals\PoolQuantity;
use Bitrix\Sale\Internals\SiteCurrencyTable;
use Bitrix\Sale\OrderBase;
use Bitrix\Sale\PriceMaths;
use Bitrix\Sale\Internals\Catalog\Provider;
use Bitrix\Sale\ProviderBase;
use Bitrix\Sale\Registry;
use Bitrix\Sale\Result;
use Bitrix\Sale\ResultError;

Main\Localization\Loc::loadMessages(__FILE__);

abstract class BaseRefreshStrategy
{
	const REFRESH_FIELD = 'DATE_REFRESH';

	protected $data;
	protected $refreshGap;

	public function __construct(array $data = null)
	{
		$this->data = $data;
	}

	protected function getBasketItemRefreshTimestamp(BasketItemBase $basketItem)
	{
		/** @var DateTime $refreshDate */
		$refreshDate = $basketItem->getField(self::REFRESH_FIELD);
		if ($refreshDate)
		{
			return $refreshDate->getTimestamp();
		}

		return 0;
	}

	protected function isBasketItemChanged(BasketItemBase $basketItem)
	{
		$changedValues = $basketItem->getFields()->getChangedValues();

		// remove not meaningful field
		unset($changedValues[self::REFRESH_FIELD]);

		return !empty($changedValues);
	}

	protected function getBasketRefreshGapTime()
	{
		if (!isset($this->refreshGap))
		{
			$this->refreshGap = (int)Option::get('sale', 'basket_refresh_gap', 0);
		}

		return $this->refreshGap;
	}

	protected function getBasketIndexList(BasketBase $basket)
	{
		$basketIndexList = array();

		/** @var BasketItemBase $basketItem */
		foreach ($basket as $basketItem)
		{
			$providerName = $basketItem->getProviderName();

			if (strval(trim($providerName)) == '')
			{
				$callbackFunction = $basketItem->getCallbackFunction();
				if (!empty($callbackFunction))
				{
					$providerName = $callbackFunction;
				}
				else
				{
					$providerName = null;
				}
			}

			if (!empty($providerName) && $providerName[0] == "\\")
			{
				$providerName = ltrim($providerName, '\\');
			}

			$basketIndexList[$providerName][$basketItem->getProductId()][] = $basketItem;
		}

		return $basketIndexList;
	}

	protected function updateBasket(BasketBase $basket, array $productDataList)
	{
		$result = new Result();
		$changedBasketItems = array();

		$basketIndexList = $this->getBasketIndexList($basket);

		foreach ($productDataList as $providerName => $productValueList)
		{
			foreach ($productValueList as $productId => $productData)
			{
				if (empty($basketIndexList[$providerName][$productId]))
				{
					$basketIndexList[$providerName][$productId][] = $basket->createItem($productData['MODULE_ID'], $productData['PRODUCT_ID']);
				}

				/** @var BasketItemBase $item */
				foreach ($basketIndexList[$providerName][$productId] as $item)
				{
					if ($item && isset($productData['DELETE']) && $productData['DELETE'])
					{
						$item->delete();
						continue;
					}

					$r = $this->updateBasketItem($item, $productData);
					if (!$r->isSuccess())
					{
						$result->addErrors($r->getErrors());
					}

					if ($this->isBasketItemChanged($item))
					{
						$changedBasketItems[] = $item->getBasketCode();
					}
				}
			}
		}

		$result->addData(array(
			'CHANGED_BASKET_ITEMS' => $changedBasketItems
		));

		return $result;
	}

	protected function updateBasketItem(BasketItemBase $item, $data)
	{
		$result = new Result();

		if (!empty($data))
		{
			$preparedData = $this->prepareData($item, $data);

			if (!$preparedData)
			{
				return $result;
			}

			if (!$item->isCustomPrice() && isset($preparedData['DISCOUNT_PRICE']) && isset($preparedData['BASE_PRICE']))
			{
				$preparedData['PRICE'] = $preparedData['BASE_PRICE'] - $preparedData['DISCOUNT_PRICE'];
			}

			if (empty($preparedData)
				|| (isset($preparedData['QUANTITY']) && $preparedData['QUANTITY'] == 0)
				|| (isset($data['ACTIVE']) && $data['ACTIVE'] == 'N'))
			{
				$preparedData['CAN_BUY'] = 'N';
				unset($preparedData['QUANTITY']);
			}

			/** @var Main\Event $event */
			$event = new Main\Event('sale', EventActions::EVENT_ON_BASKET_ITEM_REFRESH_DATA, array(
				'ENTITY' => $item,
				'VALUES' => $data,
				'PREPARED_VALUES' => $preparedData
			));
			$event->send();

			if ($event->getResults())
			{
				/** @var Main\EventResult $eventResult */
				foreach ($event->getResults() as $eventResult)
				{
					if ($eventResult->getType() == Main\EventResult::ERROR)
					{
						$errorMsg = new ResultError(
							Main\Localization\Loc::getMessage('SALE_EVENT_ON_BASKET_ITEM_REFRESH_DATA'),
							'SALE_EVENT_ON_BASKET_ITEM_REFRESH_DATA'
						);
						if ($eventResultData = $eventResult->getParameters())
						{
							if (isset($eventResultData) && $eventResultData instanceof ResultError)
							{
								/** @var ResultError $errorMsg */
								$errorMsg = $eventResultData;
							}
						}

						$result->addError($errorMsg);
					}
				}
			}

			if ($this->getBasketRefreshGapTime() !== 0)
			{
				$item->setFieldNoDemand(self::REFRESH_FIELD, new DateTime());
			}
		}
		else
		{
			$preparedData['CAN_BUY'] = 'N';
		}

		/** @var Result $r */
		$r = $this->applyRefreshResult($item, $preparedData);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	protected function prepareData(BasketItemBase $item, $data)
	{
		if (empty($data))
		{
			return false;
		}

		$preparedData = array();

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);
		/** @var BasketItemBase $basketItemClassName */
		$basketItemClassName = $registry->getBasketItemClassName();

		if (!empty($data['PRICE_LIST']))
		{
			$basketItemCode = $item->getBasketCode();

			if (!empty($data['PRICE_LIST'][$basketItemCode]))
			{
				$priceData = $data['PRICE_LIST'][$basketItemCode];

				if (!isset($priceData['QUANTITY']) && isset($priceData['AVAILABLE_QUANTITY']))
				{
					$priceData['QUANTITY'] = $priceData['AVAILABLE_QUANTITY'];
				}

				$data = $priceData + $data;
				if (isset($data['QUANTITY']))
				{
					$data['QUANTITY'] = $data['AVAILABLE_QUANTITY'] = static::getAvailableQuantityFromPool($item, $data['QUANTITY']);
				}
			}
			else
			{
				return false;
			}
		}

		$settableFields = $basketItemClassName::getSettableFieldsMap();
		$roundFields = array_fill_keys($basketItemClassName::getRoundFields(), true);

		foreach ($data as $key => $value)
		{
			if (isset($settableFields[$key]))
			{
				if ($key === 'NAME' && $item->getField('NAME') != '')
					continue;

				if ($key === 'PRICE' && $item->isCustomPrice())
				{
					$value = $item->getPrice();
				}

				if (isset($roundFields[$key]))
				{
					$value = PriceMaths::roundPrecision($value);
				}

				$preparedData[$key] = $value;
			}
		}

		return $preparedData;
	}

	protected static function getAvailableQuantityFromPool(BasketItemBase $item, $quantity)
	{
		$availableQuantity = $quantity;
		/** @var BasketBase $basket */
		$basket = $item->getCollection();
		if (!$basket)
		{
			throw new Main\ObjectNotFoundException('Basket');
		}

		$order = $basket->getOrder();
		if ($order && $order->getId() > 0)
		{
			$productId = $item->getProductId();

			$poolQuantity = 0;

			$pool = PoolQuantity::getInstance($order->getInternalId());
			$reserveQuantityList = $pool->getQuantities(PoolQuantity::POOL_RESERVE_TYPE);
			$quantityList = $pool->getQuantities(PoolQuantity::POOL_QUANTITY_TYPE);

			if ($quantityList[$productId])
				$poolQuantity += $quantityList[$productId];

			if ($reserveQuantityList[$productId])
				$poolQuantity += $reserveQuantityList[$productId];

			if ($poolQuantity < 0)
			{
				$poolQuantity = abs($poolQuantity);
			}

			if (($quantity + $poolQuantity) >= $item->getQuantity())
			{
				$availableQuantity = $item->getQuantity();
			}
		}

		return $availableQuantity;
	}


	protected function getProviderContext(BasketBase $basket)
	{
		global $USER;

		$context = array();

		$order = $basket->getOrder();
		/** @var OrderBase $order */
		if ($order)
		{
			$context['USER_ID'] = $order->getUserId();
			$context['SITE_ID'] = $order->getSiteId();
			$context['CURRENCY'] = $order->getCurrency();
		}
		else
		{
			/** @var BasketItem $basketItem */
			$basketItem = $basket->rewind();
			if (!$basketItem)
			{
				return $context;
			}

			$siteId = $basketItem->getField('LID');
			$fuserId = $basketItem->getFUserId();
			$currency = $basketItem->getCurrency();

			$userId = Fuser::getUserIdById($fuserId);

			if (empty($context['SITE_ID']))
			{
				$context['SITE_ID'] = $siteId;
			}

			if (empty($context['USER_ID']) && $userId > 0)
			{
				$context['USER_ID'] = $userId;
			}

			if (empty($context['CURRENCY']))
			{
				if (empty($currency))
				{
					$currency = SiteCurrencyTable::getSiteCurrency($siteId);
				}

				if (!empty($currency) && CurrencyManager::checkCurrencyID($currency))
				{
					$context['CURRENCY'] = $currency;
				}

			}
		}

		return $context;
	}

	protected function getBasketItemsToRefresh(BasketBase $basket, $quantity = 0)
	{
		$itemsToRefresh = array();
		$currentItemsCount = 0;

		$basketRefreshStart = time();
		$refreshGap = $this->getBasketRefreshGapTime();

		foreach ($basket as $basketItem)
		{
			if ($quantity > 0 && $currentItemsCount >= $quantity)
			{
				break;
			}

			$basketItemLastRefresh = $this->getBasketItemRefreshTimestamp($basketItem);
			if ($basketRefreshStart - $basketItemLastRefresh >= $refreshGap)
			{
				$itemsToRefresh[] = $basketItem;
				$currentItemsCount++;
			}
		}

		return $itemsToRefresh;
	}

	/**
	 * @param BasketBase $basket
	 * @param array      $itemsToRefresh
	 *
	 * @return Result
	 */
	protected function getProviderResult(BasketBase $basket, $itemsToRefresh = array())
	{
		if (!empty($itemsToRefresh))
		{
			$context = $basket->getContext();
			$result = Provider::getProductData($itemsToRefresh, $context);
		}
		else
		{
			$result = new Result();
			$result->setData(array(
				'PRODUCT_DATA_LIST' => array()
			));
		}

		return $result;
	}

	/**
	 * @param BasketItemBase $item
	 * @param                $fields
	 *
	 * @return Result
	 */
	protected function applyRefreshResult(BasketItemBase $item, $fields)
	{
		return $item->setFields($fields);
	}

	/**
	 * @param BasketBase $basket
	 *
	 * @return Result
	 */
	abstract protected function getProductData(BasketBase $basket);

	/**
	 * @param BasketBase $basket
	 *
	 * @return Result
	 */
	public function refresh(BasketBase $basket)
	{
		if (!$basket->isEmpty())
		{
			$result = $this->getProductData($basket);
			if ($result->isSuccess())
			{
				$productData = $result->get('PRODUCT_DATA_LIST');
				if (!empty($productData))
				{
					$r = $this->updateBasket($basket, $productData);
					if ($r->isSuccess())
					{
						$result->addData($r->getData());
					}
					else
					{
						$result->addErrors($r->getErrors());
					}
				}
				else
				{
					$result->addData(array(
						'CHANGED_BASKET_ITEMS' => array()
					));
				}
			}
		}
		else
		{
			$result = new Result();
			$result->setData(array(
				'PRODUCT_DATA_LIST' => array(),
				'CHANGED_BASKET_ITEMS' => array()
			));
		}

		return $result;
	}
}