Your IP : 18.191.116.31


Current Path : /home/bitrix/ext_www/dev.home-comfort.in.ua/bitrix/modules/sale/lib/
Upload File :
Current File : /home/bitrix/ext_www/dev.home-comfort.in.ua/bitrix/modules/sale/lib/basketcomponenthelper.php

<?php
namespace Bitrix\Sale;

use Bitrix\Main,
	Bitrix\Catalog;

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

class BasketComponentHelper
{

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 *
	 * @return int|float
	 */
	public static function getFUserBasketQuantity($fuserId, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$quantity = null;
		if (!empty($_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId]) && is_array($_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId])
			&& array_key_exists($fuserId, $_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId]))
		{
			$quantity = $_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId][$fuserId];
		}

		if ($quantity === null)
		{
			static::updateFUserBasketQuantity($fuserId, $siteId);
			$quantity = $_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId][$fuserId];
		}

		return $quantity;
	}

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 *
	 * @return int|float
	 */
	public static function getFUserBasketPrice($fuserId, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$price = null;
		if (!empty($_SESSION['SALE_USER_BASKET_PRICE'][$siteId]) && is_array($_SESSION['SALE_USER_BASKET_PRICE'][$siteId])
			&& array_key_exists($fuserId, $_SESSION['SALE_USER_BASKET_PRICE'][$siteId]))
		{
			$price = $_SESSION['SALE_USER_BASKET_PRICE'][$siteId][$fuserId];
		}

		if ($price === null)
		{
			static::updateFUserBasketPrice($fuserId, $siteId);
			$price = $_SESSION['SALE_USER_BASKET_PRICE'][$siteId][$fuserId];
		}

		return $price;
	}

	/**
	 * @param int $fuserId
	 * @param int|float $quantity
	 * @param string|null $siteId
	 *
	 * @return void
	 */
	protected static function setFUserBasketQuantity($fuserId, $quantity, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$_SESSION['SALE_USER_BASKET_QUANTITY'][$siteId][$fuserId] = $quantity;
	}

	/**
	 * @param int $fuserId
	 * @param int|float $price
	 * @param string|null $siteId
	 *
	 * @return void
	 */
	protected static function setFUserBasketPrice($fuserId, $price, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}
		$_SESSION['SALE_USER_BASKET_PRICE'][$siteId][$fuserId] = $price;
	}

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 * @param array|null $basketList
	 *
	 * @return void
	 */
	public static function updateFUserBasketPrice($fuserId, $siteId = null, $basketList = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$price = 0;

		if ($basketList === null)
		{
			$basketList = static::getFUserBasketList($fuserId, $siteId);
		}

		if (!empty($basketList) && is_array($basketList))
		{
			$orderData = static::calculatePrice($fuserId, $basketList);
			$price = $orderData['ORDER_PRICE'];
		}

		static::setFUserBasketPrice($fuserId, $price, $siteId);
	}

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 * @param array|null $basketList
	 *
	 * @return void
	 */
	public static function updateFUserBasketQuantity($fuserId, $siteId = null, $basketList = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$quantity = 0;

		if ($basketList === null)
		{
			$basketList = static::getFUserBasketList($fuserId, $siteId);
		}

		if (!empty($basketList) && is_array($basketList))
		{
			$quantity = count($basketList);
		}

		static::setFUserBasketQuantity($fuserId, $quantity, $siteId);
	}

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 *
	 * @return void
	 */
	public static function updateFUserBasket($fuserId, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$basketList = static::getFUserBasketList($fuserId, $siteId);

		static::updateFUserBasketPrice($fuserId, $siteId, $basketList);
		static::updateFUserBasketQuantity($fuserId, $siteId, $basketList);
	}

	/**
	 * @param int $fuserId
	 * @param string|null $siteId
	 *
	 * @return array
	 */
	protected static function getFUserBasketList($fuserId, $siteId = null)
	{
		if ($siteId === null)
		{
			$siteId = SITE_ID;
		}

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);
		$basketClassName = $registry->getBasketClassName();

		$basketList = array();
		$res = $basketClassName::getList(array(
								   'filter' => array(
									   'FUSER_ID' => $fuserId,
									   'ORDER_ID' => null,
									   'LID' => $siteId,
									   'CAN_BUY' => 'Y',
									   'DELAY' => 'N'
								   ),
							   ));
		while($data = $res->fetch())
		{
			if (\CSaleBasketHelper::isSetItem($data))
				continue;

			if (!isset($basketData['BASE_PRICE']) || (float)$basketData['BASE_PRICE'] <= 0)
			{
				$basketData['BASE_PRICE'] = $basketData['PRICE'] + $basketData['DISCOUNT_PRICE'];
			}

			$basketList[] = $data;
		}

		return $basketList;
	}

	/**
	 * @param int $fuserId
	 * @param array $basketList
	 *
	 * @return array
	 */
	protected static function calculatePrice($fuserId, array $basketList)
	{
		$totalPrice = 0;
		$totalWeight = 0;

		foreach ($basketList as $basketData)
		{
			$totalPrice += $basketData["PRICE"] * $basketData["QUANTITY"];
			$totalWeight += $basketData["WEIGHT"] * $basketData["QUANTITY"];
		}

		$orderData = array(
			'SITE_ID' => SITE_ID,
			'ORDER_PRICE' => $totalPrice,
			'ORDER_WEIGHT' => $totalWeight,
			'BASKET_ITEMS' => $basketList
		);

		$basket = Basket::create(SITE_ID);
		$basket->setFUserId($fuserId);
		foreach ($basketList as $oldItem)
		{
			$item = $basket->createItem($oldItem['MODULE'], $oldItem['PRODUCT_ID']);
			unset($oldItem['MODULE'], $oldItem['PRODUCT_ID']);
			$item->initFields($oldItem);
		}
		$orderData['ORDER_PRICE'] = self::calculateBasketCost($basket);
		unset($basket);

		return $orderData;
	}


	/**
	 * @param Main\Event $event
	 *
	 * @return Main\EventResult
	 */
	public static function onSaleBasketItemEntitySaved(Main\Event $event)
	{
		$fuserId = Fuser::getId(true);
		$basketItem = $event->getParameter('ENTITY');

		$originalValues = $event->getParameter('VALUES');
		if ((!$basketItem instanceof BasketItem))
		{
			return new Main\EventResult( Main\EventResult::SUCCESS, null, 'sale');
		}

		/** @var \Bitrix\Sale\Basket $basket */
		if ((!$basket = $basketItem->getCollection())
			|| ($basketItem->getFUserId() != $fuserId)
		)
		{
			return new Main\EventResult( Main\EventResult::SUCCESS, null, 'sale');
		}

		if ($basketItem->isChanged())
		{
			$updateSessionData = false;

			if (!$basket->getOrder())
			{
				if (!$updateSessionData && array_key_exists('QUANTITY', $originalValues))
				{
					$updateSessionData = true;
				}

				if (!$updateSessionData && (array_key_exists('PRICE', $originalValues) && PriceMaths::roundPrecision($originalValues['PRICE']) !== PriceMaths::roundPrecision($basketItem->getPrice())))
				{
					$updateSessionData = true;
				}

				if (!$updateSessionData && (array_key_exists('DISCOUNT_PRICE', $originalValues) && PriceMaths::roundPrecision($originalValues['DISCOUNT_PRICE']) !== PriceMaths::roundPrecision($basketItem->getDiscountPrice())))
				{
					$updateSessionData = true;
				}
			}

			if (!$updateSessionData && (array_key_exists('ORDER_ID', $originalValues) && (intval($originalValues['ORDER_ID'])) == 0 && intval($basketItem->getField('ORDER_ID') > 0)))
			{
				$updateSessionData = true;
			}

			if (!$updateSessionData
				&& (array_key_exists('CAN_BUY', $originalValues) && ($originalValues['CAN_BUY'] !== $basketItem->getField('CAN_BUY'))))
			{
				$updateSessionData = true;
			}

			if (!$updateSessionData
				&& (array_key_exists('DELAY', $originalValues) && ($originalValues['DELAY'] !== $basketItem->getField('DELAY'))))
			{
				$updateSessionData = true;
			}

			if ($updateSessionData)
			{
				/** @var \Bitrix\Sale\Basket $allBasket */
				if ($allBasket = $basketItem->getCollection())
				{

					static::updateFUserBasketPrice($fuserId, SITE_ID);
					static::updateFUserBasketQuantity($fuserId, SITE_ID);
				}
			}
		}

		return new Main\EventResult( Main\EventResult::SUCCESS, null, 'sale');
	}

	/**
	 * @param \Bitrix\Main\Event $event
	 *
	 * @return \Bitrix\Main\EventResult
	 */
	public static function onSaleBasketItemDeleted(Main\Event $event)
	{
		$fuserId = Fuser::getId(true);
		$originalValues = $event->getParameter('VALUES');
		if ($originalValues['FUSER_ID'] != $fuserId)
		{
			return new Main\EventResult( Main\EventResult::SUCCESS, null, 'sale');
		}

		static::updateFUserBasketPrice($fuserId, SITE_ID);
		static::updateFUserBasketQuantity($fuserId, SITE_ID);

		return new Main\EventResult( Main\EventResult::SUCCESS, null, 'sale');
	}

	/**
	 * @param Basket $basket
	 * @param BasketItem|null $item
	 *
	 * @return Result
	 */
	public static function checkQuantityRatio(Basket $basket, BasketItem $item = null)
	{
		$result = new Result();

		$basketItemRatioList = array();
		$ratioList = array();
		$ratioResult = static::getRatio($basket, $item);

		if ($ratioResult->isSuccess())
		{
			$ratioData = $ratioResult->getData();
			if (!empty($ratioData) && is_array($ratioData)
				&& array_key_exists('RATIO_LIST', $ratioData) && !empty($ratioData['RATIO_LIST']) && is_array($ratioData['RATIO_LIST']))
			{
				$ratioList = $ratioData['RATIO_LIST'];
			}
		}

		/** @var BasketItem $basketItem */
		foreach ($basket as $basketItem)
		{
			$foundItem = true;
			if ($item !== null)
			{
				if ($basketItem->getBasketCode() != $item->getBasketCode())
				{
					$foundItem = false;
				}
			}

			if ($foundItem)
			{
				$basketItemRatioList[$basketItem->getBasketCode()] = false;
				if (array_key_exists($basketItem->getBasketCode(), $ratioList))
				{
					$basketItemQuantity = floatval($basketItem->getQuantity());
					$basketItemRatio = floatval($ratioList[$basketItem->getBasketCode()]);

					$mod = roundEx(($basketItemQuantity / $basketItemRatio - round($basketItemQuantity / $basketItemRatio)), 6);

					if ($mod === 0)
					{
						$basketItemRatioList[$basketItem->getBasketCode()] = true;
					}
				}
			}
		}

		if (!empty($basketItemRatioList))
			$result->addData(array('CHECK_RATIO_LIST' => $basketItemRatioList));

		return $result;
	}

	/**
	 * @param Basket $basket
	 * @param BasketItem|null $item
	 *
	 * @return Result
	 */
	public static function correctQuantityRatio(Basket $basket, BasketItem $item = null)
	{
		$result = new Result();

		$checkRatioList = array();
		$checkRatioResult = static::checkQuantityRatio($basket, $item);

		if ($checkRatioResult->isSuccess())
		{
			$checkRatioData = $checkRatioResult->getData();
			if (!empty($checkRatioData) && is_array($checkRatioData)
				&& array_key_exists('CHECK_RATIO_LIST', $checkRatioData) && !empty($checkRatioData['CHECK_RATIO_LIST']) && is_array($checkRatioData['CHECK_RATIO_LIST']))
			{
				$checkRatioList = $checkRatioData['CHECK_RATIO_LIST'];
			}
		}

		$basketItemRatioList = array();
		$ratioList = null;


		/** @var BasketItem $basketItem */
		foreach ($basket as $basketItem)
		{
			$foundItem = true;
			if ($item !== null)
			{
				if ($basketItem->getBasketCode() != $item->getBasketCode())
				{
					$foundItem = false;
				}
			}

			if ($foundItem)
			{
				$basketItemRatioList[$basketItem->getBasketCode()] = false;
				if (array_key_exists($basketItem->getBasketCode(), $checkRatioList) && $checkRatioList[$basketItem->getBasketCode()] === false)
				{
					if ($ratioList === null)
					{
						$ratioList = array();
						$ratioResult = static::getRatio($basket, $item);
						if ($ratioResult->isSuccess())
						{
							$ratioData = $ratioResult->getData();
							if (!empty($ratioData) && is_array($ratioData)
								&& array_key_exists('RATIO_LIST', $ratioData) && !empty($ratioData['RATIO_LIST']) && is_array($ratioData['RATIO_LIST']))
							{
								$ratioList = $ratioData['RATIO_LIST'];
							}
						}
					}
					
					if (!array_key_exists($basketItem->getBasketCode(), $ratioList))
					{
						$result->addError(new ResultError(Main\Localization\Loc::getMessage('SALE_BASKET_COMPONENT_HELPER_PRODUCT_RATIO_NOT_FOUND', array(
							'#PRODUCT_NAME#' => $basketItem->getField('NAME')
						)), 'SALE_BASKET_COMPONENT_HELPER_PRODUCT_RATIO_NOT_FOUND'));
						continue;
					}

					$basketItemQuantity = floatval($basketItem->getQuantity());
					$basketItemRatio = floatval($ratioList[$basketItem->getBasketCode()]);

					$mod = roundEx(($basketItemQuantity / $basketItemRatio - round($basketItemQuantity / $basketItemRatio)), 6);

					if ($mod != 0)
					{
						$quantity = floor(ceil($basketItemQuantity) / $basketItemRatio) * $basketItemRatio;
						$r = $basketItem->setField('QUANTITY', $quantity);
						if (!$r->isSuccess())
						{
							$result->addErrors($r->getErrors());
						}
						elseif ($quantity <= 0)
						{
							$result->addWarning(new ResultWarning(Main\Localization\Loc::getMessage('SALE_BASKET_COMPONENT_HELPER_PRODUCT_NOT_ENOUGH_QUANTITY', array(
								'#PRODUCT_NAME#' => $basketItem->getField('NAME')
							)), 'SALE_BASKET_COMPONENT_HELPER_PRODUCT_NOT_ENOUGH_QUANTITY'));
						}
					}
				}
			}
		}

		return $result;
	}

	/**
	 * @param Basket $basket
	 * @param BasketItem|null $item
	 *
	 * @return Result
	 * @throws Main\LoaderException
	 */
	public static function getRatio(Basket $basket, BasketItem $item = null)
	{
		$result = new Result();
		$ratioList = array();
		if (Main\Loader::includeModule('catalog'))
		{
			static $cacheRatio = array();
			$map = array();
			$elementList = array();

			/** @var BasketItem $basketItem */
			foreach ($basket as $basketItem)
			{
				$code = $basketItem->getBasketCode();
				if ($item !== null && $item->getBasketCode() != $code)
				{
					continue;
				}

				$hash = md5((strval($basketItem->getField("PRODUCT_PROVIDER_CLASS")) != '' ? $basketItem->getField("PRODUCT_PROVIDER_CLASS"): "")."|".(strval($basketItem->getField("MODULE")) != '' ? $basketItem->getField("MODULE"): "")."|".$basketItem->getField("PRODUCT_ID"));

				if (array_key_exists($hash, $cacheRatio))
				{
					$ratioList[$code] = $cacheRatio[$hash];
				}
				else
				{
					$elementList[$basketItem->getField("PRODUCT_ID")] = $basketItem->getField("PRODUCT_ID");
				}

				if (!isset($map[$basketItem->getField("PRODUCT_ID")]))
				{
					$map[$basketItem->getField("PRODUCT_ID")] = array();
				}

				$map[$basketItem->getField("PRODUCT_ID")][] = $code;
			}

			if (!empty($elementList))
			{
				$res = Catalog\MeasureRatioTable::getList(array(
					'select' => array('*'),
					'filter' => array('@PRODUCT_ID' => $elementList, '=IS_DEFAULT' => 'Y')
				));
				while ($ratioData = $res->fetch())
				{
					if (empty($map[$ratioData["PRODUCT_ID"]]))
						continue;

					foreach ($map[$ratioData["PRODUCT_ID"]] as $key)
					{
						$ratioList[$key] = $ratioData["RATIO"];

						if (!$basketItem = $basket->getItemByBasketCode($key))
							continue;

						$hash = md5((strval($basketItem->getField("PRODUCT_PROVIDER_CLASS")) != '' ? $basketItem->getField("PRODUCT_PROVIDER_CLASS"): "")."|".(strval($basketItem->getField("MODULE")) != '' ? $basketItem->getField("MODULE"): "")."|".$basketItem->getField("PRODUCT_ID"));

						$cacheRatio[$hash] = $ratioData["RATIO"];
					}
					unset($key);
				}
				unset($ratioData, $dbRatio);
			}
			unset($elementList, $map);
		}

		if (!empty($ratioList))
			$result->addData(array('RATIO_LIST' => $ratioList));

		return $result;
	}

	/**
	 * @param Basket $basket
	 *
	 * @return int|float
	 */
	protected static function calculateBasketCost(Basket $basket)
	{
		if ($basket->count() == 0)
			return 0;

		$oldApiStatus = Compatible\DiscountCompatibility::isUsed(); // TODO: remove this code after refactoring DiscountCompatibility
		if ($oldApiStatus)
			Compatible\DiscountCompatibility::stopUsageCompatible();
		DiscountCouponsManager::freezeCouponStorage();
		$basket->refreshData(array('PRICE', 'COUPONS'));
		$discounts = Discount::loadByBasket($basket);
		$discounts->calculate();
		$discountResult = $discounts->getApplyResult();
		DiscountCouponsManager::unFreezeCouponStorage();
		if ($oldApiStatus)
			Compatible\DiscountCompatibility::revertUsageCompatible();

		if (empty($discountResult['PRICES']['BASKET']))
			return 0;

		$result = 0;
		$discountResult = $discountResult['PRICES']['BASKET'];
		/** @var BasketItem $basketItem */
		foreach ($basket as $basketItem)
		{
			if (!$basketItem->canBuy())
				continue;
			$code = $basketItem->getBasketCode();
			if (!empty($discountResult[$code]))
				$result += $discountResult[$code]['PRICE'] * $basketItem->getQuantity();
			unset($code);
		}
		unset($basketItem);
		unset($discountResult);

		return $result;
	}
}