403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/sale/lib/helpers/order/builder/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/sale/lib/helpers/order/builder/orderbuilder.php
<?php
namespace Bitrix\Sale\Helpers\Order\Builder;

use Bitrix\Main;
use Bitrix\Sale\Internals;
use Bitrix\Sale\PropertyValue;
use Bitrix\Sale\PropertyValueCollection;
use Bitrix\Sale\BasketItem;
use Bitrix\Sale\Shipment;
use Bitrix\Main\ArgumentNullException;
use Bitrix\Main\Error;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ObjectException;
use Bitrix\Sale\Order;
use Bitrix\Sale\Helpers\Admin\Blocks\OrderBuyer;
use Bitrix\Sale\Payment;
use Bitrix\Sale\PaySystem;
use Bitrix\Main\Type\Date;
use Bitrix\Main\Type\DateTime;
use Bitrix\Sale\Registry;
use \Bitrix\Sale\Delivery;
use Bitrix\Sale\Result;
use Bitrix\Sale\Configuration;
use Bitrix\Sale\ShipmentItem;
use Bitrix\Sale\TradeBindingEntity;
use Bitrix\Sale\TradingPlatformTable;

Loc::loadLanguageFile($_SERVER['DOCUMENT_ROOT'] . BX_ROOT . '/modules/sale/lib/helpers/admin/blocks/orderbasketshipment.php');

/**
 * Class OrderBuilder
 * @package Bitrix\Sale\Helpers\Order\Builder
 * @internal
 */
abstract class OrderBuilder
{
	/** @var OrderBuilderExist|OrderBuilderNew */
	protected $delegate = null;
	/** @var BasketBuilder  */
	protected $basketBuilder = null;

	/** @var SettingsContainer */
	protected $settingsContainer = null;

	/** @var Order  */
	protected $order = null;
	/** @var array */
	protected $formData = array();
	/** @var ErrorsContainer  */
	protected $errorsContainer = null;

	/** @var bool */
	protected $isStartField;

	/** @var Registry */
	protected $registry = null;

