Your IP : 52.15.200.26


Current Path : /home/bitrix/ext_www/www.piano.royal-thermo.com.ua/bitrix/modules/sale/lib/
Upload File :
Current File : /home/bitrix/ext_www/www.piano.royal-thermo.com.ua/bitrix/modules/sale/lib/order.php

<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage sale
 * @copyright 2001-2012 Bitrix
 */
namespace Bitrix\Sale;

use Bitrix\Main\Config;
use Bitrix\Main\Entity;
use Bitrix\Main;
use Bitrix\Main\Type;
use Bitrix\Sale\Internals;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\PaySystem\Manager;
use Bitrix\Sale\PaySystem\Service;

Loc::loadMessages(__FILE__);

class Order
	extends OrderBase implements \IShipmentOrder, \IPaymentOrder, IBusinessValueProvider
{

	private $isNew = null;
	/** @var Discount $discount */
	protected $discount = null;

	const SALE_ORDER_LOCK_STATUS_RED = 'red';
	const SALE_ORDER_LOCK_STATUS_GREEN = 'green';
	const SALE_ORDER_LOCK_STATUS_YELLOW = 'yellow';


	protected $isStartField = null;
	protected $isMeaningfulField = false;
	protected $isOnlyMathAction = null;

	/**
	 * Modify shipment collection.
	 *
	 * @param string $action				Action code.
	 * @param Shipment $shipment			Shipment.
	 * @param null|string $name					Field name.
	 * @param null|string|int|float $oldValue				Old value.
	 * @param null|string|int|float $value					New value.
	 * @return bool
	 *
	 * @throws Main\NotImplementedException
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\ArgumentOutOfRangeException
	 * @throws \Bitrix\Main\NotSupportedException
	 * @throws \Exception
	 */
	public function onShipmentCollectionModify($action, Shipment $shipment, $name = null, $oldValue = null, $value = null)
	{
		global $USER;

		$result = new Result();

		if ($action == EventActions::DELETE)
		{
			if ($this->getField('DELIVERY_ID') == $shipment->getDeliveryId())
			{
				/** @var ShipmentCollection $shipmentCollection */
				if (!$shipmentCollection = $shipment->getCollection())
				{
					throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
				}

				$foundShipment = false;

				/** @var Shipment $entityShipment */
				foreach ($shipmentCollection as $entityShipment)
				{
					if ($entityShipment->isSystem())
						continue;

					if (intval($entityShipment->getField('DELIVERY_ID')) > 0)
					{
						$foundShipment = true;
						$this->setFieldNoDemand('DELIVERY_ID', $entityShipment->getField('DELIVERY_ID'));
						break;
					}
				}

				if (!$foundShipment && !$shipment->isSystem())
				{
					/** @var Shipment $systemShipment */
					if (($systemShipment = $shipmentCollection->getSystemShipment()) && intval($systemShipment->getField('DELIVERY_ID')) > 0)
					{
						$this->setFieldNoDemand('DELIVERY_ID', $systemShipment->getField('DELIVERY_ID'));
					}
				}
			}
		}

		if ($action != EventActions::UPDATE)
			return $result;



		// PRICE_DELIVERY, ALLOW_DELIVERY, DEDUCTED, MARKED
		// CANCELED, DELIVERY_ID
		if ($name == "ALLOW_DELIVERY")
		{
			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_ALLOW_DELIVERY_ORDER_CANCELED'), 'SALE_ORDER_ALLOW_DELIVERY_ORDER_CANCELED'));
				return $result;
			}

			$r = $shipment->deliver();
			if ($r->isSuccess())
			{
				$event = new Main\Event('sale', EventActions::EVENT_ON_SHIPMENT_DELIVER, array(
					'ENTITY' =>$shipment
				));
				$event->send();
			}
			else
			{
				$result->addErrors($r->getErrors());
			}

			if (Configuration::getProductReservationCondition() == Configuration::RESERVE_ON_ALLOW_DELIVERY)
			{
				if ($value == "Y")
				{
					/** @var Result $r */
					$r = $shipment->tryReserve();
					if (!$r->isSuccess())
					{
						$shipment->setField('MARKED', 'Y');

						if (is_array($r->getErrorMessages()))
						{
							$oldErrorText = $shipment->getField('REASON_MARKED');
							foreach($r->getErrorMessages() as $error)
							{
								$oldErrorText .= (strval($oldErrorText) != '' ? "\n" : ""). $error;
							}

							$shipment->setField('REASON_MARKED', $oldErrorText);
						}

						$result->addErrors($r->getErrors());
					}
				}
				else
				{
					if (!$shipment->isShipped())
					{
						/** @var Result $r */
						$r = $shipment->tryUnreserve();
						if (!$r->isSuccess())
						{
							$result->addErrors($r->getErrors());
						}
					}
				}

				if (!$result->isSuccess())
				{
					return $result;
				}
			}

			if ($oldValue == "N")
			{
				$orderStatus = Config\Option::get('sale', 'status_on_allow_delivery', '');

				if (strval($orderStatus) != '')
				{
					if ($USER && $USER->isAuthorized())
					{
						$statusesList = OrderStatus::getAllowedUserStatuses($USER->getID(), $this->getField('STATUS_ID'));
					}
					else
					{
						$statusesList = OrderStatus::getAllStatuses();
					}

					if($this->getField('STATUS_ID') != $orderStatus && array_key_exists($orderStatus, $statusesList))
					{
						/** @var Result $r */
						$r = $this->setField('STATUS_ID', $orderStatus);
						if (!$r->isSuccess())
						{
							$result->addErrors($r->getErrors());
							return $result;
						}
					}
				}

			}

			if (Configuration::needShipOnAllowDelivery() && $value == "Y")
			{
				if (!$shipment->isEmpty())
					$shipment->setField("DEDUCTED", "Y");
			}

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

			if ($shipmentCollection->isAllowDelivery() && $this->getField('ALLOW_DELIVERY') == 'N')
				$this->setFieldNoDemand('DATE_ALLOW_DELIVERY', new Type\DateTime());

			$this->setFieldNoDemand('ALLOW_DELIVERY', $shipmentCollection->isAllowDelivery() ? "Y" : "N");
		}
		elseif ($name == "DEDUCTED")
		{
			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_SHIPMENT_ORDER_CANCELED'), 'SALE_ORDER_SHIPMENT_ORDER_CANCELED'));
				return $result;
			}

			if (Configuration::getProductReservationCondition() == Configuration::RESERVE_ON_SHIP)
			{
				if ($value == "Y")
				{
					/** @var Result $r */
					$r = $shipment->tryReserve();
					if (!$r->isSuccess())
					{
						$shipment->setField('MARKED', 'Y');

						if (is_array($r->getErrorMessages()))
						{
							$oldErrorText = $shipment->getField('REASON_MARKED');
							foreach($r->getErrorMessages() as $error)
							{
								$oldErrorText .= (strval($oldErrorText) != '' ? "\n" : ""). $error;
							}

							$shipment->setField('REASON_MARKED', $oldErrorText);
						}

						$result->addErrors($r->getErrors());
						return $result;
					}
				}
				else
				{
					$shipment->tryUnreserve();
				}
			}

			if ($value == "Y")
			{
				/** @var Result $r */
				$r = $shipment->tryShip();
				if (!$r->isSuccess())
				{
					$shipment->setField('MARKED', 'Y');

					if (is_array($r->getErrorMessages()))
					{
						$oldErrorText = $shipment->getField('REASON_MARKED');
						foreach($r->getErrorMessages() as $error)
						{
							$oldErrorText .= (strval($oldErrorText) != '' ? "\n" : ""). $error;
						}

						$shipment->setField('REASON_MARKED', $oldErrorText);
					}
					$result->addErrors($r->getErrors());
					return $result;
				}

			}
			elseif ($oldValue == 'Y')
			{
				/** @var Result $r */
				$r = $shipment->tryUnship();
				if (!$r->isSuccess())
				{
					/** @var Result $resultShipment */
					$resultShipment = $shipment->setField('MARKED', 'Y');
					if (!$resultShipment->isSuccess())
					{
						$result->addErrors($resultShipment->getErrors());
					}

					if (is_array($r->getErrorMessages()))
					{
						$oldErrorText = $shipment->getField('REASON_MARKED');
						foreach($r->getErrorMessages() as $error)
						{
							$oldErrorText .= (strval($oldErrorText) != '' ? "\n" : ""). $error;
						}

						/** @var Result $resultShipment */
						$resultShipment = $shipment->setField('REASON_MARKED', $oldErrorText);
						if (!$resultShipment->isSuccess())
						{
							$result->addErrors($resultShipment->getErrors());
						}
					}

				}

				if ($shipment->needReservation())
				{
					$r = $shipment->tryReserve();
					if (!$r->isSuccess())
					{
						$result->addErrors($r->getErrors());
					}
				}
			}

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

			$this->setFieldNoDemand('DEDUCTED', $shipmentCollection->isShipped() ? "Y" : "N");

			if ($shipmentCollection->isShipped())
			{
				if (strval($shipment->getField('DATE_DEDUCTED')) != '')
				{
					$this->setFieldNoDemand('DATE_DEDUCTED', $shipment->getField('DATE_DEDUCTED'));
				}
				if (strval($shipment->getField('EMP_DEDUCTED_ID')) != '')
				{
					$this->setFieldNoDemand('EMP_DEDUCTED_ID', $shipment->getField('EMP_DEDUCTED_ID'));
				}
			}
		}
		elseif ($name == "MARKED")
		{
			if ($value == "Y")
			{
				/** @var Result $r */
				$r = $this->setField('MARKED', 'Y');
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
		}
		elseif ($name == "REASON_MARKED")
		{
			if (!empty($value))
			{
				$orderReasonMarked = $this->getField('REASON_MARKED');
				if (is_array($value))
				{
					$newOrderReasonMarked = '';
					foreach ($value as $err)
					{
						$newOrderReasonMarked .= (strval($newOrderReasonMarked) != '' ? "\n" : "") . $err;
					}
				}
				else
				{
					$newOrderReasonMarked = $value;
				}

				/** @var Result $r */
				$r = $this->setField('REASON_MARKED', $orderReasonMarked. (strval($orderReasonMarked) != '' ? "\n" : ""). $newOrderReasonMarked);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
		}
		elseif ($name == "BASE_PRICE_DELIVERY")
		{
			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_PRICE_DELIVERY_ORDER_CANCELED'), 'SALE_ORDER_PRICE_DELIVERY_ORDER_CANCELED'));
				return $result;
			}

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

			$discount = $this->getDiscount();
			$discount->setCalculateShipments($shipment);

			$r = $shipment->setField('PRICE_DELIVERY', $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}
		elseif ($name == "PRICE_DELIVERY")
		{
			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_PRICE_DELIVERY_ORDER_CANCELED'), 'SALE_ORDER_PRICE_DELIVERY_ORDER_CANCELED'));
				return $result;
			}

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

			$this->setFieldNoDemand(
				"PRICE_DELIVERY",
				$this->getField("PRICE_DELIVERY") - $oldValue + $value
			);

			/** @var Result $r */
			$r = $this->setField(
				"PRICE",
				$this->getField("PRICE") - $oldValue + $value
			);

			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}

		}
		elseif ($name == "DELIVERY_ID")
		{
			if ($shipment->isSystem() || intval($shipment->getField('DELIVERY_ID')) <= 0 )
			{
				return $result;
			}

			$this->setFieldNoDemand('DELIVERY_ID', $shipment->getField('DELIVERY_ID'));
		}


		if ($value != $oldValue)
		{
			$fields = $this->fields->getChangedValues();
			if (!array_key_exists("UPDATED_1C", $fields))
				parent::setField("UPDATED_1C", "N");
		}

		return $result;
	}

	/**
	 * Fill basket.
	 *
	 * @param Basket $basket			Basket.
	 * @return Result
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 */
	public function setBasket(Basket $basket)
	{
		$result = new Result();

		$isStartField = $this->isStartField();

		$r = parent::setBasket($basket);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}

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

		/** @var Result $r */
		$r = $shipmentCollection->resetCollection();
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}

		if (!$this->isMathActionOnly())
		{
			/** @var Result $r */
			$r = $this->refreshData();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}


		if ($isStartField)
		{
			$hasMeaningfulFields = $this->hasMeaningfulField();

			/** @var Result $r */
			$r = $this->doFinalAction($hasMeaningfulFields);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}


		return $result;
	}

	/**
	 * @param string $value
	 * @return null|static
	 * @throws Main\ArgumentNullException
	 * @throws Main\NotImplementedException
	 */
	public static function loadByAccountNumber($value)
	{
		$filter = array(
			'filter' => array('ACCOUNT_NUMBER' => $value),
			'select' => array('*'),
		);

		if ($orderDat = static::loadFromDb($filter))
		{
			$order = new static($orderDat);

			$order->calculateType = static::SALE_ORDER_CALC_TYPE_CHANGE;

			return $order;
		}

		return null;
	}


	/**
	 * @param array $filter
	 * @return array
	 * @throws Main\ArgumentException
	 */
	static protected function loadFromDb(array $filter)
	{
		if ($orderDat = Internals\OrderTable::getList($filter)->fetch())
		{
			return $orderDat;
		}

		return false;
	}


	/**
	 * @return mixed|static
	 */
	protected function loadBasket()
	{
		if (intval($this->getId()) > 0)
		{
			return Basket::loadItemsForOrder($this);
		}
		else
		{
			return false;
		}
	}

	/**
	 * @return ShipmentCollection
	 */
	public function getShipmentCollection()
	{
		if(empty($this->shipmentCollection))
		{
			$this->shipmentCollection = $this->loadShipmentCollection();
		}

		return $this->shipmentCollection;
	}


	/**
	 * @return PaymentCollection
	 */
	public function getPaymentCollection()
	{
		if(empty($this->paymentCollection))
		{
			$this->paymentCollection = $this->loadPaymentCollection();
		}
		return $this->paymentCollection;
	}

	/**
	 * @return ShipmentCollection|static
	 */
	public function loadShipmentCollection()
	{
		return ShipmentCollection::load($this);
	}

	/**
	 * @return PaymentCollection
	 */
	public function loadPaymentCollection()
	{
		return PaymentCollection::load($this);
	}

	/**
	 * @return PropertyValueCollection
	 */
	public function loadPropertyCollection()
	{
		return PropertyValueCollection::load($this);
	}

	/**
	 * @return array
	 * @throws Main\ObjectNotFoundException
	 */
	public function getDeliverySystemId()
	{
		$result = array();
		/** @var ShipmentCollection $shipmentCollection */
		if (!$shipmentCollection = $this->getShipmentCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
		}

		/** @var Shipment $shipment */
		foreach ($shipmentCollection as $shipment)
		{
			$result[] = $shipment->getDeliveryId();
		}

		return $result;
	}

	/**
	 * @return array
	 * @throws Main\ObjectNotFoundException
	 */
	public function getPaymentSystemId()
	{
		$result = array();
		/** @var PaymentCollection $paymentCollection */
		if (!$paymentCollection = $this->getPaymentCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "PaymentCollection" not found');
		}

		/** @var Payment $payment */
		foreach ($paymentCollection as $payment)
		{
			$result[] = $payment->getPaymentSystemId();
		}

		return $result;
	}


	/**
	 * @return Entity\AddResult|Entity\UpdateResult|Result|mixed
	 * @throws Main\ArgumentOutOfRangeException
	 */
	public function save()
	{
		global $USER, $CACHE_MANAGER;

		$result = new Result();

		$id = $this->getId();
		$this->isNew = ($id == 0);

		/** @var array $oldEntityValues */
		$oldEntityValues = $this->fields->getOriginalValues();

		/** @var Main\Entity\Event $event */
		$event = new Main\Event('sale', EventActions::EVENT_ON_ORDER_BEFORE_SAVED, array(
			'ENTITY' => $this,
			'VALUES' => $oldEntityValues
		));
		$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_BEFORE_ORDER_SAVED_ERROR'), 'SALE_EVENT_ON_BEFORE_ORDER_SAVED_ERROR');
					if ($eventResultData = $eventResult->getParameters())
					{
						if (isset($eventResultData) && $eventResultData instanceof ResultError)
						{
							/** @var ResultError $errorMsg */
							$errorMsg = $eventResultData;
						}
					}

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

			if (!$result->isSuccess())
			{
				return $result;
			}
		}

		$r = $this->verify();
		if (!$r->isSuccess())
		{
			/** @var ResultError $error */
			foreach ($r->getErrors() as $error)
			{
				if ($error instanceof ResultNotice)
				{
					continue;
				}
				else
				{
					$result->addError($error);
				}
			}

			if (!$result->isSuccess())
				return $result;
		}

		$r = Provider::onOrderSave($this);
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}


		$fields = $this->fields->getValues();

		if ($id > 0)
		{
			$fields = $this->fields->getChangedValues();
			$isChanged = (bool)(!empty($fields));

			if ($this->isChanged())
			{
				if (!isset($fields['DATE_UPDATE']) || strval($fields['DATE_UPDATE']) == '')
				{
					$fields['DATE_UPDATE'] = new Type\DateTime();
					$this->setFieldNoDemand('DATE_UPDATE', $fields['DATE_UPDATE']);
				}

				$fields['VERSION'] = intval($this->getField('VERSION')) + 1;
				$this->setFieldNoDemand('VERSION', $fields['VERSION']);

				if (array_key_exists('REASON_MARKED', $fields) && strlen($fields['REASON_MARKED']) > 255)
				{
					$fields['REASON_MARKED'] = substr($fields['REASON_MARKED'], 0, 255);
				}
			}

			if (!empty($fields) && is_array($fields))
			{
				$r = Internals\OrderTable::update($id, $fields);
				if (!$r->isSuccess())
				{
					OrderHistory::addAction(
						'ORDER',
						$id,
						'ORDER_UPDATE_ERROR',
						$id,
						$this,
						array("ERROR" => $r->getErrorMessages())
					);

					$result->addWarnings($r->getErrors());
					return $result;
				}

				if ($resultData = $r->getData())
					$result->setData($resultData);

				OrderHistory::addAction('ORDER', $id, 'ORDER_UPDATED', $id, $this);
			}
		}
		else
		{
			$isChanged = true;
			if (!isset($fields['DATE_INSERT']) || strval($fields['DATE_INSERT']) == '')
			{
				$fields['DATE_INSERT'] = new Type\DateTime();
				$this->setFieldNoDemand('DATE_INSERT', $fields['DATE_INSERT']);
			}

			if (!isset($fields['DATE_UPDATE']) || strval($fields['DATE_UPDATE']) == '')
			{
				$fields['DATE_UPDATE'] = new Type\DateTime();
				$this->setFieldNoDemand('DATE_UPDATE', $fields['DATE_UPDATE']);
			}

			if ($USER->isAuthorized())
			{
				$fields['CREATED_BY'] = $USER->getID();
				$this->setFieldNoDemand('CREATED_BY', $fields['CREATED_BY']);
			}

			if (!isset($fields['STATUS_ID']) || strval($fields['STATUS_ID']) == '')
			{
				$orderStatus = OrderStatus::getInitialStatus();
				if (!empty($orderStatus) && !is_array($orderStatus))
				{
					$fields['STATUS_ID'] = $orderStatus;
					$this->setFieldNoDemand('STATUS_ID', $fields['STATUS_ID']);
				}
			}

			if (isset($fields['STATUS_ID']) && strval($fields['STATUS_ID']) != '')
			{
				if (!isset($fields['DATE_STATUS']) || strval($fields['DATE_STATUS']) == '')
				{
					$fields['DATE_STATUS'] = new Type\DateTime();
					$this->setFieldNoDemand('DATE_STATUS', $fields['DATE_STATUS']);
				}


				if ((!isset($fields['EMP_STATUS_ID']) || (int)$fields['EMP_STATUS_ID'] <= 0) && $USER->isAuthorized())
				{
					$fields['EMP_STATUS_ID'] = $USER->getID();
					$this->setFieldNoDemand('EMP_STATUS_ID', $fields['EMP_STATUS_ID']);
				}
			}

			if (array_key_exists('REASON_MARKED', $fields) && strlen($fields['REASON_MARKED']) > 255)
			{
				$fields['REASON_MARKED'] = substr($fields['REASON_MARKED'], 0, 255);
			}


			$r = Internals\OrderTable::add($fields);
			if (!$r->isSuccess())
			{
				$result->addWarnings($r->getErrors());
				return $result;
			}

			if ($resultData = $r->getData())
				$result->setData($resultData);

			$id = $r->getId();
			$this->setFieldNoDemand('ID', $id);

			/** @var Result $r */
			$r = static::setAccountNumber($id);
			if ($r->isSuccess())
			{
				if ($accountData = $r->getData())
				{
					if (array_key_exists('ACCOUNT_NUMBER', $accountData))
					{
						$this->setField('ACCOUNT_NUMBER', $accountData['ACCOUNT_NUMBER']);
					}
				}
			}
			OrderHistory::addAction('ORDER', $id, 'ORDER_ADDED', $id, $this);
		}

		if ($id > 0)
		{
			$result->setId($id);
		}

		if ($eventName = static::getEntityEventName())
		{
			$oldEntityValues = $this->fields->getOriginalValues();

			if (!empty($oldEntityValues))
			{
				/** @var Main\Event $event */
				$event = new Main\Event('sale', 'On'.$eventName.'EntitySaved', array(
					'ENTITY' => $this,
					'VALUES' => $oldEntityValues,
				));
				$event->send();
			}
		}

		$changeMeaningfulFields = array(
			"PERSON_TYPE_ID",
			"CANCELED",
			"STATUS_ID",
			"MARKED",
			"PRICE",
			"SUM_PAID",
			"USER_ID",
			"EXTERNAL_ORDER",
		);


		if ($isChanged)
		{
			$logFields = array();

			if (!$this->isNew)
			{
				$fields = $this->getFields();
				$originalValues = $fields->getOriginalValues();

				foreach($originalValues as $originalFieldName => $originalFieldValue)
				{
					if (in_array($originalFieldName, $changeMeaningfulFields) && $this->getField($originalFieldName) != $originalFieldValue)
					{
						$logFields[$originalFieldName] = $this->getField($originalFieldName);
						$logFields['OLD_'.$originalFieldName] = $originalFieldValue;
					}
				}

				OrderHistory::addLog('ORDER', $id, "ORDER_UPDATE", $id, $this, $logFields, OrderHistory::SALE_ORDER_HISTORY_LOG_LEVEL_1);
			}

		}

		OrderHistory::collectEntityFields('ORDER', $id, $id);

		/** @var Basket $basket */
		$basket = $this->getBasket();

		/** @var Result $r */
		$r = $basket->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}

		/** @var PaymentCollection $paymentCollection */
		$paymentCollection = $this->getPaymentCollection();

		/** @var Result $r */
		$r = $paymentCollection->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}


		// user budget
		Internals\UserBudgetPool::onUserBudgetSave($this->getUserId());

		/** @var ShipmentCollection $shipmentCollection */
		$shipmentCollection = $this->getShipmentCollection();

		/** @var Result $r */
		$r = $shipmentCollection->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}

		/** @var Tax $tax */
		$tax = $this->getTax();

		/** @var Result $r */
		$r = $tax->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}


		/** @var PropertyValueCollection $propertyCollection */
		$propertyCollection = $this->getPropertyCollection();

		/** @var Result $r */
		$r = $propertyCollection->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}

		/** @var Discount $discount */
		$discount = $this->getDiscount();

		/** @var Result $r */
		$r = $discount->save();
		if (!$r->isSuccess())
		{
			$result->addWarnings($r->getErrors());
		}

		/** @var array $oldEntityValues */
		$oldEntityValues = $this->fields->getOriginalValues();

		OrderHistory::addLog('ORDER', $this->getId(), 'ORDER_EVENT_ON_ORDER_SAVED', null, null, array(), OrderHistory::SALE_ORDER_HISTORY_LOG_LEVEL_1);

		$event = new Main\Event('sale', EventActions::EVENT_ON_ORDER_SAVED, array(
			'ENTITY' => $this,
			'IS_NEW' => $this->isNew,
			'VALUES' => $oldEntityValues,
		));
		$event->send();


		if (($eventList = Internals\EventsPool::getEvents($this)) && !empty($eventList) && is_array($eventList))
		{
			foreach ($eventList as $eventName => $eventData)
			{
				$event = new Main\Event('sale', $eventName, $eventData);
				$event->send();

				Notify::callNotify($this, $eventName);
			}

			Internals\EventsPool::resetEvents($this);
		}

		if (!$result->isSuccess())
		{
			$errorMsg = $this->getField('REASON_MARKED');
			$errorMsg .= (strval($errorMsg) != ""? "\n" : "").join("\n", $result->getErrors());
			$updateFields = array(
				'MARKED' => 'Y',
				'DATE_MARKED' => new Type\DateTime(),
				'EMP_MARKED_ID' => $USER->getId(),
				'REASON_MARKED' => $errorMsg
			);
			Internals\OrderTable::update($id, $updateFields);

			OrderHistory::addLog('ORDER', $this->getId(), 'ORDER_EVENT_ON_ORDER_SAVED_ERROR', null, null, array("ERROR" => $errorMsg), OrderHistory::SALE_ORDER_HISTORY_LOG_LEVEL_1);
		}
		else
		{
			if(defined("CACHED_b_sale_order") && ($this->isNew || ($this->isChanged() && $fields["UPDATED_1C"] != "Y")))
			{
				$CACHE_MANAGER->Read(CACHED_b_sale_order, "sale_orders");
				$CACHE_MANAGER->SetImmediate("sale_orders", true);
			}
		}

		OrderHistory::collectEntityFields('ORDER', $id, $id);


		$this->fields->clearChanged();

		$this->isNew = false;

		return $result;
	}

	/**
	 * Delete order.
	 *
	 * @param int $id				Order id.
	 * @return Result
	 * @throws Main\ArgumentNullException
	 */
	public static function delete($id)
	{
		$result = new Result();

		if (!$order = Order::load($id))
		{
			$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_ENTITY_NOT_FOUND'), 'SALE_ORDER_ENTITY_NOT_FOUND'));
			return $result;
		}

		/** @var Result $r */
		$r = $order->setField('CANCELED', 'Y');
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}

		/** @var Basket $basketCollection */
		if ($basketCollection = $order->getBasket())
		{
			/** @var BasketItem $basketItem */
			foreach ($basketCollection as $basketItem)
			{
				$basketItem->delete();
			}
		}

		/** @var ShipmentCollection $shipmentCollection */
		if ($shipmentCollection = $order->getShipmentCollection())
		{
			/** @var Shipment $shipment */
			foreach ($shipmentCollection as $shipment)
			{
				$shipment->delete();
			}
		}


		/** @var PaymentCollection $paymentCollection */
		if ($paymentCollection = $order->getPaymentCollection())
		{
			/** @var Payment $payment */
			foreach ($paymentCollection as $payment)
			{
				$payment->delete();
			}
		}

		/** @var PropertyValueCollection $propertyCollection */
		if ($propertyCollection = $order->getPropertyCollection())
		{
			/** @var PropertyValue $property */
			foreach ($propertyCollection as $property)
			{
				$property->delete();
			}
		}

		$event = new Main\Event('sale', EventActions::EVENT_ON_BEFORE_ORDER_DELETE, array(
			'ENTITY' => $order
		));
		$event->send();

		foreach ($event->getResults() as $eventResult)
		{
			$return = null;
			if ($eventResult->getType() == Main\EventResult::ERROR)
			{
				continue;
			}

			if ($eventResult->getType() == Main\EventResult::SUCCESS)
			{
				$return = $eventResult->getParameters('return');
				if ($return !== null)
				{
					return $result;
				}
			}
		}

		/** @var Result $r */
		$r = $order->save();
		if ($r->isSuccess())
		{
			/** @var Entity\DeleteResult $r */
			$r = Internals\OrderTable::delete($id);
			if ($r->isSuccess())
			{
				OrderHistory::deleteByOrderId($id);
			}
		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		$event = new Main\Event('sale', EventActions::EVENT_ON_ORDER_DELETED, array(
			'ENTITY' => $order,
			'VALUE' => ((bool) $r->isSuccess())
		));
		$event->send();

		return $result;
	}

	/**
	 * @return bool
	 */
	public function isPaid()
	{
		return $this->getField('PAYED') == "Y" ? true : false;
	}

	/**
	 * @return bool
	 */
	public function isShipped()
	{
		$shipmentCollection = $this->getShipmentCollection();
		return $shipmentCollection->isShipped();
	}

	/**
	 * @return bool
	 */
	public function isAllowDelivery()
	{
		return $this->getField('ALLOW_DELIVERY') == "Y"? true: false;
	}

	/**
	 * @return bool
	 */
	public function isCanceled()
	{
		return $this->getField('CANCELED') == "Y"? true: false;
	}

	/**
	 * Modify payment collection.
	 *
	 * @param string $action			Action.
	 * @param Payment $payment			Payment.
	 * @param null|string $name				Field name.
	 * @param null|string|int|float $oldValue		Old value.
	 * @param null|string|int|float $value			New value.
	 * @return Result
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotImplementedException
	 * @throws Main\ObjectNotFoundException
	 */
	public function onPaymentCollectionModify($action, Payment $payment, $name = null, $oldValue = null, $value = null)
	{
		$result = new Result();

		if ($action != EventActions::UPDATE)
			return $result;

		if (($name == "CURRENCY") && ($value != $this->getField("CURRENCY")))
			throw new Main\NotImplementedException();

		if ($name == "SUM" || $name == "PAID")
		{

			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_PAID_ORDER_CANCELED'), 'SALE_ORDER_PAID_ORDER_CANCELED'));
				return $result;
			}

			if (($name == "SUM") && !$payment->isPaid())
			{
				if ($value == 0 && $payment->isInner())
					$payment->delete();

				return $result;
			}


			$r = $this->syncOrderAndPayments($payment);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}

		}
		elseif ($name == "IS_RETURN")
		{
			if ($this->isCanceled())
			{
				$result->addError(new ResultError(Loc::getMessage('SALE_ORDER_RETURN_ORDER_CANCELED'), 'SALE_ORDER_RETURN_ORDER_CANCELED'));
				return $result;
			}

			if ($value != Payment::RETURN_NONE)
			{
				if (!$payment->isPaid())
				{
					$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_PAYMENT_RETURN_NOT_PAID'), 'SALE_ORDER_PAYMENT_RETURN_NOT_PAID'));
					return $result;
				}

				$oldPaid = $this->isPaid()? "Y" : "N";

				/** @var PaymentCollection $paymentCollection */
				if (!$paymentCollection = $this->getPaymentCollection())
				{
					throw new Main\ObjectNotFoundException('Entity "PaymentCollection" not found');
				}

				$creditSum = 0;
				$paid = $paymentCollection->getPaidSum() - $this->getPrice();

				if ($paid < 0)
					$creditSum = $payment->getSum();
				elseif ($payment->getSum() - $paid > 0)
					$creditSum = $payment->getSum() - $paid;

				if ($value == Payment::RETURN_PS)
				{
					$psId = $payment->getPaymentSystemId();
				}
				elseif ($value == Payment::RETURN_INNER)
				{
					$psId = Manager::getInnerPaySystemId();
				}
				else
				{
					$result->addError(new Entity\EntityError('unsupported operation'));
					return $result;
				}

				$service = Manager::getObjectById($psId);

				if ($service && $service->isRefundable())
				{
					if ($creditSum)
					{
						if ($value == Payment::RETURN_INNER)
						{
							$refResult = $service->refund($payment, $creditSum);
							if (!$refResult->isSuccess())
							{
								$result->addErrors($refResult->getErrors());
								return $result;
							}
						}
						elseif ($value == Payment::RETURN_PS)
						{
							$overPayment = $payment->getSum() - $this->getPrice();
							if ($overPayment > 0)
							{
								$userBudget = Internals\UserBudgetPool::getUserBudgetByOrder($this);
								if (Payment::roundByFormatCurrency($overPayment, $this->getCurrency()) <= Payment::roundByFormatCurrency($userBudget, $this->getCurrency()))
								{
									$refResult = $service->refund($payment, $payment->getSum());
									if ($refResult->isSuccess())
									{
										Internals\UserBudgetPool::addPoolItem($this, -$overPayment, Internals\UserBudgetPool::BUDGET_TYPE_ORDER_PAY, $payment);
									}
									else
									{
										$result->addErrors($refResult->getErrors());
										return $result;
									}
								}
								else
								{
									$result->addError(new Entity\EntityError(Loc::getMessage('SALE_ORDER_PAYMENT_RETURN_PAID')));
									return $result;
								}
							}
						}
					}
				}
				else
				{
					$result->addError(new Entity\EntityError(Loc::getMessage('SALE_ORDER_PAYMENT_RETURN_NO_SUPPORTED')));
					return $result;
				}

				$payment->setFieldNoDemand('PAID', 'N');

				$finalSumPaid = $this->getSumPaid() - $creditSum;
				if ($finalSumPaid != $this->getSumPaid())
				{
					$this->setFieldNoDemand('SUM_PAID', $finalSumPaid);
					$this->setFieldNoDemand('PAYED', ($this->getPrice() <= $finalSumPaid) ? "Y" : "N");
				}

				/** @var Result $r */
				$r = $this->onAfterSyncPaid($oldPaid);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
			else
			{

				if ($payment->isPaid())
				{
					$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_PAYMENT_RETURN_PAID'), 'SALE_ORDER_PAYMENT_RETURN_PAID'));
					return $result;
				}

				$userBudget = Internals\UserBudgetPool::getUserBudgetByOrder($this);
				if (Payment::roundByFormatCurrency($userBudget, $this->getCurrency()) < Payment::roundByFormatCurrency($payment->getSum(), $this->getCurrency()))
				{
					$result->addError( new ResultError( Loc::getMessage('SALE_ORDER_PAYMENT_NOT_ENOUGH_USER_BUDGET'), "SALE_ORDER_PAYMENT_NOT_ENOUGH_USER_BUDGET") );
					return $result;
				}

				Internals\UserBudgetPool::addPoolItem($this, ($payment->getSum() * -1), Internals\UserBudgetPool::BUDGET_TYPE_ORDER_PAY, $payment);

				$r = $payment->setField('PAID', "Y");
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
					return $result;
				}

			}

		}
		elseif ($name == "PAY_SYSTEM_ID")
		{
			if ($payment->getField('PAY_SYSTEM_ID') != $this->getField('PAY_SYSTEM_ID'))
			{
				$this->setFieldNoDemand('PAY_SYSTEM_ID', $payment->getField('PAY_SYSTEM_ID'));
			}

		}
		elseif ($name == "DATE_PAID")
		{
			if ($payment->getField('DATE_PAID') != $this->getField('DATE_PAID'))
			{
				$this->setFieldNoDemand('DATE_PAYED', $payment->getField('DATE_PAID'));
			}

		}

		if ($value != $oldValue)
		{
			$fields = $this->fields->getChangedValues();
			if (!array_key_exists("UPDATED_1C", $fields))
				parent::setField("UPDATED_1C", "N");
		}

		return $result;
	}

	/**
	 * Modify order field.
	 *
	 * @param string $name				Field name.
	 * @param mixed|string|int|float $oldValue			Old value.
	 * @param mixed|string|int|float $value				New value.
	 * @return Entity\Result|Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotImplementedException
	 * @throws Main\ObjectNotFoundException
	 */
	protected function onFieldModify($name, $oldValue, $value)
	{
		global $USER;

		$result = new Result();

		if ($name == "PRICE")
		{
			/** @var Result $r */
			$r = $this->refreshVat();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}


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

			$r = $shipmentCollection->onOrderModify($name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

			/** @var PaymentCollection $paymentCollection */
			if (!$paymentCollection = $this->getPaymentCollection())
			{
				throw new Main\ObjectNotFoundException('Entity "PaymentCollection" not found');
			}

			$r = $paymentCollection->onOrderModify($name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

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

			return $result;
		}
		elseif ($name == "CURRENCY")
		{
			throw new Main\NotImplementedException('field CURRENCY');
		}
		elseif ($name == "PERSON_TYPE_ID")
		{
			// may be need activate properties
			//throw new Main\NotImplementedException();
		}
		elseif ($name == "CANCELED")
		{
			$event = new Main\Event('sale', EventActions::EVENT_ON_BEFORE_ORDER_CANCELED, array(
				'ENTITY' => $this
			));
			$event->send();

			/** @var PaymentCollection $paymentCollection */
			if (!$paymentCollection = $this->getPaymentCollection())
			{
				throw new Main\ObjectNotFoundException('Entity "PaymentCollection" not found');
			}

			$r = $paymentCollection->onOrderModify($name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

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

			$r = $shipmentCollection->onOrderModify($name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

			$this->setField('DATE_CANCELED', new Type\DateTime());

			if ($USER->isAuthorized())
				$this->setField('EMP_CANCELED_ID', $USER->getID());

			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_CANCELED, array(
				'ENTITY' => $this,
			));

			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_CANCELED_SEND_MAIL, array(
				'ENTITY' => $this,
			));
		}
		elseif ($name == "USER_ID")
		{
			throw new Main\NotImplementedException('field USER_ID');
		}
		elseif($name == "MARKED")
		{
			if ($oldValue != "Y")
			{
				$this->setField('DATE_MARKED', new Type\DateTime());

				if ($USER->isAuthorized())
					$this->setField('EMP_MARKED_ID', $USER->getID());
			}
			elseif ($value == "N")
			{
				$this->setField('REASON_MARKED', '');
			}

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

			$r = $shipmentCollection->onOrderModify($name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}
		}
		elseif ($name == "STATUS_ID")
		{

			$event = new Main\Event('sale', EventActions::EVENT_ON_BEFORE_ORDER_STATUS_CHANGE, array(
				'ENTITY' => $this,
				'VALUE' => $value,
				'OLD_VALUE' => $oldValue,
			));
			$event->send();

			$this->setField('DATE_STATUS', new Type\DateTime());

			if ($USER && $USER->isAuthorized())
				$this->setField('EMP_STATUS_ID', $USER->GetID());

			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_STATUS_CHANGE, array(
				'ENTITY' => $this,
				'VALUE' => $value,
				'OLD_VALUE' => $oldValue,
			));

			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_STATUS_CHANGE_SEND_MAIL, array(
				'ENTITY' => $this,
				'VALUE' => $value,
				'OLD_VALUE' => $oldValue,
			));
		}

		return $result;
	}

	/**
	 * Modify basket.
	 *
	 * @param string $action				Action.
	 * @param BasketItem $basketItem		Basket item.
	 * @param null|string $name				Field name.
	 * @param null|string|int|float $oldValue		Old value.
	 * @param null|string|int|float $value			New value.
	 * @return Result
	 * @throws Main\NotImplementedException
	 * @throws Main\NotSupportedException
	 * @throws Main\ObjectNotFoundException
	 */
	public function onBasketModify($action, BasketItem $basketItem, $name = null, $oldValue = null, $value = null)
	{
		$result = new Result();
		if ($action != EventActions::UPDATE)
			return $result;

		if ($name == "QUANTITY")
		{
			if ($value < 0)
			{
				$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_BASKET_WRONG_QUANTITY',
									array(
										'#PRODUCT_NAME#' => $basketItem->getField('NAME')
									)
				), 'SALE_ORDER_BASKET_WRONG_QUANTITY') );

				return $result;
			}

			/** @var ShipmentCollection $shipmentCollection */
			if (!$shipmentCollection = $this->getShipmentCollection())
			{
				throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
			}
			$r = $shipmentCollection->onBasketModify($action, $basketItem, $name, $oldValue, $value);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

			if ($value == 0)
			{

				/** @var Result $r */
				$r = $this->refreshVat();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
					return $result;
				}

				if ($tax = $this->getTax())
				{
					$tax->refreshData();
				}
			}

			if ($basketItem->isBundleChild())
				return $result;

			/** @var Result $result */
			$r = $this->setField(
				"PRICE",
				$this->getBasket()->getPrice() + $this->getShipmentCollection()->getPriceDelivery()
			);

			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}

			if ($this->getId() == 0 && !$this->isMathActionOnly())
			{
				$shipmentCollection->refreshData();
			}

			return $result;
		}
		elseif ($name == "PRICE")
		{
			/** @var Result $result */
			$r = $this->setField(
				"PRICE",
				$this->getBasket()->getPrice() + $this->getShipmentCollection()->getPriceDelivery()
			);

			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

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

			if ($this->getId() == 0 && !$this->isMathActionOnly())
			{
				$shipmentCollection->refreshData();
			}
			return $result;
		}
		elseif ($name == "CURRENCY")
		{
			if ($value != $this->getField("CURRENCY"))
				throw new Main\NotSupportedException("CURRENCY");
		}
		elseif ($name == "DIMENSIONS")
		{
			/** @var ShipmentCollection $shipmentCollection */
			if (!$shipmentCollection = $this->getShipmentCollection())
			{
				throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
			}
			return $shipmentCollection->onBasketModify($action, $basketItem, $name, $oldValue, $value);
		}

		return $result;
	}

	/**
	 * Modify property value collection.
	 *
	 * @param string $action				Action.
	 * @param PropertyValue $property		Property.
	 * @param null|string $name				Field name.
	 * @param null|string|int|float $oldValue		Old value.
	 * @param null|string|int|float $value			New value.
	 * @return bool
	 */
	public function onPropertyValueCollectionModify($action, PropertyValue $property, $name = null, $oldValue = null, $value = null)
	{
		return new Result();
	}

	/**
	 * Sync.
	 *
	 * @param Payment $payment			Payment.
	 * @return Result
	 * @throws Main\ObjectNotFoundException
	 */
	protected function syncOrderAndPayments(Payment $payment = null)
	{
		global $USER;

		$result = new Result();

		$oldPaid = $this->getField('PAYED');
		$paymentCollection = $this->getPaymentCollection();
		$sumPaid = $paymentCollection->getPaidSum();

		if ($payment)
		{
			$finalSumPaid = $sumPaid;

			if ($payment->isPaid())
			{
				if ($sumPaid > $this->getPrice())
				{
					$finalSumPaid = $this->getSumPaid() + $payment->getSum();
				}
			}
			else
			{

				$r = $this->syncOrderPaymentPaid($payment);
				if ($r->isSuccess())
				{
					$paidResult = $r->getData();
					if (isset($paidResult['SUM_PAID']))
					{
						$finalSumPaid = $paidResult['SUM_PAID'];
					}
				}
				else
				{
					$result->addErrors($r->getErrors());
					return $result;
				}

			}
		}
		else
		{
			$finalSumPaid = $this->getSumPaid();

			$r = $this->syncOrderPaid();
			if ($r->isSuccess())
			{
				$paidResult = $r->getData();
				if (isset($paidResult['SUM_PAID']))
				{
					$finalSumPaid = $paidResult['SUM_PAID'];
				}
			}
			else
			{
				$result->addErrors($r->getErrors());
				return $result;
			}
		}

		$paid = ($finalSumPaid > 0 && Payment::roundByFormatCurrency($this->getPrice(), $this->getCurrency()) <= Payment::roundByFormatCurrency($finalSumPaid, $this->getCurrency()));

		$this->setFieldNoDemand('PAYED', $paid ? "Y" : "N");

		if ($paid && $oldPaid == "N")
		{
			if ($payment !== null)
				$payment->setFieldNoDemand('IS_RETURN', 'N');

			if ($USER->isAuthorized())
				$this->setFieldNoDemand('EMP_PAYED_ID', $USER->getID());

			if ($paymentCollection->isPaid() && $payment !== null)
			{
				if (strval($payment->getField('PAY_VOUCHER_NUM')) != '')
				{
					$this->setFieldNoDemand('PAY_VOUCHER_NUM', $payment->getField('PAY_VOUCHER_NUM'));
				}

				if (strval($payment->getField('PAY_VOUCHER_DATE')) != '')
				{
					$this->setFieldNoDemand('PAY_VOUCHER_DATE', $payment->getField('PAY_VOUCHER_DATE'));
				}
			}
		}

		if ($finalSumPaid > 0 && $finalSumPaid > $this->getPrice())
		{
			if (($payment && $payment->isPaid()) || !$payment)
			{
				Internals\UserBudgetPool::addPoolItem($this, $finalSumPaid - $this->getPrice(), Internals\UserBudgetPool::BUDGET_TYPE_EXCESS_SUM_PAID, $payment);
			}

			$finalSumPaid = $this->getPrice();
		}

		$this->setFieldNoDemand('SUM_PAID', $finalSumPaid);

		$r = $this->onAfterSyncPaid($oldPaid);

		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	/**
	 * @param Payment $payment
	 * @return Result
	 */
	protected function syncOrderPaymentPaid(Payment $payment)
	{
		$result = new Result();

		if ($payment->isPaid())
			return $result;

		$paymentCollection = $this->getPaymentCollection();
		$sumPaid = $paymentCollection->getPaidSum();

		$userBudget = Internals\UserBudgetPool::getUserBudgetByOrder($this);

		$debitSum = $payment->getSum();

		$maxPaid = $payment->getSum() + $sumPaid - $this->getSumPaid();

		if ($maxPaid >= $payment->getSum())
		{
			$finalSumPaid = $this->getSumPaid();
		}
		else
		{
			$debitSum = $maxPaid;
			$finalSumPaid = $sumPaid;
		}

		if ($debitSum > 0)
		{
			if (Payment::roundByFormatCurrency($debitSum, $this->getCurrency()) > Payment::roundByFormatCurrency($userBudget, $this->getCurrency()))
			{
				$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_PAYMENT_CANCELLED_PAID'), 'SALE_ORDER_PAYMENT_NOT_ENOUGH_USER_BUDGET_SYNCPAID') );
				return $result;
			}

			Internals\UserBudgetPool::addPoolItem($this, ($debitSum * -1), Internals\UserBudgetPool::BUDGET_TYPE_ORDER_CANCEL_PART, $payment);
		}

		$result->setData(array('SUM_PAID' => $finalSumPaid));

		return $result;
	}

	/**
	 * @return Result
	 */
	protected function syncOrderPaid()
	{
		$result = new Result();

		if ($this->getSumPaid() == $this->getPrice())
			return $result;

		$debitSum = $this->getPrice() - $this->getSumPaid();

		$paymentCollection = $this->getPaymentCollection();
		$sumPaid = $paymentCollection->getPaidSum();
		$userBudget = Internals\UserBudgetPool::getUserBudgetByOrder($this);

		$bePaid = $sumPaid - $this->getSumPaid();

		if ($bePaid > 0)
		{
			if ($debitSum > $bePaid)
			{
				$debitSum = $bePaid;
			}

			if ($debitSum >= $userBudget)
			{
				$debitSum = $userBudget;
			}

			if ($userBudget >= $debitSum && $debitSum > 0)
			{
				Internals\UserBudgetPool::addPoolItem($this, ($debitSum * -1), Internals\UserBudgetPool::BUDGET_TYPE_ORDER_PAY);

				$finalSumPaid = $this->getSumPaid() + $debitSum;
				$result->setData(array(
									 'SUM_PAID' => $finalSumPaid
								 ));
			}
		}


		return $result;
	}


	/**
	 * @param null $oldPaid
	 * @return Result
	 * @throws Main\ObjectNotFoundException
	 */
	protected function onAfterSyncPaid($oldPaid = null)
	{
		global $USER;
		$result = new Result();
		/** @var PaymentCollection $paymentCollection */
		if (!$paymentCollection = $this->getPaymentCollection())
		{
			throw new Main\ObjectNotFoundException('Entity "PaymentCollection" not found');
		}

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

		$oldPaidBool = null;

		if ($oldPaid !== null)
			$oldPaidBool = ($oldPaid == "Y");

		if ($oldPaid == "N" && $this->isPaid() )
		{

			$orderStatus = Config\Option::get('sale', 'status_on_paid', '');

			if (strval($orderStatus) != '')
			{
				if ($USER && $USER->isAuthorized())
				{
					$statusesList = OrderStatus::getAllowedUserStatuses($USER->getID(), $this->getField('STATUS_ID'));
					$statusesList = array_keys($statusesList);
				}
				else
				{
					$statusesList = OrderStatus::getAllStatuses();
				}

				if($this->getField('STATUS_ID') != $orderStatus && in_array($orderStatus, $statusesList))
				{
					$this->setField('STATUS_ID', $orderStatus);
				}
			}

		}

		if ($oldPaid !== null && $this->isPaid() != $oldPaidBool)
		{
			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_PAID, array(
				'ENTITY' => $this,
			));

			Internals\EventsPool::addEvent($this, EventActions::EVENT_ON_ORDER_PAID_SEND_MAIL, array(
				'ENTITY' => $this,
			));
		}

		if (Configuration::getProductReservationCondition() == Configuration::RESERVE_ON_PAY)
		{
			if ($paymentCollection->hasPaidPayment())
			{
				$r = $shipmentCollection->tryReserve();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
			else
			{
				$r = $shipmentCollection->tryUnreserve();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
		}
		elseif (Configuration::getProductReservationCondition() == Configuration::RESERVE_ON_FULL_PAY)
		{
			if ($oldPaid == "N" && $this->isPaid())
			{
				$r = $shipmentCollection->tryReserve();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
			elseif ($oldPaid == "Y" && !$this->isPaid())
			{
				$r = $shipmentCollection->tryUnreserve();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
		}

		if (Configuration::needAllowDeliveryOnPay())
		{
			if ($oldPaid == "N" && $this->isPaid())
			{
				$r = $shipmentCollection->allowDelivery();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
			elseif ($oldPaid == "Y" && !$this->isPaid())
			{
				$r = $shipmentCollection->disallowDelivery();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}
		}

		return $result;
	}

	/**
	 * Reset the value of the order and delivery
	 * @internal
	 * @param array $select - the list of fields which need to be reset
	 */
	public function resetData($select = array('PRICE'))
	{
		if (in_array('PRICE', $select))
		{
			$this->setFieldNoDemand('PRICE', 0);
		}

		if (in_array('PRICE_DELIVERY', $select))
		{
			$this->setFieldNoDemand('PRICE_DELIVERY', 0);
		}
	}

	/**
	 * Reset the value of taxes
	 *
	 * @internal
	 */
	public function resetTax()
	{
		$this->setFieldNoDemand('TAX_PRICE', 0);
		$this->setFieldNoDemand('TAX_VALUE', 0);
	}

	/**
	 * Full refresh order data.
	 *
	 * @param array $select				Fields list.
	 * @return Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ObjectNotFoundException
	 */
	public function refreshData($select = array())
	{
		$result = new Result();

		$isStartField = $this->isStartField();

		$this->calculateType = ($this->getId() > 0 ? static::SALE_ORDER_CALC_TYPE_REFRESH : static::SALE_ORDER_CALC_TYPE_NEW);
		$this->resetData($select);

		/** @var Basket $basket */
		$basket = $this->getBasket();
		if (!$basket)
		{
			return $result;
		}

		/** @var Result $r */
		$r = $this->setField('PRICE', $basket->getPrice());
		if (!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			return $result;
		}

		if ($this instanceof \IShipmentOrder)
		{
			/** @var ShipmentCollection $shipmentCollection */
			if (!$shipmentCollection = $this->getShipmentCollection())
			{
				throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
			}

			$r = $shipmentCollection->refreshData();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}
		}

		/** @var Tax $tax */
		if ($tax = $this->getTax())
		{
			$tax->resetTaxList();
		}

		if ($isStartField)
		{
			$hasMeaningfulFields = $this->hasMeaningfulField();

			/** @var Result $r */
			$r = $this->doFinalAction($hasMeaningfulFields);
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}

		return $result;
	}

	/**
	 * Get the entity of taxes
	 *
	 * @return Tax
	 */
	public function getTax()
	{
		if ($this->tax === null)
		{
			$this->tax = $this->loadTax();
		}
		return $this->tax;
	}

	/**
	 *
	 * @return Result
	 * @throws Main\ObjectNotFoundException
	 */
	protected function syncOrderTax()
	{
		$result = new Result();

		/** @var Tax $tax */
		if (!$tax = $this->getTax())
		{
			throw new Main\ObjectNotFoundException('Entity "Tax" not found');
		}

		$this->resetTax();
		/** @var Result $r */
		$r = $tax->calculate();
		if ($r->isSuccess())
		{
			$taxResult = $r->getData();
			if (isset($taxResult['TAX_PRICE']) && floatval($taxResult['TAX_PRICE']) > 0)
			{
				/** @var Result $r */
				$r = $this->setField('TAX_PRICE', $taxResult['TAX_PRICE']);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}

			if (isset($taxResult['VAT_SUM']) && floatval($taxResult['VAT_SUM']) > 0)
			{
				/** @var Result $r */
				$r = $this->setField('VAT_SUM', $taxResult['VAT_SUM']);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}

			if (isset($taxResult['VAT_DELIVERY']) && floatval($taxResult['VAT_DELIVERY']) > 0)
			{
				/** @var Result $r */
				$r = $this->setField('VAT_DELIVERY', $taxResult['VAT_DELIVERY']);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}

			/** @var Result $r */
			$r = $this->setField('TAX_VALUE', $this->isUsedVat()? $this->getVatSum() : $this->getField('TAX_PRICE'));
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}

		}
		else
		{
			$result->addErrors($r->getErrors());
		}

		return $result;
	}

	/**
	 * @return Tax|static
	 */
	protected function loadTax()
	{
		return Tax::load($this);
	}


	/**
	 * @return Discount
	 */
	public function getDiscount()
	{
		if ($this->discount === null)
		{
			$this->discount = $this->loadDiscount();
		}

		return $this->discount;
	}

	/**
	 * @return mixed
	 */
	protected function loadDiscount()
	{
		return Discount::load($this);
	}

	/**
	 * Set account number.
	 *
	 * @param int $id			Account id.
	 * @return bool
	 */
	public static function setAccountNumber($id)
	{
		return \CSaleOrder::setAccountNumberById($id);
	}

	/**
	 * apply discount.
	 * @internal
	 * @param array $data			Order data.
	 * @return Result
	 */
	public function applyDiscount(array $data)
	{
		if (!empty($data['BASKET_ITEMS']) && is_array($data['BASKET_ITEMS']))
		{
			/** @var Basket $basket */
			$basket = $this->getBasket();

			foreach ($data['BASKET_ITEMS'] as $basketCode => $basketItemData)
			{
				/** @var BasketItem $basketItem */
				if ($basketItem = $basket->getItemByBasketCode($basketCode))
				{
					if (!$basketItem->isCustomPrice())
					{
						if (isset($basketItemData['PRICE']) && isset($basketItemData['DISCOUNT_PRICE']))
						{
							$basketItemData['PRICE'] = (float)$basketItemData['PRICE'];
							if ($basketItemData['PRICE'] >= 0 && $basketItem->getPrice() != $basketItemData['PRICE'])
							{
								$basketItemData['PRICE'] = roundEx($basketItemData['PRICE'], SALE_VALUE_PRECISION);
								$basketItemData['DISCOUNT_PRICE'] = roundEx($basketItemData['DISCOUNT_PRICE'], SALE_VALUE_PRECISION);
								$basketItem->setField('PRICE', $basketItemData['PRICE']);
								$basketItem->setField('DISCOUNT_PRICE', $basketItemData['DISCOUNT_PRICE']);
							}
						}
					}
				}
				unset($basketItem);
			}
			unset($basketCode, $basketItemData);
		}

		if (isset($data['SHIPMENT']) && intval($data['SHIPMENT']) > 0
			&& isset($data['PRICE_DELIVERY']) && floatval($data['PRICE_DELIVERY']) >= 0)
		{
			/** @var ShipmentCollection $shipmentCollection */
			if ($shipmentCollection = $this->getShipmentCollection())
			{
				/** @var Shipment $shipment */
				if ($shipment = $shipmentCollection->getItemByShipmentCode($data['SHIPMENT']))
				{
					if (floatval($data['PRICE_DELIVERY']) >= 0)
					{
						$data['PRICE_DELIVERY'] = roundEx(floatval($data['PRICE_DELIVERY']), SALE_VALUE_PRECISION);
						$shipment->setField('PRICE_DELIVERY', $data['PRICE_DELIVERY']);
					}


				}
			}
		}


		if (isset($data['DISCOUNT_PRICE']) && floatval($data['DISCOUNT_PRICE']) >= 0)
		{
			$data['DISCOUNT_PRICE'] = roundEx(floatval($data['DISCOUNT_PRICE']), SALE_VALUE_PRECISION);
			$this->setField('DISCOUNT_PRICE', $data['DISCOUNT_PRICE']);
		}

		return new Result();
	}

	/**
	 * Save field modify to history.
	 *
	 * @param string $name				Field name.
	 * @param null|string $oldValue		Old value.
	 * @param null|string $value		New value.
	 */
	protected function addChangesToHistory($name, $oldValue = null, $value = null)
	{
		if ($this->getId() > 0)
		{
			$historyFields = array();
			if ($name == "PRICE")
			{
				$historyFields['CURRENCY'] = $this->getCurrency();
			}

			$historyFields['OLD_'.$name] = $oldValue;

			OrderHistory::addField(
				'ORDER',
				$this->getId(),
				$name,
				$oldValue,
				$value,
				$this->getId(),
				$this,
				$historyFields
			);
		}
	}

	/**
	 * Lock order.
	 *
	 * @param int $id			Order id.
	 * @return Entity\UpdateResult|Result
	 * @throws \Exception
	 */
	public static function lock($id)
	{
		global $USER;

		$result = new Result();
		$id = (int)$id;
		if ($id <= 0)
		{
			$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_WRONG_ID'), 'SALE_ORDER_WRONG_ID') );
			return $result;
		}

		return Internals\OrderTable::update($id, array(
			'DATE_LOCK' => new Main\Type\DateTime(),
			'LOCKED_BY' => $USER->GetID()
		));
	}

	/**
	 * Unlock order.
	 *
	 * @param int $id			Order id.
	 * @return Entity\UpdateResult|Result
	 * @throws Main\ArgumentNullException
	 * @throws \Exception
	 */
	public static function unlock($id)
	{
		global $USER;

		$result = new Result();
		$id = (int)$id;
		if ($id <= 0)
		{
			$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_WRONG_ID'), 'SALE_ORDER_WRONG_ID') );
			return $result;
		}

		if(!$order = Order::load($id))
		{
			$result->addError( new ResultError(Loc::getMessage('SALE_ORDER_ENTITY_NOT_FOUND'), 'SALE_ORDER_ENTITY_NOT_FOUND') );
			return $result;
		}

		$userRights = \CMain::getUserRight("sale", $USER->getUserGroupArray(), "Y", "Y");

		if (($userRights >= "W") || ($order->getField("LOCKED_BY") == $USER->getID()))
		{
			return Internals\OrderTable::update($id, array(
				'DATE_LOCK' => null,
				'LOCKED_BY' => null
			));
		}

		return $result;
	}

	/**
	 * Return is order locked.
	 *
	 * @param int $id			Order id.
	 * @return bool
	 */
	public static function isLocked($id)
	{
		/** @var Result $r */
		$r = static::getLockedStatus($id);
		if ($r->isSuccess())
		{
			$lockResultData = $r->getData();

			if (array_key_exists('LOCK_STATUS', $lockResultData)
				&& $lockResultData['LOCK_STATUS'] == static::SALE_ORDER_LOCK_STATUS_RED)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Return order locked status.
	 *
	 * @param int $id		Order id.
	 * @return Result
	 * @throws Main\ArgumentException
	 */
	public static function getLockedStatus($id)
	{
		$result = new Result();

		$res = Internals\OrderTable::getList(array(
				'filter' => array('=ID' => $id),
				'select' => array(
					'LOCKED_BY',
					'LOCK_STATUS',
					'DATE_LOCK'
				)
		));

		if ($data = $res->fetch())
		{
			$result->addData(array(
				'LOCKED_BY' => $data['LOCKED_BY'],
				'LOCK_STATUS' => $data['LOCK_STATUS'],
				'DATE_LOCK' => $data['DATE_LOCK'],
			));
		}

		return $result;
	}

	/**
	 * @return null|string
	 */
	public function getTaxLocation()
	{
		if (strval(($this->getField('TAX_LOCATION')) == ""))
		{
			/** @var PropertyValueCollection $propertyCollection */
			$propertyCollection = $this->getPropertyCollection();

			if ($property = $propertyCollection->getTaxLocation())
			{
				$this->setField('TAX_LOCATION', $property->getValue());
			}

		}

		return $this->getField('TAX_LOCATION');
	}

	/**
	 * @param bool $isMeaningfulField
	 * @return bool
	 */
	public function isStartField($isMeaningfulField = false)
	{
		if ($this->isStartField === null)
		{
			$this->isStartField = true;
		}
		else
			$this->isStartField = false;

		if ($isMeaningfulField === true)
		{
			$this->isMeaningfulField = true;
		}

		return $this->isStartField;
	}

	/**
	 *
	 */
	public function clearStartField()
	{
		$this->isStartField = null;
		$this->isMeaningfulField = false;
	}

	/**
	 * @return bool
	 */
	public function hasMeaningfulField()
	{
		return $this->isMeaningfulField;
	}

	/**
	 * @param bool $hasMeaningfulField
	 * @return Result
	 * @throws Main\ArgumentNullException
	 * @throws Main\ObjectNotFoundException
	 */
	public function doFinalAction($hasMeaningfulField = false)
	{
		$result = new Result();

		if (!$hasMeaningfulField)
		{
			$this->clearStartField();
			return $result;
		}

		$currentIsMathActionOnly = $this->isMathActionOnly();

		if ($basket = $this->getBasket())
		{
			$this->setMathActionOnly(true);

			if ($eventName = static::getEntityEventName())
			{
				$event = new Main\Event('sale', 'OnBefore'.$eventName.'FinalAction', array(
					'ENTITY' => $this,
					'HAS_MEANINGFUL_FIELD' => $hasMeaningfulField,
					'BASKET' => $basket,
				));
				$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_BEFORE_'.strtoupper($eventName).'_FINAL_ACTION_ERROR'), 'SALE_EVENT_ON_BEFORE_'.strtoupper($eventName).'_FINAL_ACTION_ERROR');
							if ($eventResultData = $eventResult->getParameters())
							{
								if (isset($eventResultData) && $eventResultData instanceof ResultError)
								{
									/** @var ResultError $errorMsg */
									$errorMsg = $eventResultData;
								}
							}

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

				if (!$result->isSuccess())
				{
					return $result;
				}
			}



			// discount
			$discount = $this->getDiscount();
			$r = $discount->calculate();
			if (!$r->isSuccess())
			{
//				$this->clearStartField();
//				$result->addErrors($r->getErrors());
//				return $result;
			}

			if ($r->isSuccess() && ($discountData = $r->getData()) && !empty($discountData) && is_array($discountData))
			{
				/** @var Result $r */
				$r = $this->applyDiscount($discountData);
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
					return $result;
				}
			}


			/** @var Tax $tax */
			$tax = $this->getTax();
			/** @var Result $r */
			$r = $tax->calculate();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

			$r = $tax->calculateDelivery();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
				return $result;
			}

			$taxChanged = false;
			$taxResult = $r->getData();
			if (isset($taxResult['TAX_PRICE']) && floatval($taxResult['TAX_PRICE']) >= 0)
			{
				if (!$this->isUsedVat())
				{
					$taxChanged = true;
					$this->setField('TAX_PRICE', $taxResult['TAX_PRICE']);

					$this->setFieldNoDemand(
						"PRICE",
						$this->getBasket()->getPrice() + $this->getShipmentCollection()->getPriceDelivery() + $taxResult['TAX_PRICE']
					);
				}

			}

			if (array_key_exists('VAT_SUM', $taxResult))
			{
				if ($this->isUsedVat())
				{
					$this->setField('VAT_SUM', $taxResult['VAT_SUM']);
				}
			}

			if ($taxChanged || $this->isUsedVat())
			{
				$taxValue = $this->isUsedVat()? $this->getVatSum() : $this->getField('TAX_PRICE');
				if (floatval($taxValue) != floatval($this->getField('TAX_VALUE')))
					$this->setField('TAX_VALUE', floatval($taxValue));
			}





		}

		//
		if (!$currentIsMathActionOnly)
			$this->setMathActionOnly(false);

		//


		$this->clearStartField();

		if ($eventName = static::getEntityEventName())
		{
			$event = new Main\Event('sale', 'OnAfter'.$eventName.'FinalAction', array(
				'ENTITY' => $this,
			));
			$event->send();
		}

		return $result;
	}

	/**
	 * @internal
	 * @param bool $value
	 * @return bool
	 */
	public function setMathActionOnly($value = false)
	{
		$this->isOnlyMathAction = $value;
	}

	/**
	 * @return bool
	 */
	public function isMathActionOnly()
	{
		return $this->isOnlyMathAction;
	}

	/**
	 * @param string $event
	 * @return array
	 */
	public static function getEventListUsed($event)
	{
		return GetModuleEvents("sale", $event, true);
	}

	/**
	 * @internal
	 * @return null|bool
	 */
	public function isNew()
	{
		return $this->isNew;
	}

	/**
	 * @return bool
	 */
	public function isChanged()
	{
		if (parent::isChanged())
			return true;

		/** @var PropertyValueCollection $propertyCollection */
		if ($propertyCollection = $this->getPropertyCollection())
		{
			if ($propertyCollection->isChanged())
			{
				return true;
			}
		}

		/** @var Basket $basket */
		if ($basket = $this->getBasket())
		{
			if ($basket->isChanged())
			{
				return true;
			}

			/** @var PaymentCollection $paymentCollection */
			if ($paymentCollection = $this->getPaymentCollection())
			{
				if ($paymentCollection->isChanged())
				{
					return true;
				}
			}

			/** @var ShipmentCollection $shipmentCollection */
			if ($shipmentCollection = $this->getShipmentCollection())
			{
				if ($shipmentCollection->isChanged())
				{
					return true;
				}
			}

		}

		return false;
	}

	/**
	 * @return Result
	 */
	public function verify()
	{
		$result = new Result();
		/** @var Basket $basket */
		if ($basket = $this->getBasket())
		{
			$r = $basket->verify();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}

		/** @var PaymentCollection $paymentCollection */
		if ($paymentCollection = $this->getPaymentCollection())
		{
			$r = $paymentCollection->verify();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}

		/** @var ShipmentCollection $shipmentCollection */
		if ($shipmentCollection = $this->getShipmentCollection())
		{
			$r = $shipmentCollection->verify();
			if (!$r->isSuccess())
			{
				$result->addErrors($r->getErrors());
			}
		}

		return $result;
	}

	public function getBusinessValueProviderInstance($mapping)
	{
		$providerInstance = null;

		if (is_array($mapping))
		{
			switch ($mapping['PROVIDER_KEY'])
			{
				case 'ORDER'   :
				case 'PROPERTY': $providerInstance = $this; break;
				case 'USER'    : $providerInstance = $this->getField('USER_ID'); break;
				// TODO case 'PAYMENT' & 'SHIPMENT': aggregate fields maybe?? What about COMPANY??
			}
		}

		return $providerInstance;
	}

}