%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/internals/catalog/
Upload File :
Create Path :
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/internals/catalog/provider.php

<?php


namespace Bitrix\Sale\Internals\Catalog;


use Bitrix\Main;
use Bitrix\Sale;
use Bitrix\Sale\Internals\PoolQuantity;
use Bitrix\Sale\Internals\ShipmentRules;

/**
 * Class Provider
 *
 * @package Bitrix\Sale\Internals
 */
final class Provider
{

	const SALE_TRANSFER_PROVIDER_SHIPMENT_NEED_SHIP = true;
	const SALE_TRANSFER_PROVIDER_SHIPMENT_NEED_NOT_SHIP = false;
	const SALE_TRANSFER_PROVIDER_SHIPMENT_NEED_EMPTY = null;

	private static $ignoreErrors = false;


	/**
	 * @param $basketList
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentTypeException
	 */
	public static function getProductData($basketList, array $context)
	{
		$result = new Sale\Result();

		if (empty($context))
		{
			throw new Main\ArgumentNullException('context');
		}

		if (!is_array($basketList) && !($basketList instanceof Sale\BasketBase))
		{
			throw new Main\ArgumentTypeException('basketList');
		}

		$creator = Sale\Internals\ProviderCreator::create($context);
		/** @var Sale\BasketItem $basketItem */
		foreach ($basketList as $basketItem)
		{
			$creator->addBasketItem($basketItem);
		}

		$r = $creator->getProductData();
		if ($r->isSuccess())
		{
			$data = $r->getData();
			if (array_key_exists('PRODUCT_DATA_LIST', $data))
			{
				$result->setData($data);
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	/**
	 * @param Sale\BasketItemBase $basketItem
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentNullException
	 */
	public static function getBundleItems(Sale\BasketItemBase $basketItem, array $context)
	{
		if (empty($context))
		{
			throw new Main\ArgumentNullException('context');
		}

		$result = new Sale\Result();

		$creator = Sale\Internals\ProviderCreator::create($context);
		/** @var Sale\BasketItem $basketItem */
		$creator->addBasketItem($basketItem);

		$r = $creator->getBundleItems();
		if ($r->isSuccess())
		{
			return $r;
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	/**
	 * @param Sale\BasketItemBase $basketItem
	 * @param array|null $context
	 *
	 * @return Sale\Result
	 * @throws Main\ObjectNotFoundException
	 * @throws Main\SystemException
	 */
	public static function checkAvailableQuantityByBasketItem(Sale\BasketItemBase $basketItem, array $context = array())
	{
		$result = new Sale\Result();

		/** @var \Bitrix\Sale\Basket $basket */
		if (!$basket = $basketItem->getCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "Basket" not found');
		}

		$order = $basket->getOrder();
		if (empty($context) && $order)
		{
			$context = static::prepareContext($order, $context);
		}

		$r = static::checkContext($context);
		if (!$r->isSuccess())
		{
			return $r;
		}

		$quantity = $basketItem->getQuantity();
		$productId = $basketItem->getProductId();

		$deltaQuantity = $basketItem->getDeltaQuantity();

		$poolQuantity = 0;

		if ($order)
		{
			if ($deltaQuantity <= 0)
			{
				$result->setData(
					array(
						'AVAILABLE_QUANTITY' => $quantity
					)
				);

				return $result;
			}

			$pool = PoolQuantity::getInstance($order->getInternalId());
			$poolQuantity = $pool->get(PoolQuantity::POOL_RESERVE_TYPE, $productId);
			if (!empty($poolQuantity))
			{
				$tryQuantity = $quantity + $poolQuantity;
				if ($tryQuantity == 0)
				{
					$result->setData(array(
						 'AVAILABLE_QUANTITY' => $quantity
					 ));

					return $result;
				}
			}
		}


		$resultList = array();

		$creator = Sale\Internals\ProviderCreator::create($context);

		/** @var Sale\BasketItem $basketItem */
		$creator->addBasketItem($basketItem);

		$r = $creator->getAvailableQuantity();
		if ($r->isSuccess())
		{
			$providerName = null;
			$providerName = $basketItem->getProviderName();

			if (strval(trim($providerName)) == '')
			{
				$providerName = $basketItem->getCallbackFunction();
			}

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

			$checkProviderName = $providerName;
			$data = $r->getData();
			if (array_key_exists('AVAILABLE_QUANTITY_LIST', $data) && isset($data['AVAILABLE_QUANTITY_LIST'][$checkProviderName]))
			{
				$resultList = $data['AVAILABLE_QUANTITY_LIST'][$checkProviderName];
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		if (isset($resultList[$productId]))
		{
//			$availableQuantity = $deltaQuantity;
			$result->setData(
				array(
					'AVAILABLE_QUANTITY' => $resultList[$productId] - $poolQuantity
				)
			);
		}

		return $result;
	}

	/**
	 * @param Sale\BasketItemBase $basketItem
	 * @param array|null $context
	 *
	 * @return Sale\Result
	 * @throws Main\ObjectNotFoundException
	 * @throws Main\SystemException
	 */
	public static function getAvailableQuantityAndPriceByBasketItem(Sale\BasketItemBase $basketItem, array $context = array())
	{
		$result = new Sale\Result();

		/** @var \Bitrix\Sale\Basket $basket */
		if (!$basket = $basketItem->getCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "Basket" not found');
		}

		$order = $basket->getOrder();

		if (empty($context) && !$order)
		{
			$context = $basket->getContext();
		}

		if (empty($context) && $order)
		{
			$context = static::prepareContext($order, $context);
		}

		$r = static::checkContext($context);
		if (!$r->isSuccess())
		{
			return $r;
		}

		$resultData = array();

		$creator = Sale\Internals\ProviderCreator::create($context);

		/** @var Sale\BasketItem $basketItem */
		$creator->addBasketItem($basketItem);

		$r = $creator->getAvailableQuantityAndPrice();
		if ($r->isSuccess())
		{
			$providerName = $basketItem->getProviderName();

			if (strval($providerName) == '')
			{
				$providerName = $basketItem->getCallbackFunction();
			}

			$providerName = static::clearProviderName($providerName);

			$checkProviderName = $providerName;
			$data = $r->getData();
			if (array_key_exists('PRODUCT_DATA_LIST', $data) && isset($data['PRODUCT_DATA_LIST'][$checkProviderName]))
			{
				$productData = $data['PRODUCT_DATA_LIST'][$checkProviderName];

				if (isset($productData['PRICE_LIST'][$basketItem->getProductId()][$basketItem->getBasketCode()]))
				{
					$resultData['PRICE_DATA'] = $productData['PRICE_LIST'][$basketItem->getProductId()][$basketItem->getBasketCode()];
				}

				if (isset($productData['AVAILABLE_QUANTITY_LIST'][$basketItem->getProductId()]))
				{
					$resultData['AVAILABLE_QUANTITY'] = $productData['AVAILABLE_QUANTITY_LIST'][$basketItem->getProductId()];
				}
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		if (isset($resultData))
		{
			$result->setData(
				$resultData
			);
		}

		return $result;
	}

	/**
	 * @param Sale\Shipment $shipment
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ObjectNotFoundException
	 */
	public static function tryReserveShipment(Sale\Shipment $shipment, array $context = array())
	{
		$result = new Sale\Result();

		/** @var Sale\ShipmentCollection $shipmentCollection */
		if (!$shipmentCollection = $shipment->getCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		/** @var Sale\Order $order */
		$order = $shipmentCollection->getOrder();
		if (!$order)
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		$context = static::prepareContext($order, $context);
		$r = static::checkContext($context);
		if (!$r->isSuccess())
		{
			return $r;
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());

		/** @var Sale\ShipmentItemCollection $shipmentCollection */
		$shipmentItemCollection = $shipment->getShipmentItemCollection();

		$availableQuantityList = array();
		$needQuantityList = array();

		/** @var Sale\Result $r */
		$r = static::getNeedQuantityByShipmentItemCollection($shipmentItemCollection);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}
		else
		{
			$data = $r->getData();
			if (!empty($data['NEED_QUANTITY_LIST']))
			{
				$needQuantityList = $data['NEED_QUANTITY_LIST'];
			}
		}

		if ($r->hasWarnings())
		{
			$result->addWarnings($r->getWarnings());
		}

		if ($shipmentItemCollection->count() == 0)
		{
			return $result;
		}

		$creator = Sale\Internals\ProviderCreator::create($context);
		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$shipmentProductData = $creator->createItemForReserve($shipmentItem);
			$creator->addShipmentProductData($shipmentProductData);
		}

		$r = $creator->getAvailableQuantity();
		if ($r->isSuccess())
		{
			$data = $r->getData();
			if (array_key_exists('AVAILABLE_QUANTITY_LIST', $data))
			{
				$availableQuantityList = $data['AVAILABLE_QUANTITY_LIST'] + $availableQuantityList;
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		if ($r->hasWarnings())
		{
			$result->addWarnings($r->getWarnings());
		}

		if (!empty($needQuantityList) && $result->isSuccess())
		{
			$applyItemsList = array();

			foreach ($availableQuantityList as $providerName => $productAvailableQuantityList)
			{
				$providerName = trim($providerName);
				foreach ($productAvailableQuantityList as $productId => $productAvailableQuantity)
				{
					if (array_key_exists($productId, $needQuantityList[$providerName]))
					{
						if (Sale\Configuration::getProductReservationCondition() != Sale\Configuration::RESERVE_ON_SHIP)
						{
							$poolQuantity = 0;
							if ($order->getId() > 0)
							{
								$poolQuantity = (float)$pool->get(PoolQuantity::POOL_RESERVE_TYPE, $productId);
							}
							$needQuantity = $needQuantityList[$providerName][$productId];

							$productAvailableQuantity -= $poolQuantity;
							$reservedQuantity = ($needQuantity >= $productAvailableQuantity ? $productAvailableQuantity : $needQuantity);

							$applyItemsList[$providerName][$productId] = $reservedQuantity;
						}
					}
					else
					{
						/** @var Sale\ShipmentItem $shipmentItem */
						foreach ($shipmentItemCollection as $shipmentItem)
						{
							$basketItem = $shipmentItem->getBasketItem();

							if ($basketItem->getProductId() == $productId)
							{
								$result->addWarning( new Sale\ResultWarning(Main\Localization\Loc::getMessage('SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY', array(
									'#PRODUCT_NAME#' => $basketItem->getField('NAME')
								)), 'SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY') );
								break;
							}
						}
					}
				}

			}

			if (!empty($applyItemsList))
			{
				$shipmentProductIndex = static::createProductShipmentItemMapByShipmentItemCollection($shipmentItemCollection);

				/** @var Sale\Shipment $shipment */
				if (!$shipment = $shipmentItemCollection->getShipment())
				{
					throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollectionCollection" not found');
				}

				/** @var Sale\ShipmentCollection $shipmentCollection */
				if (!$shipmentCollection = $shipment->getCollection())
				{
					throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
				}

				/** @var Sale\Order $order */
				if (!$order = $shipmentCollection->getOrder())
				{
					throw new Main\ObjectNotFoundException('Entity "Order" not found');
				}

				$pool = PoolQuantity::getInstance($order->getInternalId());

				static::setAvailableQuantityToShipmentItemCollection($pool, $shipmentProductIndex, $applyItemsList);
			}
		}

		return $result;
	}

	/**
	 * @param Sale\ShipmentItem $shipmentItem
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 * @throws \Exception
	 */
	public static function tryReserveShipmentItem(Sale\ShipmentItem $shipmentItem, array $context = array())
	{
		$result = new Sale\Result();

		/** @var Sale\ShipmentItemCollection $shipmentItemCollection */
		$shipmentItemCollection = $shipmentItem->getCollection();
		if (!$shipmentItemCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollection" not found');
		}

		/** @var Sale\Shipment $shipment */
		$shipment = $shipmentItemCollection->getShipment();
		if (!$shipment)
		{
			throw new Main\ObjectNotFoundException('Entity "Shipment" not found');
		}

		/** @var Sale\ShipmentCollection $shipmentCollection */
		$shipmentCollection = $shipment->getCollection();
		if (!$shipmentCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		/** @var Sale\Order $order */
		$order = $shipmentCollection->getOrder();
		if (!$order)
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		$context = static::prepareContext($order, $context);
		$r = static::checkContext($context);
		if (!$r->isSuccess())
		{
			return $r;
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());

		/** @var Sale\ShipmentItemCollection $shipmentCollection */
		$shipmentItemCollection = $shipment->getShipmentItemCollection();

		$availableQuantityList = [];
		$needQuantityList = [];

		$r = static::getNeedQuantityByShipmentItem($shipmentItem);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}
		else
		{
			$data = $r->getData();
			if (!empty($data['NEED_QUANTITY_LIST']))
			{
				$needQuantityList = $data['NEED_QUANTITY_LIST'];
			}
		}

		$creator = Sale\Internals\ProviderCreator::create($context);

		$shipmentProductData = $creator->createItemForReserve($shipmentItem);
		$creator->addShipmentProductData($shipmentProductData);

		$r = $creator->getAvailableQuantity();
		if ($r->isSuccess())
		{
			$data = $r->getData();
			if (array_key_exists('AVAILABLE_QUANTITY_LIST', $data))
			{
				$availableQuantityList = $data['AVAILABLE_QUANTITY_LIST'];
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		if ($r->hasWarnings())
		{
			$result->addWarnings($r->getWarnings());
		}

		if (!empty($needQuantityList) && $result->isSuccess())
		{
			$applyItemsList = [];

			foreach ($availableQuantityList as $providerName => $productAvailableQuantityList)
			{
				$providerName = trim($providerName);
				foreach ($productAvailableQuantityList as $productId => $productAvailableQuantity)
				{
					if (array_key_exists($productId, $needQuantityList[$providerName]))
					{
						if (Sale\Configuration::getProductReservationCondition() != Sale\Configuration::RESERVE_ON_SHIP)
						{
							$poolQuantity = 0;
							if ($order->getId() > 0)
							{
								$poolQuantity = (float)$pool->get(PoolQuantity::POOL_RESERVE_TYPE, $productId);
							}
							$needQuantity = $needQuantityList[$providerName][$productId];

							$productAvailableQuantity -= $poolQuantity;
							$reservedQuantity = ($needQuantity >= $productAvailableQuantity ? $productAvailableQuantity : $needQuantity);

							$applyItemsList[$providerName][$productId] = $reservedQuantity;
						}
					}
					else
					{
						/** @var Sale\ShipmentItem $shipmentItem */
						$basketItem = $shipmentItem->getBasketItem();

						if ($basketItem->getProductId() == $productId)
						{
							$result->addWarning( new Sale\ResultWarning(Main\Localization\Loc::getMessage('SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY', array(
								'#PRODUCT_NAME#' => $basketItem->getField('NAME')
							)), 'SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY') );
							break;
						}
					}
				}

			}

			if (!empty($applyItemsList))
			{
				$shipmentProductIndex = static::createProductShipmentItemMapByShipmentItem($shipmentItem);

				/** @var Sale\Shipment $shipment */
				if (!$shipment = $shipmentItemCollection->getShipment())
				{
					throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollectionCollection" not found');
				}

				/** @var Sale\ShipmentCollection $shipmentCollection */
				if (!$shipmentCollection = $shipment->getCollection())
				{
					throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
				}

				/** @var Sale\Order $order */
				if (!$order = $shipmentCollection->getOrder())
				{
					throw new Main\ObjectNotFoundException('Entity "Order" not found');
				}

				$pool = PoolQuantity::getInstance($order->getInternalId());
				static::setAvailableQuantityToShipmentItemCollection($pool, $shipmentProductIndex, $applyItemsList);
			}
		}

		return $result;
	}

	/**
	 * @param Sale\ShipmentItem $shipmentItem
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 * @throws \Exception
	 */
	public static function tryUnreserveShipmentItem(Sale\ShipmentItem $shipmentItem)
	{
		$result = new Sale\Result();

		/** @var Sale\ShipmentItemCollection $shipmentItemCollection */
		$shipmentItemCollection = $shipmentItem->getCollection();
		if (!$shipmentItemCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollection" not found');
		}

		/** @var Sale\Shipment $shipment */
		$shipment = $shipmentItemCollection->getShipment();
		if (!$shipment)
		{
			throw new Main\ObjectNotFoundException('Entity "Shipment" not found');
		}

		/** @var Sale\ShipmentCollection $shipmentCollection */
		$shipmentCollection = $shipment->getCollection();
		if (!$shipmentCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		/** @var Sale\Order $order */
		$order = $shipmentCollection->getOrder();
		if (!$order)
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());

		/** @var Sale\BasketItem $basketItem */
		$basketItem = $shipmentItem->getBasketItem();
		if (!$basketItem)
		{
			throw new Main\ObjectNotFoundException('Entity "BasketItem" not found');
		}

		$productId = $basketItem->getProductId();

		$reservedQuantity = $shipmentItem->getReservedQuantity();

		if ($reservedQuantity == 0)
		{
			return $result;
		}

		$pool->add(Sale\Internals\PoolQuantity::POOL_RESERVE_TYPE, $productId, -1 * $reservedQuantity);
		if ($shipmentItem)
		{
			$foundItem = false;
			$poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $productId);
			if (!empty($poolItems))
			{
				/** @var Sale\Shipment $poolItem */
				foreach ($poolItems as $poolItem)
				{
					if ($poolItem->getInternalIndex() == $shipmentItem->getInternalIndex())
					{
						$foundItem = true;
						break;
					}
				}
			}

			if (!$foundItem)
			{
				Sale\Internals\ItemsPool::add($order->getInternalId(), $productId, $shipmentItem);
			}
		}

		$r = $shipmentItem->setField('RESERVED_QUANTITY', $shipmentItem->getReservedQuantity() + -1 * $reservedQuantity);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	/**
	 * @param Sale\ShipmentItemCollection $shipmentItemCollection
	 *
	 * @return Sale\Result
	 */
	private static function getNeedQuantityByShipmentItemCollection(Sale\ShipmentItemCollection $shipmentItemCollection)
	{
		$result = new Sale\Result();

		if ($shipmentItemCollection->count() == 0)
		{
			return $result;
		}

		$needQuantityList = array();
		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$basketItem = $shipmentItem->getBasketItem();
			if (!$basketItem)
			{
				continue;
			}

			$productId = $basketItem->getProductId();

			$providerName = $basketItem->getProviderName();
			$providerName = static::clearProviderName($providerName);

			$needQuantity = ($shipmentItem->getQuantity() - $shipmentItem->getReservedQuantity());
			if (!isset($needQuantityList[$providerName]) || !array_key_exists($productId, $needQuantityList[$providerName]))
			{
				$needQuantityList[$providerName][$productId] = 0;
			}

			$needQuantityList[$providerName][$productId] += $needQuantity;
		}

		if (!empty($needQuantityList))
		{
			$result->setData(
				array(
					'NEED_QUANTITY_LIST' => $needQuantityList,
				)
			);
		}
		return $result;
	}

	/**
	 * @param Sale\ShipmentItem $shipmentItem
	 *
	 * @return Sale\Result
	 */
	private static function getNeedQuantityByShipmentItem(Sale\ShipmentItem $shipmentItem)
	{
		$result = new Sale\Result();
		$needQuantityData = array();

		$basketItem = $shipmentItem->getBasketItem();

		$productId = $basketItem->getProductId();

		$providerName = $basketItem->getProviderName();
		$providerName = static::clearProviderName($providerName);

		$needQuantityData[$providerName][$productId] = ($shipmentItem->getQuantity() - $shipmentItem->getReservedQuantity());

		$result->setData(
			array(
				'NEED_QUANTITY_LIST' => $needQuantityData,
			)
		);

		return $result;
	}

	/**
	 * @param Sale\Shipment $shipment
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 * @throws \Exception
	 */
	public static function tryUnreserveShipment(Sale\Shipment $shipment)
	{
		$result = new Sale\Result();

		/** @var Sale\ShipmentCollection $shipmentCollection */
		if (!$shipmentCollection = $shipment->getCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		/** @var Sale\Order $order */
		if (!$order = $shipmentCollection->getOrder())
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());

		/** @var Sale\ShipmentItemCollection $shipmentCollection */
		$shipmentItemCollection = $shipment->getShipmentItemCollection();

		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			/** @var Sale\BasketItem $basketItem */
			if (!$basketItem = $shipmentItem->getBasketItem())
			{
				throw new Main\ObjectNotFoundException('Entity "BasketItem" not found');
			}

			$productId = $basketItem->getProductId();

			$reservedQuantity = $shipmentItem->getReservedQuantity();

			if ($reservedQuantity == 0)
				continue;

			$pool->add(Sale\Internals\PoolQuantity::POOL_RESERVE_TYPE, $productId, -1 * $reservedQuantity);
			if ($shipmentItem)
			{
				$foundItem = false;
				$poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $productId);
				if (!empty($poolItems))
				{
					/** @var Sale\Shipment $poolItem */
					foreach ($poolItems as $poolItem)
					{
						if ($poolItem->getInternalIndex() == $shipmentItem->getInternalIndex())
						{
							$foundItem = true;
							break;
						}
					}
				}

				if (!$foundItem)
				{
					Sale\Internals\ItemsPool::add($order->getInternalId(), $productId, $shipmentItem);
				}
			}

			$r = $shipmentItem->setField('RESERVED_QUANTITY', $shipmentItem->getReservedQuantity() + -1 * $reservedQuantity);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}

		}

		return $result;
	}
	/**
	 * @param $needQuantity
	 * @param $reservedQuantity
	 *
	 * @return float|int
	 */
	private static function countNeedQuantity($needQuantity, $reservedQuantity)
	{
		$setQuantity = $needQuantity;
		if ($needQuantity >= $reservedQuantity)
		{
			$setQuantity = $reservedQuantity;
		}

		return $setQuantity;
	}

	/**
	 * @param Sale\ShipmentItemCollection $shipmentItemCollection
	 *
	 * @return array
	 */
	private static function createProductShipmentItemMapByShipmentItemCollection(Sale\ShipmentItemCollection $shipmentItemCollection)
	{
		static $shipmentProductIndex = array();

		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$shipmentProductIndexData = static::createProductShipmentItemMapByShipmentItem($shipmentItem);
			$shipmentProductIndex = array_merge($shipmentProductIndex,  $shipmentProductIndexData);
		}

		return $shipmentProductIndex;
	}

	/**
	 * @param Sale\ShipmentItem $shipmentItem
	 *
	 * @return array
	 */
	private static function createProductShipmentItemMapByShipmentItem(Sale\ShipmentItem $shipmentItem)
	{
		static $shipmentProductIndex = array();

		/** @var Sale\ShipmentItem $shipmentItem */
		$basketItem = $shipmentItem->getBasketItem();

		$providerName = $basketItem->getProviderName();
		$providerName = static::clearProviderName($providerName);

		$productId = $basketItem->getProductId();
		$index = $shipmentItem->getInternalIndex();

		$shipmentProductIndex[$providerName][$productId][$index] = $shipmentItem;

		return $shipmentProductIndex;
	}

	/**
	 * @param PoolQuantity $pool
	 * @param array $shipmentProductIndex
	 * @param array $items
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 * @throws \Exception
	 */
	private static function setAvailableQuantityToShipmentItemCollection(PoolQuantity $pool, array $shipmentProductIndex, array $items)
	{
		$result = new Sale\Result();

		foreach ($items as $providerName => $productsList)
		{
			foreach ($productsList as $productId => $reservedQuantity)
			{
				if (empty($shipmentProductIndex[$providerName][$productId]))
					continue;

				/**
				 * @var  $shipmetnItemIndex
				 * @var Sale\ShipmentItem $shipmentItem
				 */
				foreach ($shipmentProductIndex[$providerName][$productId] as $shipmetnItemIndex => $shipmentItem)
				{
					$needQuantity = ($shipmentItem->getQuantity() - $shipmentItem->getReservedQuantity());

					$setQuantity = static::countNeedQuantity($needQuantity, $reservedQuantity);

					if ($needQuantity == 0 || $setQuantity == 0 )
						continue;

					$reservedQuantity -= $setQuantity;

					$pool->add(Sale\Internals\PoolQuantity::POOL_RESERVE_TYPE, $productId, $setQuantity);

					/** @var Sale\ShipmentItemCollection $shipmentItemCollection */
					$shipmentItemCollection = $shipmentItem->getCollection();
					if (!$shipmentItemCollection)
					{
						throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
					}

					/** @var Sale\Shipment $shipment */
					$shipment = $shipmentItemCollection->getShipment();
					if (!$shipment)
					{
						throw new Main\ObjectNotFoundException('Entity "Shipment" not found');
					}

					/** @var Sale\ShipmentCollection $shipmentCollection */
					if (!$shipmentCollection = $shipment->getCollection())
					{
						throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
					}

					/** @var Sale\Order $order */
					if (!$order = $shipmentCollection->getOrder())
					{
						throw new Main\ObjectNotFoundException('Entity "Order" not found');
					}

					$foundItem = false;
					$poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $productId);
					if (!empty($poolItems))
					{
						/** @var Sale\Shipment $poolItem */
						foreach ($poolItems as $poolItem)
						{
							if ($poolItem->getInternalIndex() == $shipmentItem->getInternalIndex())
							{
								$foundItem = true;
								break;
							}
						}
					}

					if (!$foundItem)
					{
						Sale\Internals\ItemsPool::add($order->getInternalId(), $productId, $shipmentItem);
					}


					$r = $shipmentItem->setField('RESERVED_QUANTITY', $shipmentItem->getReservedQuantity() + $setQuantity);
					if (!$r->isSuccess())
					{
						$result->addErrors($r->getErrors());
					}
				}

			}
		}
		return $result;
	}

	/**
	 * @param Sale\Shipment $shipment
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ObjectNotFoundException
	 */
	public static function tryShipShipment(Sale\Shipment $shipment, array $context = array())
	{
		$result = new Sale\Result();

		$context = static::prepareContextByShipment($shipment, $context);

		/** @var Sale\ShipmentCollection $shipmentCollection */
		$shipmentCollection = $shipment->getCollection();
		if (!$shipmentCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		$order = $shipmentCollection->getOrder();
		if (!$order)
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());

		/** @var Sale\ShipmentItemCollection $shipmentCollection */
		$shipmentItemCollection = $shipment->getShipmentItemCollection();

		$needShipList = array();
		$creator = Sale\Internals\ProviderCreator::create($context);
		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$creator->addShipmentItem($shipmentItem);
		}

		$r = $creator->isNeedShip();
		if ($r->isSuccess())
		{
			$data = $r->getData();
			if (array_key_exists('IS_NEED_SHIP', $data))
			{
				$needShipList = $data['IS_NEED_SHIP'] + $needShipList;
			}
		}

		$creator = Sale\Internals\ProviderCreator::create($context);
		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$shipmentProductData = $creator->createItemForShip($shipmentItem, $needShipList);
			$creator->addShipmentProductData($shipmentProductData);
		}

		$tryShipProductList = array();

		$isIgnoreErrors = false;

		$r = $creator->tryShip();

		$needSetAfterResult = false;
		if ($r->isSuccess())
		{
			if ($r->hasWarnings())
			{
				$result->addWarnings($r->getWarnings());
			}
			else
			{
				$needSetAfterResult = true;
			}
		}
		else
		{
			$result->addWarnings($r->getErrors());

			if (static::isIgnoreErrors())
			{
				$isIgnoreErrors = true;
				$needSetAfterResult = true;
			}
			else
			{
				$result->addErrors($r->getErrors());
			}

		}

		$data = $r->getData();
		if (array_key_exists('TRY_SHIP_PRODUCTS_LIST', $data))
		{
			$tryShipProductList = $data['TRY_SHIP_PRODUCTS_LIST'] + $tryShipProductList;
		}

		if ($needSetAfterResult && !empty($tryShipProductList))
		{

			if ($isIgnoreErrors)
			{
				foreach ($tryShipProductList as $providerName => &$productList)
				{
					$productList = array_fill_keys(array_keys($productList), true);
				}
			}

			$creator->setItemsResultAfterTryShip($pool, $tryShipProductList);
		}

		return $result;
	}

	/**
	 * @param Sale\ShipmentItemCollection $shipmentItemCollection
	 *
	 * @return array
	 * @throws Main\LoaderException
	 * @throws Main\ObjectNotFoundException
	 */
	public static function createProviderItemsMap(Sale\ShipmentItemCollection $shipmentItemCollection)
	{
		$providerProductList = array();
		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			$basketItem = $shipmentItem->getBasketItem();

			if (!$basketItem)
			{
				throw new Main\ObjectNotFoundException('Entity "BasketItem" not found');
			}
			if ($basketItem->isBundleParent())
			{
				continue;
			}

			$productId = $basketItem->getProductId();
			$providerName = $basketItem->getProvider();
			if (!isset($providerProductList[$providerName][$productId]))
			{
				$fields = array(
					'PRODUCT_ID' => $productId,
					'QUANTITY' => floatval($shipmentItem->getQuantity()),
					'SHIPMENT_ITEM_LIST' => array(),
					'IS_BUNDLE_CHILD' => $basketItem->isBundleChild(),
				);
			}
			else
			{
				$fields = $providerProductList[$providerName][$productId];
				$fields['QUANTITY'] += floatval($shipmentItem->getQuantity());
			}

			$shipmentItemIndex = $shipmentItem->getInternalIndex();
			$barcodeStoreData = static::createMapShipmentItemStoreData($shipmentItem);
			if (!empty($barcodeStoreData))
			{
				$fields['STORE'][$shipmentItemIndex] = $barcodeStoreData;
//				$fields['STORE'][$shipmentItemIndex]['IS_BARCODE_MULTI'] = $basketItem->isBarcodeMulti();
			}

			$fields['SHIPMENT_ITEM_LIST'][$shipmentItemIndex] = $shipmentItem;

			$providerProductList[$providerName][$productId] = $fields;
		}

		return $providerProductList;
	}

	/**
	 * @param array $rulesProducts
	 *
	 * @return array
	 * @throws Main\ObjectNotFoundException
	 */
	public static function createProviderItemsMapByRules(array $rulesProducts)
	{
		$providerProductList = array();

		foreach ($rulesProducts as $ruleData)
		{
			/** @var Sale\ShipmentItem $shipmentItem */
			$shipmentItem = $ruleData['SHIPMENT_ITEM'];
			if (!$shipmentItem)
			{
				throw new Main\ObjectNotFoundException('Entity "ShipmentItem" not found');
			}


			$productId = $ruleData['PRODUCT_ID'];
			$providerName = $ruleData['PROVIDER_NAME'];
			$shipmentItemIndex = $shipmentItem->getInternalIndex();


			if (!isset($providerProductList[$providerName][$productId]))
			{
				$fields = $ruleData;
				unset($fields['SHIPMENT_ITEM']);
				unset($fields['STORE']);
				unset($fields['NEED_RESERVE']);
				unset($fields['NEED_SHIP']);
				$fields['SHIPMENT_ITEM_LIST'] = array();
			}
			else
			{
				$fields = $providerProductList[$providerName][$productId];
				$fields['QUANTITY'] += $ruleData['QUANTITY'];
			}

			if (array_key_exists('NEED_RESERVE', $ruleData))
			{
				$fields['NEED_RESERVE'][$shipmentItemIndex] = $ruleData['NEED_RESERVE'];
			}

			if (array_key_exists('NEED_SHIP', $ruleData))
			{
				$fields['NEED_SHIP'][$shipmentItemIndex] = $ruleData['NEED_SHIP'];
			}

			if (!empty($ruleData['STORE']))
			{
				$fields['STORE'][$shipmentItemIndex] = $ruleData['STORE'][$shipmentItemIndex];
			}

			$fields['SHIPMENT_ITEM_LIST'][$shipmentItemIndex] = $shipmentItem;

			$providerProductList[$providerName][$productId] = $fields;
		}

		return $providerProductList;
	}

	/**
	 * @internal
	 * @param Sale\ShipmentItem $shipmentItem
	 *
	 * @return array|bool
	 * @throws Main\ObjectNotFoundException
	 */
	public static function createMapShipmentItemStoreData(Sale\ShipmentItem $shipmentItem)
	{
		$resultList = array();

		/** @var Sale\BasketItem $basketItem */
		if (!$basketItem = $shipmentItem->getBasketItem())
		{
			throw new Main\ObjectNotFoundException('Entity "BasketItem" not found');
		}

		if ($basketItem->isBundleParent())
		{
			return false;
		}

		/** @var Sale\ShipmentItemStoreCollection $shipmentItemStoreCollection */
		if (!$shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentItemStoreCollection" not found');
		}

		if ($shipmentItemStoreCollection->count() > 0)
		{
			$countBarcode = 0;
			/** @var Sale\ShipmentItemStore $shipmentItemStore */
			foreach ($shipmentItemStoreCollection as $shipmentItemStore)
			{
				/** @var Sale\BasketItem $basketItem */
				if (!$basketItem = $shipmentItemStore->getBasketItem())
				{
					throw new Main\ObjectNotFoundException('Entity "BasketItem" not found');
				}

				//				$basketCode = $basketItem->getBasketCode();
				$productId = $basketItem->getProductId();

				$storeId = $shipmentItemStore->getStoreId();

				if (!isset($resultList[$storeId]))
				{
					$resultList[$storeId] = array(
						'PRODUCT_ID' => $productId,
						'QUANTITY' => 0,
						'STORE_ID' => $storeId,
						'IS_BARCODE_MULTI' => $basketItem->isBarcodeMulti(),
						'BARCODE' => array()
					);
				}

				$barcodeId = ($shipmentItemStore->getId() > 0)? $shipmentItemStore->getId() : 'n'.$countBarcode;
				$countBarcode++;
				$resultList[$storeId]['QUANTITY'] += $basketItem->isBarcodeMulti()? 1 : $shipmentItemStore->getQuantity();
				$resultList[$storeId]['BARCODE'][$barcodeId] = $shipmentItemStore->getBarcode();

			}
		}

		return $resultList;
	}

	/**
	 * @internal
	 * @param $shipmentItemList
	 *
	 * @return array
	 * @throws Main\ObjectNotFoundException
	 * @throws Main\SystemException
	 */
	public static function createMapShipmentItemCollectionStoreData($shipmentItemList)
	{
		$resultList = array();

		/** @var Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemList as $shipmentItem)
		{
			$basketCode = $shipmentItem->getBasketCode();

			if (!isset($resultList[$basketCode]))
			{
				$resultList[$basketCode] = array();
			}
			
			$map = static::createMapShipmentItemStoreData($shipmentItem);
			if (!empty($map) && is_array($map))
			{
				$resultList[$basketCode] = $map + $resultList[$basketCode];
			}
		}

		return $resultList;
	}


	/**
	 * @param Sale\Order $order
	 * @param array|null $context
	 *
	 * @return Sale\Result
	 * @throws Main\SystemException
	 */
	public static function save(Sale\Order $order, array $context = array())
	{
		$result = new Sale\Result();

		$context = static::prepareContext($order, $context);

		$r = static::checkContext($context);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}

		$pool = PoolQuantity::getInstance($order->getInternalId());
		/** @var array $poolQuantitiesList */
		$poolQuantitiesList = $pool->getQuantities(PoolQuantity::POOL_QUANTITY_TYPE);

		/** @var array $poolReservationList */
		$poolReservationList = $pool->getQuantities(PoolQuantity::POOL_RESERVE_TYPE);

		if (empty($poolQuantitiesList) && empty($poolReservationList))
			return $result;

		$rulesMap = ShipmentRules::createOrderRuleMap($order, $pool);

		if (empty($rulesMap))
		{
			return $result;
		}

		$r = ShipmentRules::saveRules($rulesMap, $context);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}

		if ($r->hasWarnings())
		{
			$result->addWarnings($r->getWarnings());
		}

		$pool->reset(PoolQuantity::POOL_QUANTITY_TYPE);
		$pool->reset(PoolQuantity::POOL_RESERVE_TYPE);

		return $result;
	}


	/**
	 * @param Sale\Shipment $shipment
	 *
	 * @return Sale\Order
	 * @throws Main\ObjectNotFoundException
	 */
	public static function getOrderByShipment(Sale\Shipment $shipment)
	{
		/** @var Sale\ShipmentCollection $shipmentCollection */
		$shipmentCollection = $shipment->getCollection();
		if (!$shipmentCollection)
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		$order = $shipmentCollection->getOrder();
		if (!$order)
		{
			throw new Main\ObjectNotFoundException('Entity "Order" not found');
		}

		return $order;
	}



	/**
	 * @param Sale\Shipment $shipment
	 * @param array $context
	 *
	 * @return array
	 * @throws Main\ObjectNotFoundException
	 */
	private static function prepareContextByShipment(Sale\Shipment $shipment, array $context = array())
	{
		$order = static::getOrderByShipment($shipment);

		if (empty($context))
		{
			$context = array(
				'SITE_ID' => $order->getSiteId(),
				'USER_ID' => $order->getUserId(),
				'CURRENCY' => $order->getCurrency(),
			);
		}
		else
		{
			if (empty($context['SITE_ID']))
			{
				$context['SITE_ID'] = $order->getSiteId();
			}

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

			if (empty($context['CURRENCY']))
			{
				$context['CURRENCY'] = $order->getCurrency();
			}
		}

		return $context;
	}

	/**
	 * @param Sale\OrderBase $order
	 * @param array $context
	 *
	 * @return array
	 */
	private static function prepareContext(Sale\OrderBase $order, array $context = array())
	{
		if (empty($context))
		{
			$context = array(
				'SITE_ID' => $order->getSiteId(),
				'USER_ID' => $order->getUserId(),
				'CURRENCY' => $order->getCurrency(),
			);
		}

		if (!empty($context))
		{
			if (empty($context['SITE_ID']))
			{
				$context['SITE_ID'] = $order->getSiteId();
			}

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

			if (empty($context['CURRENCY']))
			{
				$context['CURRENCY'] = $order->getCurrency();
			}
		}

		return $context;
	}

	/**
	 * @param array $context
	 *
	 * @return Sale\Result
	 * @throws Main\ArgumentNullException
	 */
	private static function checkContext(array $context)
	{
		$result = new Sale\Result();

		if (empty($context['SITE_ID']))
		{
			throw new Main\ArgumentNullException('SITE_ID');
		}

		if (empty($context['CURRENCY']))
		{
			throw new Main\ArgumentNullException('CURRENCY');
		}

		return $result;
	}

	/**
	 * @param $module
	 * @param $name
	 *
	 * @return string|null
	 * @throws Main\LoaderException
	 */
	public static function getProviderName($module, $name)
	{
		static $providerProxy = array();
		$code = $module."|".$name;

		if (array_key_exists($code, $providerProxy))
		{
			return $providerProxy[$code];
		}

		$providerName = null;
		if (strval($module) != '' && Main\Loader::includeModule($module) && class_exists($name))
		{
			$provider = static::getProviderEntity($name);
			if ($provider)
			{
				$providerName = $name;
			}
		}

		if ($providerName !== null)
		{
			$providerProxy[$code] = $providerName;
		}

		return $providerName;
	}

	/**
	 * @param $name
	 *
	 * @return mixed|null
	 */
	public static function getProviderEntity($name)
	{
		static $providerEntityProxy = array();
		if (array_key_exists($name, $providerEntityProxy))
		{
			return $providerEntityProxy[$name];
		}

		if (class_exists($name))
		{
			$productProvider = new $name();
			if ($productProvider instanceof Sale\SaleProviderBase || array_key_exists("IBXSaleProductProvider", class_implements($name)))
			{
				$providerEntityProxy[$name] = $productProvider;
				return $productProvider;
			}
		}

		return null;
	}

	/**
	 * @param $name
	 *
	 * @return bool
	 */
	public static function isProviderCallbackFunction($name)
	{
		return (array_key_exists("IBXSaleProductProvider", class_implements($name)));
	}


	/**
	 * @param $providerName
	 *
	 * @return string
	 */
	private static function clearProviderName($providerName)
	{
		if (substr($providerName, 0, 1) == "\\")
		{
			$providerName = substr($providerName, 1);
		}

		return trim($providerName);
	}

	/**
	 * @internal
	 * @param $value
	 */
	public static function setIgnoreErrors($value)
	{
		static::$ignoreErrors = ($value === true);
	}

	/**
	 * @internal
	 * @return bool
	 */
	public static function isIgnoreErrors()
	{
		return static::$ignoreErrors;
	}

}

Zerion Mini Shell 1.0