	public function __construct(SettingsContainer $settings)
	{
		$this->settingsContainer = $settings;
		$this->errorsContainer = new ErrorsContainer();
		$this->errorsContainer->setAcceptableErrorCodes(
			$this->settingsContainer->getItemValue('acceptableErrorCodes')
		);

		$this->registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);
	}

	/**
	 * @param $data
	 * @throws BuildingException
	 */
	public function build($data)
	{
		$this->initFields($data)
			->delegate()
			->createOrder()
			->setDiscounts() //?
			->setFields()
			->buildTradeBindings()
			->setProperties()
			->setUser()
			->buildProfile()
			->buildBasket()
			->buildPayments()
			->buildShipments()
			->setRelatedProperties()
			->setDiscounts() //?
			->finalActions();

		return $this;
	}

	public function setBasketBuilder(BasketBuilder $basketBuilder)
	{
		$this->basketBuilder = $basketBuilder;
	}

	public function getRegistry()
	{
		return $this->registry;
	}

	protected function prepareFields(array $fields)
	{
		$fields["ID"] = (isset($fields["ID"]) ? (int)$fields["ID"] : 0);
		return $fields;
	}

	public function initFields(array $data)
	{
		$data = $this->prepareFields($data);
		$this->formData = $data;
		return $this;
	}

	public function delegate()
	{
		$data = $this->formData;
		$this->delegate = (int)$data['ID'] > 0 ? new OrderBuilderExist($this) : new OrderBuilderNew($this);

		return $this;
	}

	public function createOrder()
	{
		$data = $this->formData;
		if($this->order = $this->delegate->createOrder($data))
		{
			$this->isStartField = $this->order->isStartField();
		}

		return $this;
	}

	protected function getSettableShipmentFields()
	{
		$shipmentClassName = $this->registry->getShipmentClassName();
		return array_merge(['PROPERTIES'], $shipmentClassName::getAvailableFields());
	}

	protected function getSettablePaymentFields()
	{
		$paymentClassName = $this->registry->getPaymentClassName();
		return $paymentClassName::getAvailableFields();
	}

	protected function getSettableOrderFields()
	{
		return ['RESPONSIBLE_ID', 'USER_DESCRIPTION', 'ORDER_TOPIC', 'ACCOUNT_NUMBER'];
	}

	public function setFields()
	{
		$fields = $this->getSettableOrderFields();

		foreach($fields as $field)
		{
			if(isset($this->formData[$field]))
			{
				$r = $this->order->setField($field, $this->formData[$field]);

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

		if(isset($this->formData["PERSON_TYPE_ID"]) && intval($this->formData["PERSON_TYPE_ID"]) > 0)
		{
			/** @var \Bitrix\Sale\Result $r */
			$r = $this->order->setPersonTypeId(intval($this->formData['PERSON_TYPE_ID']));
		}
		else
		{
			/** @var \Bitrix\Sale\Result $r */
			$r = $this->order->setPersonTypeId(
				OrderBuyer::getDefaultPersonType(
					$this->order->getSiteId()
				)
			);
		}

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

		return $this;
	}

	public function setProperties()
	{
		if (empty($this->formData["PROPERTIES"]))
		{
			return $this;
		}

		$propCollection = $this->order->getPropertyCollection();
		$res = $propCollection->setValuesFromPost(
			$this->formData,
			$this->settingsContainer->getItemValue('propsFiles')
		);

		if (!$res->isSuccess())
		{
			$this->getErrorsContainer()->addErrors($res->getErrors());
		}

		return $this;
	}

	public function setRelatedProperties()
	{
		if (empty($this->formData["PROPERTIES"]))
		{
			return $this;
		}

		$propCollection = $this->order->getPropertyCollection();

		/** @var PropertyValue $propertyValue */
		foreach ($propCollection as $propertyValue)
		{
			if (!$propertyValue->getRelations())
			{
				continue;
			}

			$post = Internals\Input\File::getPostWithFiles($this->formData, $this->settingsContainer->getItemValue('propsFiles'));

			$res = $propertyValue->setValueFromPost($post);
			if (!$res->isSuccess())
			{
				$this->getErrorsContainer()->addErrors($res->getErrors());
			}
		}

		return $this;
	}

	public function setUser()
	{
		$this->delegate->setUser();
		return $this;
	}

	public function buildProfile()
	{
		if (empty($this->formData["PROPERTIES"]) || empty($this->formData["USER_ID"]))
		{
			return $this;
		}

		$profileId = $this->formData["USER_PROFILE"]["ID"] ?? 0;
		$profileName = $this->formData["USER_PROFILE"]["NAME"] ?? '';

		$errors = [];
		\CSaleOrderUserProps::DoSaveUserProfile(
			$this->getUserId(),
			$profileId,
			$profileName,
			$this->order->getPersonTypeId(),
			$this->formData["PROPERTIES"],
			$errors
		);

		foreach ($errors as $error)
		{
			$this->errorsContainer->addError(new Main\Error($error['TEXT'], $error['CODE'], 'PROFILE'));
		}

		return $this;
	}

	public function setDiscounts()
	{
		if(isset($this->formData["DISCOUNTS"]) && is_array($this->formData["DISCOUNTS"]))
		{
			$this->order->getDiscount()->setApplyResult($this->formData["DISCOUNTS"]);

			$r = $this->order->getDiscount()->calculate();

			if($r->isSuccess())
			{
				$discountData = $r->getData();
				$this->order->applyDiscount($discountData);
			}
		}

		return $this;
	}

	public function buildBasket()
	{
		$this->delegate->buildBasket();
		return $this;
	}

	protected function createEmptyShipment()
	{
		$shipments = $this->order->getShipmentCollection();
		return $shipments->createItem();
	}

	protected function removeShipments()
	{
		if($this->getSettingsContainer()->getItemValue('deleteShipmentIfNotExists'))
		{
			$shipmentCollection = $this->order->getShipmentCollection();

			$shipmentIds = [];
			foreach($this->formData["SHIPMENT"] as $shipmentData)
			{
				if(!isset($shipmentData['ID']))
					continue;

				$shipment = $shipmentCollection->getItemById($shipmentData['ID']);

				if ($shipment == null)
					continue;

				$shipmentIds[] = $shipment->getId();
			}

			foreach ($shipmentCollection as $shipment)
			{
				if($shipment->isSystem())
					continue;

				if(!in_array($shipment->getId(), $shipmentIds))
				{
					$r = $shipment->delete();
					if (!$r->isSuccess())
					{
						$this->errorsContainer->addErrors($r->getErrors());
						return false;
					}
				}
			}
		}
		return true;
	}

	protected function prepareFieldsStatusId($isNew, $item, $defaultFields)
	{
		$statusId = '';

		if($isNew)
		{
			$deliveryStatusClassName = $this->registry->getDeliveryStatusClassName();
			$statusId = $deliveryStatusClassName::getInitialStatus();
		}
		elseif (isset($item['STATUS_ID']) && $item['STATUS_ID'] !== $defaultFields['STATUS_ID'])
		{
			$statusId = $item['STATUS_ID'];
		}

		return $statusId;
	}

	public function buildShipments()
	{
		$isEmptyShipmentData = empty($this->formData["SHIPMENT"]) || !is_array($this->formData["SHIPMENT"]);
		if ($isEmptyShipmentData)
		{
			$this->formData["SHIPMENT"] = [];
		}

		if ($isEmptyShipmentData && !$this->getSettingsContainer()->getItemValue('createDefaultShipmentIfNeed'))
		{
			return $this;
		}

		if($isEmptyShipmentData && $this->getOrder()->isNew())
		{
			$this->createEmptyShipment();
			return $this;
		}

		if(!$this->removeShipments())
		{
			throw new BuildingException();
		}

		$shipmentCollection = $this->order->getShipmentCollection();

		foreach($this->formData["SHIPMENT"] as $item)
		{
			$shipmentId = intval($item['ID'] ?? 0);
			$isNew = ($shipmentId <= 0);
			$deliveryService = null;
			$storeId = null;

			if (!isset($item['DEDUCTED']) || $item['DEDUCTED'] !== 'Y')
			{
				$item['DEDUCTED'] = 'N';
			}

			$extraServices =
				isset($item['EXTRA_SERVICES']) && is_array($item['EXTRA_SERVICES'])
					? $item['EXTRA_SERVICES']
					: []
			;

			$settableShipmentFields = $this->getSettableShipmentFields();
			if (!empty($settableShipmentFields))
			{
				//for backward compatibility
				$product = $item['PRODUCT'] ?? null;
				$storeId = (int)($item['DELIVERY_STORE_ID'] ?? 0);
				$item = array_intersect_key($item, array_flip($settableShipmentFields));
				if ($product !== null)
				{
					$item['PRODUCT'] = $product;
				}
				unset($product);
			}

			if($isNew)
			{
				$shipment = $shipmentCollection->createItem();
			}
			else
			{
				$shipment = $shipmentCollection->getItemById($shipmentId);

				if(!$shipment)
				{
					$this->errorsContainer->addError(new Error(Loc::getMessage("SALE_HLP_ORDERBUILDER_SHIPMENT_NOT_FOUND")." - ".$shipmentId));
					continue;
				}
			}

			$defaultFields = $shipment->getFieldValues();

			/** @var \Bitrix\Sale\BasketItem $product */
			$systemShipment = $shipmentCollection->getSystemShipment();
			$systemShipmentItemCollection = $systemShipment->getShipmentItemCollection();
			//We suggest that if  products is null - ShipmentBasket not loaded yet, if array ShipmentBasket loaded, but empty.
			$products = null;

			if(
				!isset($item['PRODUCT'])
				&& $shipment->getId() <= 0
			)
			{
				$products = array();
				$basket = $this->order->getBasket();

				if($basket)
				{
					$basketItems = $basket->getBasketItems();
					foreach($basketItems as $product)
					{
						$systemShipmentItem = $systemShipmentItemCollection->getItemByBasketCode($product->getBasketCode());

						if($product->isBundleChild() || !$systemShipmentItem || $systemShipmentItem->getQuantity() <= 0)
							continue;

						$products[] = array(
							'AMOUNT' => $systemShipmentItem->getQuantity(),
							'BASKET_CODE' => $product->getBasketCode(),
						);
					}
				}
			}
			elseif (isset($item['PRODUCT']) && is_array($item['PRODUCT']))
			{
				$products = $item['PRODUCT'];
			}

			if($item['DEDUCTED'] == 'Y' && $products !== null)
			{
				$basketResult = $this->buildShipmentBasket($shipment, $products);

				if(!$basketResult->isSuccess())
				{
					$this->errorsContainer->addErrors($basketResult->getErrors());
				}
			}

			$shipmentFields = array(
				'COMPANY_ID' => (isset($item['COMPANY_ID']) && intval($item['COMPANY_ID']) > 0) ? intval($item['COMPANY_ID']) : 0,
				'DEDUCTED' => $item['DEDUCTED'] ?? 'N',
				'DELIVERY_DOC_NUM' => $item['DELIVERY_DOC_NUM'] ?? '',
				'TRACKING_NUMBER' => $item['TRACKING_NUMBER'] ?? '',
				'CURRENCY' => $this->order->getCurrency(),
				'COMMENTS' => $item['COMMENTS'] ?? '',
			);

			if (!empty($item['IS_REALIZATION']))
			{
				$shipmentFields['IS_REALIZATION'] = $item['IS_REALIZATION'];
			}

			if (!empty($item['ACCOUNT_NUMBER']))
			{
				$shipmentFields['ACCOUNT_NUMBER'] = $item['ACCOUNT_NUMBER'];
			}

			if (!empty($item['XML_ID']))
			{
				$shipmentFields['XML_ID'] = $item['XML_ID'];
			}

			$statusId = $this->prepareFieldsStatusId($isNew, $item, $defaultFields);
			if ($statusId !== '')
			{
				$shipmentFields['STATUS_ID'] = $statusId;
			}

			if (empty($item['COMPANY_ID']))
			{
				$shipmentFields['COMPANY_ID'] = $this->order->getField('COMPANY_ID');
			}

			if (empty($item['RESPONSIBLE_ID']))
			{
				$shipmentFields['RESPONSIBLE_ID'] = $this->order->getField('RESPONSIBLE_ID');
				$shipmentFields['EMP_RESPONSIBLE_ID'] = $this->getCurrentUserId();
			}

			$deliveryId = 0;
			if (isset($item['PROFILE_ID']) && (int)$item['PROFILE_ID'] > 0)
			{
				$deliveryId = (int)$item['PROFILE_ID'];
			}
			elseif (isset($item['DELIVERY_ID']))
			{
				$deliveryId = (int)$item['DELIVERY_ID'];
			}
			elseif ($shipment->getField('DELIVERY_ID'))
			{
				$deliveryId = $shipment->getField('DELIVERY_ID');
			}

			$shipmentFields['DELIVERY_ID'] = $deliveryId;

			$dateFields = ['DELIVERY_DOC_DATE', 'DATE_DEDUCTED', 'DATE_MARKED', 'DATE_CANCELED', 'DATE_RESPONSIBLE_ID'];

			foreach($dateFields as $fieldName)
			{
				if(isset($item[$fieldName]))
				{
					if (is_string($item[$fieldName]))
					{
						try
						{
							$shipmentFields[$fieldName] = new DateTime($item[$fieldName]);
						}
						catch (ObjectException $exception)
						{
							$this->errorsContainer->addError(new Error('Wrong field "'.$fieldName.'"'));
						}
					}
					elseif ($item[$fieldName] instanceof Date)
					{
						$shipmentFields[$fieldName] = $item[$fieldName];
					}
				}
			}

			try
			{
				if($deliveryService = Delivery\Services\Manager::getObjectById($shipmentFields['DELIVERY_ID']))
				{
					if($deliveryService->isProfile())
					{
						$shipmentFields['DELIVERY_NAME'] = $deliveryService->getNameWithParent();
					}
					else
					{
						$shipmentFields['DELIVERY_NAME'] = $deliveryService->getName();
					}
				}
			}
			catch (ArgumentNullException $e)
			{
				$this->errorsContainer->addError(new Error(Loc::getMessage('SALE_HLP_ORDERBUILDER_DELIVERY_NOT_FOUND'), 'OB_DELIVERY_NOT_FOUND'));
				return $this;
			}

			$responsibleId = $shipment->getField('RESPONSIBLE_ID');

			if (($item['RESPONSIBLE_ID'] ?? null) !== $responsibleId || empty($responsibleId))
			{
				if (isset($item['RESPONSIBLE_ID']))
				{
					$shipmentFields['RESPONSIBLE_ID'] = $item['RESPONSIBLE_ID'];
				}
				else
				{
					$shipmentFields['RESPONSIBLE_ID'] = $this->order->getField('RESPONSIBLE_ID');
				}

				if (!empty($shipmentFields['RESPONSIBLE_ID']))
				{
					$shipmentFields['EMP_RESPONSIBLE_ID'] = $this->getCurrentUserId();
				}
			}

			if($extraServices)
			{
				$shipment->setExtraServices($extraServices);
			}

			$setFieldsResult = $shipment->setFields($shipmentFields);

			if(!$setFieldsResult->isSuccess())
			{
				$this->errorsContainer->addErrors($setFieldsResult->getErrors());
			}

			// region Properties
			if (isset($item['PROPERTIES']) && is_array($item['PROPERTIES']))
			{
				/** @var PropertyValueCollection $propCollection */
				$propCollection = $shipment->getPropertyCollection();
				$res = $propCollection->setValuesFromPost($item, []);

				if (!$res->isSuccess())
				{
					foreach ($res->getErrors() as $error)
					{
						$this->getErrorsContainer()->addError(
							new Main\Error($error->getMessage(), $error->getCode(), 'SHIPMENT_PROPERTIES')
						);
					}
				}

				/** @var \Bitrix\Sale\PropertyValue $propValue */
				foreach ($propCollection as $propValue)
				{
					if ($propValue->isUtil())
					{
						continue;
					}

					$property = $propValue->getProperty();
					$relatedDeliveryIds = (isset($property['RELATION']) && is_array($property['RELATION']))
						? array_column(
							array_filter(
								$property['RELATION'],
								function ($item)
								{
									return $item['ENTITY_TYPE'] === 'D';
								}
							),
							'ENTITY_ID'
						)
						: [];

					if (
						!empty($relatedDeliveryIds)
						&& !in_array($shipment->getField('DELIVERY_ID'), $relatedDeliveryIds)
					)
					{
						continue;
					}

					$res = $propValue->verify();
					if (!$res->isSuccess())
					{
						foreach ($res->getErrors() as $error)
						{
							$this->getErrorsContainer()->addError(
								new Main\Error($error->getMessage(), $propValue->getPropertyId(), 'SHIPMENT_PROPERTIES')
							);
						}
					}

					$res = $propValue->checkRequiredValue($propValue->getPropertyId(), $propValue->getValue());
					if (!$res->isSuccess())
					{
						foreach ($res->getErrors() as $error)
						{
							$this->getErrorsContainer()->addError(
								new Main\Error($error->getMessage(), $propValue->getPropertyId(), 'SHIPMENT_PROPERTIES')
							);
						}
					}
				}
			}
			// endregion

			if ($storeId)
			{
				$shipment->setStoreId($storeId);
			}

			if($item['DEDUCTED'] == 'N' && $products !== null)
			{
				$basketResult = $this->buildShipmentBasket($shipment, $products);

				if(!$basketResult->isSuccess())
				{
					$this->errorsContainer->addErrors($basketResult->getErrors());
				}
			}

			$isCustomPrice = false;
			if (isset($item['CUSTOM_PRICE_DELIVERY']))
			{
				$isCustomPrice = $item['CUSTOM_PRICE_DELIVERY'] === 'Y';
			}

			$fields = array(
				'CUSTOM_PRICE_DELIVERY' => $isCustomPrice ? 'Y' : 'N',
				'PRICE_DELIVERY' => (float)str_replace(',', '.', $item['PRICE_DELIVERY'] ?? 0),
			);

			if (isset($item['ALLOW_DELIVERY']))
			{
				$fields['ALLOW_DELIVERY'] = $item['ALLOW_DELIVERY'] === 'Y' ? 'Y' : 'N';
			}

			if (isset($item['BASE_PRICE_DELIVERY']))
			{
				$fields['BASE_PRICE_DELIVERY'] = (float)str_replace(',', '.', $item['BASE_PRICE_DELIVERY']);
			}

			$shipment = $this->delegate->setShipmentPriceFields($shipment, $fields);

			if($deliveryService && !empty($item['ADDITIONAL']))
			{
				$modifiedShipment = $deliveryService->processAdditionalInfoShipmentEdit($shipment, $item['ADDITIONAL']);

				$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);
				if ($modifiedShipment && get_class($modifiedShipment) == $registry->getShipmentClassName())
				{
					$shipment = $modifiedShipment;
				}
			}
		}

		return $this;
	}

	protected function removeShipmentItems(\Bitrix\Sale\Shipment $shipment, $products, $idsFromForm)
	{
		$result = new Result();

		$shipmentItemCollection = $shipment->getShipmentItemCollection();

		/** @var \Bitrix\Sale\ShipmentItem $shipmentItem */
		foreach ($shipmentItemCollection as $shipmentItem)
		{
			if (!array_key_exists($shipmentItem->getBasketCode(), $idsFromForm))
			{
				/** @var Result $r */
				$r = $shipmentItem->delete();
				if (!$r->isSuccess())
				{
					$result->addErrors($r->getErrors());
				}
			}

			$shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
			if ($shipmentItemStoreCollection)
			{
				/** @var \Bitrix\Sale\ShipmentItemStore $shipmentItemStore */
				foreach ($shipmentItemStoreCollection as $shipmentItemStore)
				{
					$shipmentItemId = $shipmentItemStore->getId();
					if (!isset($idsFromForm[$shipmentItem->getBasketCode()]['BARCODE_IDS'][$shipmentItemId]))
					{
						$delResult = $shipmentItemStore->delete();
						if (!$delResult->isSuccess())
						{
							$result->addErrors($delResult->getErrors());
						}
					}
				}
			}
		}

		return $result;
	}

	/**
	 * @param Shipment $shipment
	 * @param array $shipmentBasket
	 * @return Result
	 * @throws ArgumentNullException
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\ArgumentOutOfRangeException
	 * @throws \Bitrix\Main\NotSupportedException
	 * @throws \Bitrix\Main\ObjectNotFoundException
	 * @throws \Bitrix\Main\SystemException
	 * @throws \Exception
	 */
	public function buildShipmentBasket(&$shipment, $shipmentBasket)
	{
		/**@var \Bitrix\Sale\Shipment $shipment */
		$result = new Result();
		$shippingItems = array();
		$idsFromForm = array();
		$basket = $this->order->getBasket();
		$shipmentItemCollection = $shipment->getShipmentItemCollection();
		$useStoreControl = Configuration::useStoreControl();

		if(is_array($shipmentBasket))
		{
			// PREPARE DATA FOR SET_FIELDS
			foreach ($shipmentBasket as $items)
			{
				$items['QUANTITY'] = floatval(str_replace(',', '.', $items['QUANTITY']));
				$items['AMOUNT'] = floatval(str_replace(',', '.', $items['AMOUNT']));

				$r = $this->prepareDataForSetFields($shipment, $items);
				if($r->isSuccess())
				{
					$items = $r->getData()[0];
				}
				else
				{
					$result->addErrors($r->getErrors());
					return $result;
				}

				if (isset($items['BASKET_ID']) && !BasketBuilder::isBasketItemNew($items['BASKET_ID']))
				{
					if (!$basketItem = $basket->getItemById($items['BASKET_ID']))
					{
						$result->addError( new Error(
								Loc::getMessage('SALE_ORDER_SHIPMENT_BASKET_BASKET_ITEM_NOT_FOUND',  array(
									'#BASKET_ITEM_ID#' => $items['BASKET_ID'],
								)),
								'PROVIDER_UNRESERVED_SHIPMENT_ITEM_WRONG_BASKET_ITEM')
						);
						return $result;
					}
					/** @var \Bitrix\Sale\BasketItem $basketItem */
					$basketCode = $basketItem->getBasketCode();
				}
				else
				{
					$basketCode = $items['BASKET_CODE'];
					if(!$basketItem = $basket->getItemByBasketCode($basketCode))
					{
						$result->addError( new Error(
								Loc::getMessage('SALE_ORDER_SHIPMENT_BASKET_BASKET_ITEM_NOT_FOUND',  array(
									'#BASKET_ITEM_ID#' => $basketCode,
								)),
								'PROVIDER_UNRESERVED_SHIPMENT_ITEM_WRONG_BASKET_ITEM')
						);
						return $result;
					}
				}

				$isSupportedMarkingCode = false;
				if (isset($items['IS_SUPPORTED_MARKING_CODE']))
				{
					$isSupportedMarkingCode = $items['IS_SUPPORTED_MARKING_CODE'] === 'Y';
				}

				$tmp = [
					'BASKET_CODE' => $basketCode,
					'AMOUNT' => $items['AMOUNT'] ?? 0,
					'ORDER_DELIVERY_BASKET_ID' => $items['ORDER_DELIVERY_BASKET_ID'] ?? 0,
					'IS_SUPPORTED_MARKING_CODE' => $isSupportedMarkingCode ? 'Y' : 'N',
				];
				if (array_key_exists('XML_ID', $items))
				{
					$tmp['XML_ID'] = $items['XML_ID'];
				}
				$idsFromForm[$basketCode] = array();

				if (
					isset($items['BARCODE_INFO'])
					&& $items['BARCODE_INFO']
					&& ($useStoreControl || $isSupportedMarkingCode)
				)
				{
					foreach ($items['BARCODE_INFO'] as $item)
					{
						if (!$basketItem->isReservableItem())
						{
							$shippingItems[] = $tmp;
							continue;
						}

						$barcodeQuantity = ($basketItem->isBarcodeMulti() || $basketItem->isSupportedMarkingCode()) ? 1 : $item['QUANTITY'];
						$barcodeStoreId = $item['STORE_ID'];

						$tmp['BARCODE'] = array(
							'ORDER_DELIVERY_BASKET_ID' => $items['ORDER_DELIVERY_BASKET_ID'] ?? 0,
							'STORE_ID' => $barcodeStoreId,
							'QUANTITY' => $barcodeQuantity,
						);

						$tmp['BARCODE_INFO'] = [
							$item['STORE_ID'] => [
								'STORE_ID' => (int)$barcodeStoreId,
								'QUANTITY' => (float)$barcodeQuantity,
							],
						];

						$barcodeCount = 0;
						if ($item['BARCODE'])
						{
							foreach ($item['BARCODE'] as $barcode)
							{
								$barcode['ID'] = (int)($barcode['ID'] ?? 0);

								$tmp['BARCODE_INFO'][$barcodeStoreId]['BARCODE'] = [$barcode];

								if (isset($barcode['MARKING_CODE']))
								{
									$barcode['MARKING_CODE'] = (string)$barcode['MARKING_CODE'];
								}
								else
								{
									$barcode['MARKING_CODE'] = '';
								}

								$idsFromForm[$basketCode]['BARCODE_IDS'][$barcode['ID']] = true;

								if ($barcode['ID'] > 0)
								{
									$tmp['BARCODE']['ID'] = $barcode['ID'];
								}
								else
								{
									unset($tmp['BARCODE']['ID']);
								}

								$tmp['BARCODE']['BARCODE'] = (string)$barcode['VALUE'];
								$tmp['BARCODE']['MARKING_CODE'] = $barcode['MARKING_CODE'];

								$shippingItems[] = $tmp;
								$barcodeCount++;
							}
						}
						elseif (!$basketItem->isBarcodeMulti() && !$basketItem->isSupportedMarkingCode())
						{
							$shippingItems[] = $tmp;
							continue;
						}


						if ($basketItem->isBarcodeMulti() || $basketItem->isSupportedMarkingCode())
						{
							while ($barcodeCount < $item['QUANTITY'])
							{
								unset($tmp['BARCODE']['ID']);
								$tmp['BARCODE']['BARCODE'] = '';
								$tmp['BARCODE']['MARKING_CODE'] = '';
								$shippingItems[] = $tmp;
								$barcodeCount++;
							}
						}
					}
				}
				else
				{
					$shippingItems[] = $tmp;
				}
			}
		}

		// DELETE FROM COLLECTION
		$r = $this->removeShipmentItems($shipment, $shipmentBasket, $idsFromForm);
		if(!$r->isSuccess())
			$result->addErrors($r->getErrors());

		$isStartField = $shipmentItemCollection->isStartField();

		// SET DATA
		foreach ($shippingItems as $shippingItem)
		{
			if ((int)$shippingItem['ORDER_DELIVERY_BASKET_ID'] <= 0)
			{
				$basketCode = $shippingItem['BASKET_CODE'];
				/** @var \Bitrix\Sale\Order $this->order */
				$basketItem = $this->order->getBasket()->getItemByBasketCode($basketCode);

				/** @var \Bitrix\Sale\BasketItem $basketItem */
				$shipmentItem = $shipmentItemCollection->createItem($basketItem);

				if ($shipmentItem === null)
				{
					$result->addError(
						new Error(
							Loc::getMessage('SALE_ORDER_SHIPMENT_BASKET_ERROR_ALREADY_SHIPPED')
						)
					);
					return $result;
				}

				unset($shippingItem['BARCODE']['ORDER_DELIVERY_BASKET_ID']);
			}
			else
			{
				$shipmentItem = $shipmentItemCollection->getItemById($shippingItem['ORDER_DELIVERY_BASKET_ID']);

				if($shipmentItem)
				{
					$basketItem = $shipmentItem->getBasketItem();
				}
				else //It's a possible case when we are creating new shipment.
				{
					/** @var \Bitrix\Crm\Order\Shipment $systemShipment */
					$systemShipment = $shipment->getCollection()->getSystemShipment();
					/** @var \Bitrix\Crm\Order\ShipmentItemCollection $systemShipmentItemCollection */
					$systemShipmentItemCollection = $systemShipment->getShipmentItemCollection();

					$shipmentItem = $systemShipmentItemCollection->getItemById($shippingItem['ORDER_DELIVERY_BASKET_ID']);

					if($shipmentItem)
					{
						$basketItem = $shipmentItem->getBasketItem();
						$shipmentItem = $shipmentItemCollection->createItem($basketItem);
						$shipmentItem->setField('QUANTITY', $shipmentItem->getField('QUANTITY'));
					}
					else
					{
						$result->addError(
							new Error(
								Loc::getMessage('SALE_HLP_ORDERBUILDER_SHIPMENT_ITEM_ERROR',[
									'#ID#' => $shippingItem['ORDER_DELIVERY_BASKET_ID'],
								])
							)
						);

						continue;
					}
				}
			}

			if ($shippingItem['AMOUNT'] <= 0)
			{
				$result->addError(
					new Error(
						Loc::getMessage('SALE_ORDER_SHIPMENT_BASKET_ERROR_QUANTITY', array('#BASKET_ITEM#' => $basketItem->getField('NAME'))),
						'BASKET_ITEM_'.$basketItem->getBasketCode()
					)
				);
				continue;
			}

			$r = $this->modifyQuantityShipmentItem($shipmentItem, $shippingItem);
			if(!$r->isSuccess())
				$result->addErrors($r->getErrors());

			if (array_key_exists('XML_ID', $shippingItem))
			{
				$setFieldResult = $shipmentItem->setField('XML_ID', $shippingItem['XML_ID']);
				if (!$setFieldResult->isSuccess())
				{
					$result->addErrors($setFieldResult->getErrors());
				}
			}
		}

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

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

		return $result;
	}

	protected function prepareDataForSetFields(\Bitrix\Sale\Shipment $shipment, $items)
	{
		$result = new Result();
		return $result->setData([$items]);
	}

	protected function modifyQuantityShipmentItem(ShipmentItem $shipmentItem, array $params)
	{
		$result = new Result();
		if ($shipmentItem->getQuantity() < $params['AMOUNT'])
		{
			$this->order->setMathActionOnly(true);
			$setFieldResult = $shipmentItem->setField('QUANTITY', $params['AMOUNT']);
			$this->order->setMathActionOnly(false);

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

		$r = $this->setBarcodeShipmentItem($shipmentItem, $params);

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

		$setFieldResult = $shipmentItem->setField('QUANTITY', $params['AMOUNT']);

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

		return $result;
	}

	protected function setBarcodeShipmentItem(ShipmentItem $shipmentItem, array $params)
	{
		$result = new Result();
		$basketItem = $shipmentItem->getBasketItem();

		$useStoreControl = Configuration::useStoreControl();

		if (
			!empty($params['BARCODE'])
			&& ($useStoreControl || $params['IS_SUPPORTED_MARKING_CODE'] === 'Y' )
			&& $basketItem->isReservableItem()
		)
		{
			$barcode = $params['BARCODE'];

			/** @var \Bitrix\Sale\ShipmentItemStoreCollection $shipmentItemStoreCollection */
			$shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
			if ($shipmentItemStoreCollection)
			{
				if (!$basketItem->isBarcodeMulti() && !$basketItem->isSupportedMarkingCode())
				{
					/** @var Result $r */
					$r = $shipmentItemStoreCollection->setBarcodeQuantityFromArray($params);
					if (!$r->isSuccess())
					{
						$result->addErrors($r->getErrors());
					}
				}

				if (isset($barcode['ID']) && intval($barcode['ID']) > 0)
				{
					/** @var \Bitrix\Sale\ShipmentItemStore $shipmentItemStore */
					if ($shipmentItemStore = $shipmentItemStoreCollection->getItemById($barcode['ID']))
					{
						unset($barcode['ID']);
						$setFieldResult = $shipmentItemStore->setFields($barcode);

						if (!$setFieldResult->isSuccess())
						{
							$result->addErrors($setFieldResult->getErrors());
						}
					}
				}
				else
				{
					$shipmentItemStore = $shipmentItemStoreCollection->createItem($basketItem);
					$setFieldResult = $shipmentItemStore->setFields($barcode);
					if (!$setFieldResult->isSuccess())
					{
						$result->addErrors($setFieldResult->getErrors());
					}
				}
			}
		}

		return $result;
	}

	protected function createEmptyPayment()
	{
		$innerPaySystem = PaySystem\Manager::getObjectById(PaySystem\Manager::getInnerPaySystemId());

		$paymentCollection = $this->order->getPaymentCollection();
		$payment = $paymentCollection->createItem($innerPaySystem);
		$payment->setField('SUM', $this->order->getPrice());

		return $payment;
	}

	protected function removePayments()
	{
		if($this->getSettingsContainer()->getItemValue('deletePaymentIfNotExists'))
		{
			$paymentCollection = $this->order->getPaymentCollection();

			$paymentIds = [];
			foreach($this->formData["PAYMENT"] as $paymentData)
			{
				if(!isset($paymentData['ID']))
					continue;

				$payment = $paymentCollection->getItemById($paymentData['ID']);

				if ($payment == null)
					continue;

				$paymentIds[] = $payment->getId();
			}

			foreach ($paymentCollection as $payment)
			{
				if(!in_array($payment->getId(), $paymentIds))
				{
					$r = $payment->delete();
					if (!$r->isSuccess())
					{
						$this->errorsContainer->addErrors($r->getErrors());
						return false;
					}
				}
			}
		}
		return true;
	}

	/**
	 * @return bool
	 */
	protected function isEmptyPaymentData(): bool
	{
		return empty($this->formData["PAYMENT"]) || !is_array($this->formData["PAYMENT"]);
	}

	/**
	 * @return bool
	 */
	protected function needCreateDefaultPayment(): bool
	{
		return $this->getSettingsContainer()->getItemValue('createDefaultPaymentIfNeed');
	}

	public function buildPayments()
	{
		$isEmptyPaymentData = $this->isEmptyPaymentData();
		if ($isEmptyPaymentData)
		{
			$this->formData['PAYMENT'] = [];
		}

		if ($isEmptyPaymentData && !$this->needCreateDefaultPayment())
		{
			return $this;
		}

		if($isEmptyPaymentData && $this->getOrder()->isNew())
		{
			$this->createEmptyPayment();
			return $this;
		}

		if(!$this->removePayments())
		{
			$this->errorsContainer->addError(new Error('Payments remove - error'));
			throw new BuildingException();
		}

		$paymentCollection = $this->order->getPaymentCollection();

		foreach($this->formData["PAYMENT"] as $paymentData)
		{
			$paymentId = (int)($paymentData['ID'] ?? 0);
			$isNew = ($paymentId <= 0);
			$hasError = false;
			$products = $paymentData['PRODUCT'] ?? [];

			$settablePaymentFields = $this->getSettablePaymentFields();

			if(count($settablePaymentFields)>0)//for backward compatibility
				$paymentData = array_intersect_key($paymentData, array_flip($settablePaymentFields));

			/** @var \Bitrix\Sale\Payment $paymentItem */
			if($isNew)
			{
				$paymentItem = $paymentCollection->createItem();
				if (isset($paymentData['CURRENCY']) && !empty($paymentData['CURRENCY']) && $paymentData['CURRENCY'] !== $this->order->getCurrency())
				{
					$paymentData["SUM"] = \CCurrencyRates::ConvertCurrency($paymentData["SUM"], $paymentData["CURRENCY"], $this->order->getCurrency());
					$paymentData['CURRENCY'] = $this->order->getCurrency();
				}
			}
			else
			{
				$paymentItem = $paymentCollection->getItemById($paymentId);

				if(!$paymentItem)
				{
					$this->errorsContainer->addError(new Error(Loc::getMessage("SALE_HLP_ORDERBUILDER_PAYMENT_NOT_FOUND")." - ".$paymentId));
					continue;
				}
			}

			$isReturn = (isset($paymentData['IS_RETURN']) && ($paymentData['IS_RETURN'] == 'Y' || $paymentData['IS_RETURN'] == 'P'));
			$psService = null;

			if((int)$paymentData['PAY_SYSTEM_ID'] > 0)
			{
				$psService = PaySystem\Manager::getObjectById((int)$paymentData['PAY_SYSTEM_ID']);

				$paymentData['PAY_SYSTEM_NAME'] = ($psService) ? $psService->getField('NAME') : '';
			}

			if (isset($paymentData['COMPANY_ID']))
			{
				$paymentData['COMPANY_ID'] = (int)$paymentData['COMPANY_ID'];
			}

			if (isset($paymentData['PAID']))
			{
				$paymentFields['PAID'] = ($paymentData['PAID'] === 'Y') ? 'Y' : 'N';
				unset($paymentData['PAID']);
			}

			if ($isNew)
			{
				if(empty($paymentData['COMPANY_ID']))
				{
					$paymentData['COMPANY_ID'] = $this->order->getField('COMPANY_ID');
				}

				if(empty($paymentData['RESPONSIBLE_ID']))
				{
					$paymentData['RESPONSIBLE_ID'] = $this->order->getField('RESPONSIBLE_ID');
					$paymentData['EMP_RESPONSIBLE_ID'] = $this->getCurrentUserId();
				}
			}

			$dateFields = ['DATE_PAID', 'DATE_PAY_BEFORE', 'DATE_BILL', 'PAY_RETURN_DATE', 'PAY_VOUCHER_DATE'];

			foreach($dateFields as $fieldName)
			{
				if(isset($paymentData[$fieldName]) && is_string($paymentData[$fieldName]))
				{
					try
					{
						$paymentData[$fieldName] = new Date($paymentData[$fieldName]);
					}
					catch (ObjectException $exception)
					{
						$this->errorsContainer->addError(new Error('Wrong field "'.$fieldName.'"'));
						$hasError = true;
					}
				}
			}

			if($paymentItem->isPaid()
				&& isset($paymentData['SUM'])
				&& abs(floatval($paymentData['SUM']) - floatval($paymentItem->getSum())) > 0.001)
			{
				$this->errorsContainer->addError(new Error(Loc::getMessage("SALE_HLP_ORDERBUILDER_ERROR_PAYMENT_SUM")));
				$hasError = true;
			}

			/*
			 * We are editing an order. We have only one payment. So the payment fields are mostly in view mode.
			 * If we have changed the price of the order then the sum of the payment must be changed automaticaly by payment api earlier.
			 * But if the payment sum was received from the form we will erase the previous changes.
			 */
			if(isset($paymentData['SUM']))
			{
				$paymentData['SUM'] = (float)str_replace(',', '.', $paymentData['SUM']);
			}

			if(isset($paymentData['RESPONSIBLE_ID']))
			{
				$paymentData['RESPONSIBLE_ID'] = !empty($paymentData['RESPONSIBLE_ID']) ? $paymentData['RESPONSIBLE_ID'] : $this->getCurrentUserId();

				if($paymentData['RESPONSIBLE_ID'] != $paymentItem->getField('RESPONSIBLE_ID'))
				{
					if(!$isNew)
					{
						$paymentData['EMP_RESPONSIBLE_ID'] = $this->getCurrentUserId();
					}
				}
			}

			if(!$hasError)
			{
				if($paymentItem->isInner() && isset($paymentData['SUM']) && $paymentData['SUM'] === 0)
				{
					unset($paymentData['SUM']);
				}

				$setResult = $paymentItem->setFields($paymentData);

				if(!$setResult->isSuccess())
				{
					$this->errorsContainer->addErrors($setResult->getErrors());
				}

				if ($products)
				{
					$this->buildPayableItems($paymentItem, $products);
				}

				if($isReturn && $paymentData['IS_RETURN'])
				{
					$setResult = $paymentItem->setReturn($paymentData['IS_RETURN']);

					if(!$setResult->isSuccess())
					{
						$this->errorsContainer->addErrors($setResult->getErrors());
					}
				}

				if(!empty($paymentFields['PAID']))
				{
					$setResult = $paymentItem->setPaid($paymentFields['PAID']);

					if(!$setResult->isSuccess())
					{
						$this->errorsContainer->addErrors($setResult->getErrors());
					}
				}
			}
		}

		return $this;
	}

	/**
	 * @param Payment $payment
	 * @param array $payableItems
	 * @return Result
	 * @throws ArgumentNullException
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\NotImplementedException
	 * @throws Main\SystemException
	 */
	public function buildPayableItems(Payment $payment, array $payableItems): Result
	{
		$result = new Result();

		$basket = $this->order->getBasket();
		$payableItemCollection = $payment->getPayableItemCollection();

		foreach ($payableItems as $item)
		{
			$payableItem = null;

			if (isset($item['BASKET_CODE']))
			{
				/** @var BasketItem $basketItem */
				$basketItem = $basket->getItemByBasketCode($item['BASKET_CODE']);
				if ($basketItem)
				{
					$payableItem = $payableItemCollection->createItemByBasketItem($basketItem);
				}
			}
			elseif (isset($item['DELIVERY_ID']))
			{
				/** @var Shipment $shipment */
				foreach ($this->order->getShipmentCollection()->getNotSystemItems() as $shipment)
				{
					if (
						$shipment->getId() === 0
						&& (int)$item['DELIVERY_ID'] === $shipment->getDeliveryId()
					)
					{
						$payableItem = $payableItemCollection->createItemByShipment($shipment);
					}
				}
			}

			if ($payableItem === null)
			{
				continue;
			}

			$quantity = floatval(str_replace(',', '.', $item['QUANTITY']));

			$payableItem->setField('QUANTITY', $quantity);
		}

		return $result;
	}

	public function buildTradeBindings()
	{
		if(!isset($this->formData["TRADE_BINDINGS"]))
		{
			return $this;
		}

		if(!$this->removeTradeBindings())
		{
			return $this;
		}

		if(isset($this->formData["TRADE_BINDINGS"]) && count($this->formData["TRADE_BINDINGS"])>0)
		{
			$tradeBindingCollection = $this->order->getTradeBindingCollection();

			foreach($this->formData["TRADE_BINDINGS"] as $fields)
			{
				$tradingPlatformId = (int)($fields['TRADING_PLATFORM_ID'] ?? 0);
				if ($tradingPlatformId === 0)
				{
					continue;
				}

				$r = $this->tradingPlatformExists($tradingPlatformId);

				if($r->isSuccess())
				{
					$id = (int)($fields['ID'] ?? 0);
					$isNew = ($id <= 0);

					if($isNew)
					{
						$binding = $tradeBindingCollection->createItem();
					}
					else
					{
						$binding = $tradeBindingCollection->getItemById($id);

						if(!$binding)
						{
							$this->errorsContainer->addError(new Error('Can\'t find Trade Binding with id:"'.$id.'"', 'TRADE_BINDING_NOT_EXISTS'));
							continue;
						}
					}

					$fields = array_intersect_key($fields, array_flip(TradeBindingEntity::getAvailableFields()));

					$r = $binding->setFields($fields);
				}

				if(!$r->isSuccess())
					$this->errorsContainer->addErrors($r->getErrors());
			}
		}

		return $this;
	}

	protected function tradingPlatformExists($id)
	{
		$r = new Result();

		$platformFields = TradingPlatformTable::getById($id)->fetchAll();

		if (!isset($platformFields[0]))
		{
			$r->addError(new Error('tradingPlatform is not exists'));
		}

		return $r;
	}

	protected function removeTradeBindings()
	{
		if($this->getSettingsContainer()->getItemValue('deleteTradeBindingIfNotExists'))
		{
			$tradeBindingCollection = $this->order->getTradeBindingCollection();

			$internalIx = [];
			foreach($this->formData["TRADE_BINDINGS"] as $tradeBinding)
			{
				if(!isset($tradeBinding['ID']))
					continue;

				$binding = $tradeBindingCollection->getItemById($tradeBinding['ID']);

				if ($binding == null)
					continue;

				$internalIx[] = $binding->getId();
			}

			foreach ($tradeBindingCollection as $binding)
			{
				if(!in_array($binding->getId(), $internalIx))
				{
					$r = $binding->delete();
					if (!$r->isSuccess())
					{
						$this->errorsContainer->addErrors($r->getErrors());
						return false;
					}
				}
			}
		}

		return true;
	}

	public function finalActions()
	{
		if($this->isStartField)
		{
			$hasMeaningfulFields = $this->order->hasMeaningfulField();
			$r = $this->order->doFinalAction($hasMeaningfulFields);

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

		return $this;
	}

	public function getOrder()
	{
		return $this->order;
	}

	public function getSettingsContainer()
	{
		return $this->settingsContainer;
	}

	public function getErrorsContainer()
	{
		return $this->errorsContainer;
	}

	public function getFormData($fieldName = '')
	{
		if($fieldName <> '')
		{
			$result = $this->formData[$fieldName] ?? null;
		}
		else
		{
			$result = $this->formData;
		}

		return $result;
	}

	public function getBasketBuilder()
	{
		return $this->basketBuilder;
	}

	public static function getDefaultPersonType($siteId)
	{
		$personTypes = self::getBuyerTypesList($siteId);
		reset($personTypes);
		return key($personTypes);
	}

	public static function getBuyerTypesList($siteId)
	{
		static $result = array();

		if(!isset($result[$siteId]))
		{
			$result[$siteId] = array();

			$res = \Bitrix\Sale\Internals\PersonTypeTable::getList(array(
				'order' => array('SORT' => 'ASC', 'NAME' => 'ASC'),
				'filter' => array('=ACTIVE' => 'Y', '=PERSON_TYPE_SITE.SITE_ID' => $siteId),
			));

			while ($personType = $res->fetch())
			{
				$result[$siteId][$personType["ID"]] = htmlspecialcharsbx($personType["NAME"])." [".$personType["ID"]."]";
			}
		}

		return $result[$siteId];
	}

	public function getUserId()
	{
		$userId = (int)($this->formData["USER_ID"] ?? 0);
		if($userId > 0)
		{
			return $userId;
		}

		$userId = 0;

		$settingValue = (int)$this->getSettingsContainer()->getItemValue('createUserIfNeed');
		if ($settingValue === \Bitrix\Sale\Helpers\Order\Builder\SettingsContainer::SET_ANONYMOUS_USER)
		{
			$userId = \CSaleUser::GetAnonymousUserID();
		}
		elseif ($settingValue === \Bitrix\Sale\Helpers\Order\Builder\SettingsContainer::ALLOW_NEW_USER_CREATION)
		{
			$userId = $this->createUserFromFormData();
		}

		if ($userId > 0 && empty($this->formData["USER_ID"]))
		{
			$this->formData["USER_ID"] = $userId;
		}

		return $userId;
	}

	/**
	 * @return false|int|mixed|string|null
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\ArgumentOutOfRangeException
	 * @throws \Bitrix\Main\NotImplementedException
	 * @throws \Bitrix\Main\ObjectPropertyException
	 * @throws \Bitrix\Main\SystemException
	 */
	protected function createUserFromFormData()
	{
		$errors = [];
		$orderProps = $this->order->getPropertyCollection();

		if ($email = $orderProps->getUserEmail())
		{
			$email = $email->getValue();
		}

		if ($name = $orderProps->getPayerName())
		{
			$name = $name->getValue();
		}

		if ($phone = $orderProps->getPhone())
		{
			$phone = $phone->getValue();
		}

		if ($this->getSettingsContainer()->getItemValue('searchExistingUserOnCreating'))
		{
			$userId = $this->searchExistingUser($email, $phone);
		}

		if (!isset($userId))
		{
			$userId = $this->searchExistingUser($email, $phone);
		}

		if (!isset($userId))
		{
			$userId = \CSaleUser::DoAutoRegisterUser(
				$email,
				$name,
				$this->formData['SITE_ID'],
				$errors,
				[
					'PERSONAL_PHONE' => $phone,
					'PHONE_NUMBER' => $phone,
				]
			);

			if (!empty($errors))
			{
				foreach ($errors as $val)
				{
					$this->errorsContainer->addError(new Error($val['TEXT'], 0, 'USER'));
				}
			}
			else
			{
				// ToDo remove it? when to authorize buyer?
				global $USER;
				$USER->Authorize($userId);
			}
		}

		return $userId;
	}

	/**
	 * @param $email
	 * @param $phone
	 * @return int|null
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\ObjectPropertyException
	 * @throws \Bitrix\Main\SystemException
	 */
	private function searchExistingUser($email, $phone): ?int
	{
		$existingUserId = null;

		if (!empty($email))
		{
			$res = Main\UserTable::getRow([
				'filter' => [
					'=ACTIVE' => 'Y',
					'=EMAIL' => $email,
				],
				'select' => ['ID'],
			]);
			if (isset($res['ID']))
			{
				$existingUserId = (int)$res['ID'];
			}
		}

		if (!$existingUserId && !empty($phone))
		{
			$normalizedPhone = NormalizePhone($phone);
			$normalizedPhoneForRegistration = Main\UserPhoneAuthTable::normalizePhoneNumber($phone);

			if (!empty($normalizedPhone))
			{
				$res = Main\UserTable::getRow([
					'filter' => [
						'ACTIVE' => 'Y',
						[
							'LOGIC' => 'OR',
							'=PHONE_AUTH.PHONE_NUMBER' => $normalizedPhoneForRegistration,
							'=PERSONAL_PHONE' => $normalizedPhone,
							'=PERSONAL_MOBILE' => $normalizedPhone,
						],
					],
					'select' => ['ID'],
				]);
				if (isset($res['ID']))
				{
					$existingUserId = (int)$res['ID'];
				}
			}
		}

		return $existingUserId;
	}

	protected function getCurrentUserId(): ?int
	{
		global $USER;
		$currentUserId = null;
		if (isset($USER) && $USER instanceof \CUser)
		{
			$currentUserId = (int)$USER->GetID();
			if ($currentUserId <= 0)
			{
				$currentUserId = null;
			}
		}

		return $currentUserId;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit