Your IP : 3.133.135.89


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

<?php
namespace Bitrix\Sale\Archive;

use Bitrix\Main,
	Bitrix\Sale,
	Bitrix\Main\Config\Option,
	Bitrix\Sale\Internals,
	Bitrix\Main\Type,
	Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

/**
 * Class manages of orders's archiving, restoring entries from database
 *
 * @package Bitrix\Sale\Archive
 */
class Manager
{
	const SALE_ARCHIVE_VERSION = 1;

	/**
	 * @return array
	 */
	public static function getOrderFieldNames()
	{
		return array(
			"ACCOUNT_NUMBER", "USER_ID", "PRICE", "SUM_PAID", "CURRENCY", "STATUS_ID", "PAYED", "DEDUCTED", "CANCELED",
			"LID", "PERSON_TYPE_ID", "XML_ID", "ID_1C", "DATE_INSERT", "RESPONSIBLE_ID", "COMPANY_ID"
		);
	}

	/**
	 * @return array
	 */
	public static function getBasketFieldNames()
	{
		return array(
			"PRODUCT_ID", "PRODUCT_PRICE_ID", "NAME", "PRICE", "MODULE", "QUANTITY", "WEIGHT", "DATE_INSERT",
			"CURRENCY", "PRODUCT_XML_ID", "MEASURE_NAME", "TYPE", "SET_PARENT_ID", "MEASURE_CODE", "BASKET_DATA"
		);
	}

	/**
	 * Archive orders by filter
	 *
	 * @param array $filter			Filter the selection.
	 * @param int $limit		Limit the selection orders.
	 * @param int $timeExecution		Limits the maximum execution time.
	 *
	 * @return Sale\Result $result
	 *
	 * @throws Main\ArgumentNullException
	 * @throws \Exception
	 */
	public static function archiveOrders($filter = array(), $limit = null, $timeExecution = null)
	{
		$idList = array();
		$orderListArchive = array();
		$result = new Sale\Result();
		$countArchived = null;

		if ((int)$timeExecution)
		{
			@set_time_limit(0);
		}

		$params["filter"] = $filter;
		$params["order"] = array('ID' => "ASC");
		if ((int)$limit)
		{
			$params["limit"] = (int)$limit;
		}
		
		$ordersList = Sale\Order::getList($params);

		while ($order = $ordersList->fetch())
		{
			$orderListArchive[$order['ID']]['ORDER'] = $order;
			$idList[] = $order['ID'];
		}

		if (empty($idList))
		{
			$result->setData(array("count" => null));
			$result->addWarning(new Main\Error(Loc::getMessage("ARCHIVE_ORDER_NOT_FOUND")));
			return $result;
		}

		$idListChunks = array_chunk($idList, 999);

		foreach ($idListChunks as $idOrdersList)
		{
			$sortedOrderData = static::collectOrderData($idOrdersList);

			foreach ($idOrdersList as $id)
			{
				$orderList = array_merge($orderListArchive[$id], $sortedOrderData[$id]);
				$preparedOrderData = array_intersect_key($orderList['ORDER'], array_flip(static::getOrderFieldNames()));
				$preparedOrderData['ORDER_ID'] = $id;
				$preparedOrderData['DATE_ARCHIVED'] = new Type\DateTime();
				$preparedOrderData['VERSION'] = static::SALE_ARCHIVE_VERSION;
				$basketItems = $orderList['BASKET_ITEMS'];
				unset($orderList['BASKET_ITEMS']);
				$preparedOrderData['ORDER_DATA'] = serialize($orderList);
				$additionResult = Internals\OrderArchiveTable::add($preparedOrderData);

				if ($additionResult->isSuccess())
				{
					$archivedOrderId = $additionResult->getId();
					$basketItemIdList = array();
					if (is_array($basketItems))
					{
						foreach ($basketItems as $item)
						{
							$preparedBasketItems = array_intersect_key($item, array_flip(static::getBasketFieldNames()));
							$preparedBasketItems['ARCHIVE_ID'] = $archivedOrderId;
							$preparedBasketItems['BASKET_DATA'] = serialize($item);

							if (empty($preparedBasketItems['DATE_INSERT']))
							{
								$zeroDate = new \DateTime();
								$zeroDate->setDate(0,0,0);
								$zeroDate->setTime(0,0,0);
								$preparedBasketItems['DATE_INSERT'] = Type\DateTime::createFromPhp($zeroDate);
							}

							$additionBasketResult = Internals\BasketArchiveTable::add($preparedBasketItems);
							if ($additionBasketResult->isSuccess())
							{
								$basketItemIdList[] = $additionBasketResult->getId();
							}
							else
							{
								$additionResult->addErrors($additionBasketResult->getErrors());
								break;
							}
						}
					}

					if ($additionResult->isSuccess())
					{
						foreach ($orderList['SHIPMENT'] as $shipmentData)
						{
							if ($shipmentData["RESERVED"] == "Y" &&	$shipmentData["DEDUCTED"] == "N")
							{
								$order = Sale\Order::load($id);
								if ($shipmentCollection = $order->getShipmentCollection())
								{
									foreach ($shipmentCollection as $shipment)
									{
										$shipment->tryUnreserve();
									}

									$order->save();
								}
								
								break;
							}
						}
						Sale\Order::deleteNoDemand($id);
						$countArchived++;
					}
					else
					{
						Internals\OrderArchiveTable::delete($archivedOrderId);
						foreach ($basketItemIdList as $archivedBasketItemId)
						{
							Internals\BasketArchiveTable::delete($archivedBasketItemId);
						}
					}
				}

				if (!$additionResult->isSuccess())
				{
					$errorMessages = $additionResult->getErrorMessages();
					foreach ($errorMessages as $error)
					{
						$result->addError(new Main\Error(Loc::getMessage("ARCHIVE_ERROR_ORDER_MESSAGE", array("#ID#" => $id)).": ".$error));
					}
				}

				if ((int)$timeExecution && (getmicrotime() - START_EXEC_TIME > $timeExecution))
				{
					$result->setData(array("count" => $countArchived));
					return $result;
				}
			}
		}

		$result->setData(array("count" => $countArchived));

		return $result;
	}

	/**
	 * Archive orders that are selected by module's settings.
	 * 
	 * Used in agents.
	 * 
	 * @param int $limit		Limit the selection orders.
	 * @param int $timeExecution		Limits the maximum execution time.
	 *
	 * @return Sale\Result
	 *
	 * @throws Main\SystemException
	 */
	public static function archiveByOptions($limit = null, $timeExecution = null)
	{
		$filter = Option::get('sale', 'archive_params');

		if (strlen($filter) <= 0)
		{
			throw new Main\SystemException("Settings of order's archiving are null or empty");
		}

		$filter = unserialize($filter);

		if (isset($filter['PERIOD']))
		{
			if ((int)$filter['PERIOD'] > 0)
			{
				$date = new Type\DateTime();
				$latestDate = $date->add('-'.(int)$filter['PERIOD'].' day');
				$filter['<=DATE_INSERT'] = $latestDate;
			}

			unset($filter['PERIOD']);
		}

		return static::archiveOrders($filter, $limit, $timeExecution);
	}

	/**
	 * Used in agents. Manage execution of agent.
	 *
	 * @param int $limit		Limit the selection orders.
	 * @param int $maxTime		Maximum execution time of agent.
	 *
	 * @return string
	 *
	 * @throws Main\ArgumentNullException
	 */
	public static function archiveOnAgent($limit, $maxTime = null)
	{
		global $USER;
		$agentId = null;

		$limit = (int)$limit ? (int)$limit : 10;
		$maxTime = (int)$maxTime ? (int)$maxTime : null;

		$agentsList = \CAgent::GetList(array("ID"=>"DESC"), array(
			"MODULE_ID" => "sale",
			"NAME" => "\\Bitrix\\Sale\\Archive\\Manager::archiveOnAgent(%",
		));
		while($agent = $agentsList->Fetch())
		{
			$agentId = $agent["ID"];
		}

		if ($agentId)
		{
			if (!(isset($USER) && $USER instanceof \CUser))
			{
				$USER = new \CUser();
			}

			$result = static::archiveByOptions($limit, $maxTime);

			$resultData = $result->getData();
			if ($resultData['count'])
			{
				\CAgent::Update($agentId, array("AGENT_INTERVAL" => 60*5));

			}
			else
			{
				\CAgent::Update($agentId, array("AGENT_INTERVAL" => 24*60*60));
			}
		}
		else
		{
			\CAgent::AddAgent("\\Bitrix\\Sale\\Archive\\Manager::archiveOnAgent(".$limit.",".$maxTime.");", "sale", "N", 24*60*60, "", "Y");
		}

		return "\\Bitrix\\Sale\\Archive\\Manager::archiveOnAgent(".$limit.",".$maxTime.");";
	}


	/**
	 * Select and collect order's data to array
	 *
	 * @param array $idList			Ids list of orders.
	 *
	 * @return array
	 * @throws Main\ArgumentException
	 */
	protected static function collectOrderData($idList = array())
	{
		$sortedOrderReferences = array();

		$sortedOrderProperties = static::collectOrderProperties($idList);
		$sortedPayments = static::collectPayments($idList);
		$sortedShipments = static::collectShipments($idList);
		$sortedBasketItems = static::collectBaskets($idList);
		$couponList = static::collectCoupons($idList);
		$sortedDataDiscount = static::collectDiscountData($idList);
		$sortedDiscountRules = static::collectRules($idList);

		foreach ($idList as $id)
		{
			if (isset($couponList[$id]))
				$discountData['COUPON_LIST'] = $couponList[$id];

			$discountData['ORDER_DATA'] = isset($sortedDataDiscount[$id]) ? $sortedDataDiscount[$id] : array();
			$discountData['RULES_DATA'] = isset($sortedDiscountRules[$id]) ? $sortedDiscountRules[$id] : array();
			$sortedOrderReferences[$id] = array(
				"PROPERTIES" => $sortedOrderProperties[$id] ? $sortedOrderProperties[$id] : array(),
				"PAYMENT" => $sortedPayments[$id] ? $sortedPayments[$id] : array(),
				"SHIPMENT" => $sortedShipments[$id] ? $sortedShipments[$id] : array(),
				"BASKET_ITEMS" => $sortedBasketItems[$id] ? $sortedBasketItems[$id] : array(),
				"DISCOUNT" => $discountData
			);
		}

		return $sortedOrderReferences;
	}

	/**
	 * @param array $parameters
	 *
	 * @return Main\DB\Result
	 * @throws Main\ArgumentException
	 */
	public static function getList(array $parameters = array())
	{
		return Internals\OrderArchiveTable::getList($parameters);
	}

	/**
	 * Get entry of order from archive by entry's id.
	 *
	 * @param int $id
	 *
	 * @return Main\DB\Result
	 * @throws Main\ArgumentException
	 */
	public static function getById($id)
	{
		return Internals\OrderArchiveTable::getById($id);
	}

	/**
	 * Get entries of basket items from archive.
	 * 
	 * @param array $parameters
	 *
	 * @return Main\DB\Result
	 * @throws Main\ArgumentException
	 */
	public static function getBasketList(array $parameters = array())
	{
		return Internals\BasketArchiveTable::getList($parameters);
	}

	/**
	 * Get entry of basket item from archive by id.
	 * 
	 * @param int $id
	 *
	 * @return Main\DB\Result
	 * @throws Main\ArgumentException
	 */
	public static function getBasketItemById($id)
	{
		return Internals\BasketArchiveTable::getById($id);
	}

	/**
	 * Delete archived order with archived basket items.
	 * 
	 * @param int $id
	 *
	 * @return Main\Entity\DeleteResult
	 * @throws \Exception
	 */
	public static function delete($id)
	{
		$basketItems = static::getBasketList(
			array(
				"filter" => array("ARCHIVE_ID" => $id),
				"select" => array("ID")
			)
		);
		while ($item = $basketItems->fetch())
		{
			Internals\BasketArchiveTable::delete($item['ID']);
		}

		return Internals\OrderArchiveTable::delete($id);
	}

	/**
	 * Return Archive\Order object restored from archive
	 *
	 * @param int $id		Entity's id.
	 *
	 * @return Sale\Order
	 * @throws Main\ObjectNotFoundException
	 * @throws Main\ArgumentNullException
	 */
	public static function returnArchivedOrder($id)
	{
		$id = (int)$id;
		if ($id <= 0)
			throw new Main\ArgumentNullException("id");

		$archivedOrder = Internals\OrderArchiveTable::getList(
			array(
				"select" => array("*", "ORDER_FULL" => "ORDER_PACKED.ORDER_DATA"),
				"filter" => array("=ID" => $id),
				"limit" => 1
			)
		);
		$orderFields = $archivedOrder->fetch();

		if (!$orderFields)
			return null;

		$recoveryName = "\\Bitrix\\Sale\\Archive\\Recovery\\Version" . $orderFields['VERSION'];
		if (class_exists($recoveryName))
		{
			$orderFields['ORDER_DATA'] = unserialize($orderFields['ORDER_FULL']);
			$orderFields['ORDER_DATA']['BASKET_ITEMS'] = array();

			$basketArchivedItems = Internals\BasketArchiveTable::getList(
				array(
					"select" => array("BASKET_FULL" => "BASKET_PACKED.BASKET_DATA"),
					"filter" => array("ARCHIVE_ID" => $orderFields['ID'])
				)
			);

			while ($item = $basketArchivedItems->fetch())
			{
				$item['BASKET_DATA'] = unserialize($item['BASKET_FULL']);
				$orderFields['ORDER_DATA']['BASKET_ITEMS'][$item['BASKET_DATA']['ID']] = $item['BASKET_DATA'];
			}

			/** @var Sale\Archive\Recovery\Base $orderRecovery */
			$orderRecovery = new $recoveryName;
			$order = $orderRecovery->restoreOrder($orderFields['ORDER_DATA']);
			$order->setDateArchived($orderFields['DATE_ARCHIVED']);
			$order->setVersion($orderFields['VERSION']);
		}
		else
		{
			throw new Main\ObjectNotFoundException('Class of restoring archive didn\'t find');
		}

		return $order;
	}

	/**
	 * Collect order properties and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return mixed
	 * @throws Main\ArgumentException
	 */
	protected static function collectOrderProperties($orderIds)
	{
		$sortedOrderProperties = array();
		$orderProperties = Internals\OrderPropsValueTable::getList(
			array(
				"order" => array("ORDER_ID"),
				"filter" => array("=ORDER_ID" => $orderIds)
			)
		);

		while ($property = $orderProperties->fetch())
		{
			$sortedOrderProperties[$property['ORDER_ID']][$property['ID']] = $property;
		}
		return $sortedOrderProperties;
	}

	/**
	 * Collect payments and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return array
	 */
	protected static function collectPayments($orderIds)
	{
		$sortedPayments = array();
		$payments = Sale\Payment::getList(
			array(
				"order" => array("ORDER_ID"),
				"filter" => array("=ORDER_ID" => $orderIds)
			)
		);

		while ($payment = $payments->fetch())
		{
			$sortedPayments[$payment['ORDER_ID']][$payment['ID']] = $payment;
		}

		return $sortedPayments;
	}

	/**
	 * Collect shipments with shipment items and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return mixed
	 */
	protected static function collectShipments($orderIds)
	{
		$shipmentItemsList = array();
		$sortedShipments = array();

		$shipments = Sale\Shipment::getList(
			array(
				"order" => array("ORDER_ID"),
				"filter" => array("=ORDER_ID" => $orderIds, "SYSTEM" => 'N')
			)
		);

		while ($shipment = $shipments->fetch())
		{
			$shipmentItemsList[$shipment['ID']] = $shipment;
		}

		if (!empty($shipmentItemsList))
		{
			$shipmentsItems = Sale\ShipmentItem::getList(
				array(
					"order" => array("ORDER_DELIVERY_ID"),
					"filter" => array("ORDER_DELIVERY_ID" => array_keys($shipmentItemsList))
				)
			);

			while ($shipmentsItem = $shipmentsItems->fetch())
			{
				$shipmentItemsList[$shipmentsItem['ORDER_DELIVERY_ID']]["SHIPMENT_ITEM"][] = $shipmentsItem;
			}
		}

		foreach ($shipmentItemsList as $item)
		{
			$sortedShipments[$item['ORDER_ID']][$item['ID']] = $item;
		}

		return $sortedShipments;
	}

	/**
	 * Collect basket items with barcodes and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return array
	 * @throws Main\ArgumentException
	 */
	protected static function collectBaskets($orderIds)
	{
		$sortedBasketItems = array();
		$basketItemsList = array();

		$basketItems = Sale\Basket::getList(
			array(
				"order" => array("ORDER_ID"),
				"filter" => array("=ORDER_ID" => $orderIds)
			)
		);

		while ($element = $basketItems->fetch())
		{
			$basketItemsList[$element['ID']] = $element;
		}

		if (!empty($basketItemsList))
		{
			$basketProperties = Internals\BasketPropertyTable::getList(
				array(
					"filter" => array("BASKET_ID" => array_keys($basketItemsList))
				)
			);

			while ($property = $basketProperties->fetch())
			{
				$basketItemsList[$property["BASKET_ID"]]['PROPERTY_ITEMS'][] = $property;
			}

			$basketProperties = Sale\ShipmentItemStore::getList(
				array(
					"filter" => array("=BASKET_ID" => array_keys($basketItemsList))
				)
			);

			while ($property = $basketProperties->fetch())
			{
				$basketItemsList[$property["BASKET_ID"]]['SHIPMENT_BARCODE_ITEMS'][$property['ORDER_DELIVERY_BASKET_ID']] = $property;
			}
		}

		foreach ($basketItemsList as $basketItem)
		{
			$sortedBasketItems[$basketItem['ORDER_ID']][$basketItem['ID']] = $basketItem;
		}

		return $sortedBasketItems;
	}

	/**
	 * Collect coupons and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return array
	 * @throws Main\ArgumentException
	 */
	protected static function collectCoupons($orderIds)
	{
		$couponList = array();

		$couponsIterator = Internals\OrderCouponsTable::getList(array(
			'select' => array(
				'*',
				'MODULE_ID' => 'ORDER_DISCOUNT.MODULE_ID',
				'DISCOUNT_ID' => 'ORDER_DISCOUNT.DISCOUNT_ID',
				'DISCOUNT_NAME' => 'ORDER_DISCOUNT.NAME',
				'DISCOUNT_DESCR' => 'ORDER_DISCOUNT.ACTIONS_DESCR',
			),
			'filter' => array('=ORDER_ID' => $orderIds),
			'order' => array('ID' => 'ASC')
		));

		while ($coupon = $couponsIterator->fetch())
		{
			foreach ($coupon['DISCOUNT_DESCR'] as $discountDescriptionArray)
			{
				foreach ($discountDescriptionArray as $descriptionList)
				{
					$coupon['DISCOUNT_SIZE'] = Sale\OrderDiscountManager::formatDescription($descriptionList);
				}
			}

			$couponList[$coupon['ORDER_ID']][$coupon['COUPON']] = $coupon;
		}

		return $couponList;
	}

	/**
	 * Collect discount data and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return array
	 * @throws Main\ArgumentException
	 */
	protected static function collectDiscountData($orderIds)
	{
		$sortedDataDiscount = array();

		$dataIterator = Internals\OrderDiscountDataTable::getList(
			array(
				'select' => array('*'),
				'filter' => array('=ORDER_ID' => $orderIds)
			)
		);

		while ($dataDiscount = $dataIterator->fetch())
		{
			$sortedDataDiscount[$dataDiscount['ORDER_ID']][$dataDiscount['ID']] = $dataDiscount;
		}

		return $sortedDataDiscount;
	}

	/**
	 * Collect discount data and sort by orders's ids
	 * 
	 * @param $orderIds
	 *
	 * @return array
	 * @throws Main\ArgumentException
	 */
	protected static function collectRules($orderIds)
	{
		$sortedRules = array();
		$discountList = array();
		$rulesList = array();
		
		$ruleIterator = Internals\OrderRulesTable::getList(array(
			'filter' => array('=ORDER_ID' => $orderIds),
			'order' => array('ID' => 'ASC')
		));

		while ($rule = $ruleIterator->fetch())
		{
			$discountList[] = $rule['ORDER_DISCOUNT_ID'];
			$rulesList[$rule['ID']] = $rule;
		}

		$discountList = array_unique($discountList);

		$ruleDecsrIterator = Internals\OrderRulesDescrTable::getList(array(
			'select' => array('RULE_ID', 'DESCR', 'ID'),
			'filter' => array('@ORDER_ID' => $orderIds),
			'order' => array('ID' => 'ASC')
		));

		while ($ruleDescr = $ruleDecsrIterator->fetch())
		{
			$rulesList[$ruleDescr['RULE_ID']]['RULE_DESCR'] = $ruleDescr['DESCR'];
			$rulesList[$ruleDescr['RULE_ID']]['RULE_DESCR_ID'] = $ruleDescr['ID'];
		}

		if (!empty($discountList))
		{
			$discountIterator = Internals\OrderDiscountTable::getList(array(
				'filter' => array('@ID' => $discountList),
			));

			while ($discount = $discountIterator->fetch())
			{
				$discountList[$discount['ID']] = $discount;
			}
		}

		foreach ($rulesList as $id => $rule)
		{
			$rule["DISCOUNT_DATA"] = $discountList[$rule['ORDER_DISCOUNT_ID']] ? $discountList[$rule['ORDER_DISCOUNT_ID']] : array();
			$sortedRules[$rule['ORDER_ID']][$id] = $rule;
		}

		return $sortedRules;
	}
}