Your IP : 18.216.172.133


Current Path : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/sale/lib/exchange/entity/
Upload File :
Current File : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/sale/lib/exchange/entity/shipmentimport.php

<?php
namespace Bitrix\Sale\Exchange\Entity;

use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Sale;
use Bitrix\Sale\Internals;
use Bitrix\Sale\Exchange;
use Bitrix\Sale\Exchange\EntityCollisionType;
use Bitrix\Sale\Basket;
use Bitrix\Sale\Order;
use Bitrix\Sale\Shipment;
use Bitrix\Sale\Delivery\Services\Manager;

IncludeModuleLangFile(__FILE__);

/**
 * Class ShipmentImport
 * @package Bitrix\Sale\Exchange\Entity
 * @internal
 */
class ShipmentImport extends EntityImport
{
	protected static $currentSettingsStores = null;

	public function __construct($parentEntityContext = null)
    {
        parent::__construct($parentEntityContext);
    }

    /**
     * @return int
     */
    public function getOwnerTypeId()
    {
        return Exchange\EntityType::SHIPMENT;
    }

    /**
     * @param Internals\Entity $entity
     * @throws Main\ArgumentException
     */
    public function setEntity(Internals\Entity $entity)
    {
        if(!($entity instanceof Shipment))
            throw new Main\ArgumentException("Entity must be instanceof Shipment");

        $this->entity = $entity;
    }

    /**
     * @param array $fields
     * @return Sale\Result
     */
    protected function checkFields(array $fields)
    {
        $result = new Sale\Result();

        if(intval($fields['ORDER_ID'])<=0 &&
            !$this->isLoadedParentEntity()
        )
        {
            $result->addError(new Error('ORDER_ID is not defined',''));
        }

        return $result;
    }

	/**
	 * @return Main\Entity\AddResult|Main\Entity\UpdateResult|Sale\Result|mixed
	 */
	public function save()
    {
        /** @var Order $parentEntity */
        $parentEntity = $this->getParentEntity();
        return $parentEntity->save();
    }

	/**
	 * @param array $params
	 * @return Sale\Result
	 */
	public function add(array $params)
    {
		$result = new Sale\Result();

		if(!$this->isLoadedParentEntity())
		{
			$result->addError(new Error(GetMessage('SALE_EXCHANGE_ENTITY_SHIPMENT_ORDER_IS_NOT_LOADED_ERROR'),'ENTITY_SHIPMENT_ORDER_IS_NOT_LOADED_ERROR'));
			return $result;
		}

		$fields = $params['TRAITS'];
		$parentEntity = $this->getParentEntity();

        if(($shipmentService = Manager::getObjectById($fields['DELIVERY_ID'])) == null)
        {
			$result->addError(new Error(GetMessage('SALE_EXCHANGE_ENTITY_SHIPMENT_DELIVERY_SERVICE_IS_NOT_AVAILABLE_ERROR'),'DELIVERY_SERVICE_IS_NOT_AVAILABLE_ERROR'));
		}
		else
		{
			$shipmentCollection = $parentEntity->getShipmentCollection();
			$shipment = $shipmentCollection->createItem($shipmentService);

			$shipment->setField('DELIVERY_NAME', $shipmentService->getName());

			$basket = $parentEntity->getBasket();
			$result = $this->fillShipmentItems($shipment, $basket, $params);
			if(!$result->isSuccess())
			{
				return $result;
			}

			$result = $shipment->setFields($fields);

			if($result->isSuccess())
			{
				$this->setEntity($shipment);
			}
		}

        return $result;
    }

	/**
	 * @param array $params
	 * @return Sale\Result
	 */
	public function update(array $params)
    {
    	$result = new Sale\Result();

		if(!$this->isLoadedParentEntity())
		{
			$result->addError(new Error(GetMessage('SALE_EXCHANGE_ENTITY_SHIPMENT_ORDER_IS_NOT_LOADED_ERROR'),'ORDER_IS_NOT_LOADED_ERROR'));
			return $result;
		}

		/** @var Shipment $shipment */
        $shipment = $this->getEntity();

        $parentEntity = $this->getParentEntity();

        $criterion = $this->getCurrentCriterion($this->getEntity());

        $fields = $params['TRAITS'];
        if($criterion->equals($fields))
        {
            $basket = $parentEntity->getBasket();
            $result = $this->fillShipmentItems($shipment, $basket, $params);
            if(!$result->isSuccess())
            {
                return $result;
            }
        }

        $result = $shipment->setFields($fields);

        return $result;
    }

    /**
     * @param array|null $params
     * @return Sale\Result
     * @throws Main\ObjectNotFoundException
     */
    public function delete(array $params = null)
    {
        /** @var Shipment $entity */
        $entity = $this->getEntity();
        $result = $entity->delete();
        if($result->isSuccess())
        {
            //$this->setCollisions(EntityCollisionType::OrderShipmentDeleted, $this->getParentEntity());
        }
        else
        {
            $this->setCollisions(EntityCollisionType::OrderShipmentDeletedError, $this->getParentEntity(), implode(',', $result->getErrorMessages()));
        }

        return $result;
    }

    /**
     * @return string
     */
    protected function getExternalFieldName()
    {
        return 'EXTERNAL_DELIVERY';
    }

    /**
     * @param array $fields
	 * @return Sale\Result
     * @throws Main\ArgumentException
     * @throws Main\ArgumentNullException
     */
    public function load(array $fields)
    {
        $r = $this->checkFields($fields);
        if(!$r->isSuccess())
        {
            throw new Main\ArgumentException('ORDER_ID is not defined');
        }

        if(!$this->isLoadedParentEntity() && !empty($fields['ORDER_ID']))
        {
            $this->setParentEntity(Order::load($fields['ORDER_ID']));
        }

        if($this->isLoadedParentEntity())
        {
            $parentEntity = $this->getParentEntity();

            if(!empty($fields['ID']))
            {
                $shipment = $parentEntity->getShipmentCollection()->getItemById($fields['ID']);
            }

            /** @var Shipment $shipment*/
            if(!empty($shipment) && !$shipment->isSystem())
            {
                $this->setEntity($shipment);
            }
            else
            {
                $this->setExternal();
            }
        }
		return new Sale\Result();
    }

    /**
     * @param Order $order
     * @param Sale\BasketItem $basketItem
     * @return int
     * @throws Main\ObjectNotFoundException
     */
    private function getBasketItemQuantity(Order $order, Sale\BasketItem $basketItem)
    {
        $allQuantity = 0;
        /** @var Shipment $shipment */
        foreach ($order->getShipmentCollection() as $shipment)
        {
            if($shipment->isShipped())
            	continue;

            $allQuantity += $shipment->getBasketItemQuantity($basketItem);
        }

        return $allQuantity;
    }

    /**
     * @param Shipment $shipment
     * @param Basket $basket
     * @param array $params
     * @return Sale\Result
     * @throws Main\ObjectNotFoundException
     */
    private function fillShipmentItems(Shipment $shipment, Basket $basket, array $params)
    {
        $result = new Sale\Result();

        $order = $basket->getOrder();

        $fieldsBasketItems = $params['ITEMS'];

        if(is_array($fieldsBasketItems))
        {
            foreach($fieldsBasketItems as $items)
            {
                foreach($items as $productXML_ID => $item)
                {
                    if($productXML_ID == Exchange\ImportOneCBase::DELIVERY_SERVICE_XMLID)
                    	continue;

                	if($item['TYPE'] == Exchange\ImportBase::ITEM_ITEM)
                    {
                        if($basketItem = OrderImport::getBasketItemByItem($basket, $item))
                        {
                            $basketItemQuantity = $this->getBasketItemQuantity($order, $basketItem);

                            $shipmentItem = self::getShipmentItem($shipment, $basketItem);

                            $deltaQuantity = $item['QUANTITY'] - $shipmentItem->getQuantity();

                            if($deltaQuantity < 0)
                            {
                                $this->fillShipmentItem($shipmentItem, 0, abs($deltaQuantity));
                            }
                            elseif($deltaQuantity > 0)
                            {
                                if($basketItemQuantity >= $item['QUANTITY'])
                                {
                                    $systemShipment = $order->getShipmentCollection()->getSystemShipment();
                                    $systemBasketQuantity = $systemShipment->getBasketItemQuantity($basketItem);

                                    if($systemBasketQuantity >= $deltaQuantity)
                                    {
                                        $this->fillShipmentItem($shipmentItem, $item['QUANTITY'], $shipmentItem->getQuantity());
                                    }
                                    else
                                    {
                                        $needQuantity = $deltaQuantity - $systemBasketQuantity;

                                        $r = $this->synchronizeQuantityShipmentItems($basketItem, $needQuantity);
                                        if($r->isSuccess())
                                        {
                                            $this->fillShipmentItem($shipmentItem, $item['QUANTITY'], $shipmentItem->getQuantity());
                                        }
                                        else
                                        {
                                            $this->setCollisions(EntityCollisionType::ShipmentBasketItemsModifyError, $shipment);
                                        }
                                    }
                                }
                                else
                                {
                                    $this->setCollisions(EntityCollisionType::ShipmentBasketItemQuantityError, $shipment, $item['NAME']);
                                }
                            }
                        }
                        else
                        {
                            $this->setCollisions(EntityCollisionType::ShipmentBasketItemNotFound, $shipment);
                        }
                    }
                    else
					{
						$this->setCollisions(EntityCollisionType::OrderBasketItemTypeError, $shipment, $item['NAME']);
					}
                }
            }
        }
        return $result;
    }

    /**
     * @param Shipment $shipment
     * @param Sale\BasketItem $basketItem
     * @return Sale\ShipmentItem|null
     * @throws Main\ObjectNotFoundException
     */
    private static function getShipmentItem(Sale\Shipment $shipment, Sale\BasketItem $basketItem)
    {
        /** @var Sale\ShipmentItemCollection $shipmentItemCollection */
        if (!$shipmentItemCollection = $shipment->getShipmentItemCollection())
        {
            throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollection" not found');
        }

        $shipmentItem = $shipmentItemCollection->getItemByBasketCode($basketItem->getBasketCode());
        if (empty($shipmentItem))
        {
            $shipmentItem = $shipmentItemCollection->createItem($basketItem);
        }
        return $shipmentItem;
    }

    /**
     * @param Sale\ShipmentItem $shipmentItem
     * @param $value
     * @param $oldValue
     * @return Sale\Result
     */
    private function fillShipmentItem(Sale\ShipmentItem $shipmentItem, $value, $oldValue)
    {
        $result = new Sale\Result();

        $deltaQuantity = $value - $oldValue;

        if($shipmentItem->getQuantity() + $deltaQuantity == 0)
        {
            $r = $shipmentItem->delete();
        }
        else
        {
            $r = $shipmentItem->setField(
                "QUANTITY",
                $shipmentItem->getQuantity() + $deltaQuantity
            );
        }

        /** @var Sale\ShipmentItemCollection $shipmentItemCollection */
        $shipmentItemCollection = $shipmentItem->getCollection();

        /** @var Shipment $shipment */
        if (!$shipment = $shipmentItemCollection->getShipment())
        {
            if(!$r->isSuccess())
            {
                $result->addErrors($r->getErrors());
                $this->setCollisions(EntityCollisionType::OrderShipmentItemsModifyError, $shipment, implode(',', $r->getErrorMessages()));
            }
            else
            {
                $this->setCollisions(EntityCollisionType::OrderShipmentItemsModify, $shipment);
            }
        }

        return $result;
    }

    /**
     * Decrease total product quantity existing across all shipments by the specified value.
     * Difference between the required decrease of quantity of shipped product and quantity existing in the system shipment.
     * System shipment will specify the quantity required to remove the product from the cart or update the selected shipment
     * Pass the decrease value to system shipment.
     * Thus we decrease product quantity in the shipments and add it to the system shipment.
     * We can decrease quantity for the shipments containing the product except the current shipment if it was selected and other shipments containing the product and matching selection citeria (Exchange\IShipmentCriterion implementation).
     * If we decrease quantity relative to a specific shipment, we assume the quantity relocated to the system shipment will later be added to the selected shipment.
     * @param Sale\BasketItem $basketItem
     * @param $needQuantity
     * @return Sale\Result
     * @throws Main\ObjectNotFoundException
     * @internal
     */
    public function synchronizeQuantityShipmentItems(Sale\BasketItem $basketItem, $needQuantity)
    {
        $result = new Sale\Result();

        if(intval($needQuantity) <= 0)
        {
            return $result;
        }

        $entity = $this->getEntity();

        /** @var Sale\Order $order */
        $order = $this->getParentEntity();
        $shipmentCollection = $order->getShipmentCollection();

        /** @var Sale\Shipment $entity */
        foreach ($shipmentCollection as $shipment)
        {
            /** @var Sale\Shipment $shipment */
            if(!empty($entity) && $entity->getId() == $shipment->getId())
                continue;

            if($shipment->isShipped() || $shipment->isSystem())
				continue;

            $basketQuantity = $shipment->getBasketItemQuantity($basketItem);
            if(empty($basketQuantity))
                continue;

            $shipmentItem = self::getShipmentItem($shipment, $basketItem);

            if($basketQuantity >= $needQuantity)
            {
                $this->fillShipmentItem($shipmentItem, 0, $needQuantity);
                $needQuantity = 0;
            }
            else
            {
                $this->fillShipmentItem($shipmentItem, 0, $basketQuantity);
                $needQuantity -= $basketQuantity;
            }

            $this->setCollisions(EntityCollisionType::ShipmentBasketItemsModify, $shipment);

            if($needQuantity == 0)
                break;
        }

        if($needQuantity != 0)
            $result->addError(new Error(GetMessage('SALE_EXCHANGE_ENTITY_SHIPMENT_SYNCHRONIZE_QUANTITY_ERROR'), 'SYNCHRONIZE_QUANTITY_ERROR'));

        return $result;
    }

	/**
	 * @param $fields
	 * @return array
	 */
	static public function getFieldsDeliveryService($fields)
	{
		$result = array();
		foreach($fields["ITEMS"] as $items)
		{
			foreach($items as $item)
			{
				if($item['TYPE'] == Exchange\ImportBase::ITEM_SERVICE)
				{
					$result = $item;
					break 2;
				}
			}
		}
		return $result;
	}

    /**
     * @param $fields
     * @return array
     */
    public function prepareFieldsDeliveryService($fields)
    {
        $result = array();

        $item = self::getFieldsDeliveryService($fields);
        if(count($item)>0)
		{
			$result = array(
				"CUSTOM_PRICE_DELIVERY" => "Y",
				"BASE_PRICE_DELIVERY" => $item["PRICE"],
				"CURRENCY" => $this->settings->getCurrency()
			);
		}

        return $result;
    }

    /**
     * @param array $fields
     */
    public function refreshData(array $fields)
    {
        /** @var Sale\Shipment $entity */
        $entity = $this->getEntity();
        if(!empty($entity) && $entity->isShipped())
        {
            if($fields['DEDUCTED'] == 'N')
                $entity->setField('DEDUCTED', 'N');
        }
    }

    /**
     * @param Internals\Entity $shipment
     * @return int
     * @throws Main\ArgumentException
     */
    public static function resolveEntityTypeId(Internals\Entity $shipment)
    {
        if(!($shipment instanceof Shipment))
            throw new Main\ArgumentException("Entity must be instanceof Shipment");

        return Exchange\EntityType::SHIPMENT;
    }

	public function initFields()
	{
		$this->setFields(
			array(
				'TRAITS' => $this->getFieldsTraits(),
				'ITEMS' => $this->getFieldsItems(),
				'STORIES' => $this->getFieldsStories()
			)
		);
	}

	/**
	 * @return array
	 */
	protected function getFieldsItems()
	{
		$result = array();
		$shipment = $this->getEntity();
		if($shipment instanceof Shipment)
		{
			$order = $shipment->getParentOrder();
			/** @var Sale\BasketItem $basket */
			foreach ($order->getBasket() as $basket)
			{
				/** @var Sale\ShipmentItem $shipmentItem */
				$shipmentItem = $shipment->getShipmentItemCollection()
					->getItemByBasketCode($basket->getBasketCode());

				if($shipmentItem !== null)
				{
					$itemFields = $basket->getFieldValues();
					$itemFields['QUANTITY'] = $shipmentItem->getQuantity();

					$attributes = array();
					$attributeFields = OrderImport::getAttributesItem($basket);
					if(count($attributeFields)>0)
						$attributes['ATTRIBUTES'] = $attributeFields;

					$result[] = array_merge($itemFields, $attributes);
				}
			}
		}
		return $result;
	}

	/**
	 * @return array
	 * @internal
	 */
	protected function getFieldsStories()
	{
		$result = array();
		$entity = $this->getEntity();
		if($entity instanceof Shipment)
		{
			$shipmentItemCollection = $entity->getShipmentItemCollection();
			if($shipmentItemCollection->count()>0)
			{
				/** @var Sale\ShipmentItem $shipmentItem */
				foreach ($shipmentItemCollection as $shipmentItem)
				{
					$shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
					if ($shipmentItemStoreCollection->count()>0)
					{
						/** @var Sale\ShipmentItemStore $shipmentItemStore */
						foreach ($shipmentItemStoreCollection as $shipmentItemStore)
						{
							$result[] = array('ID'=>$shipmentItemStore->getStoreId());
						}
					}
				}
			}
		}
		return $result;
	}

	/**
	 * @param Sale\IBusinessValueProvider $entity
	 * @return Sale\Order
	 */
	static protected function getBusinessValueOrderProvider(\Bitrix\Sale\IBusinessValueProvider $entity)
	{
		if(!($entity instanceof Shipment))
			throw new Main\ArgumentException("entity must be instanceof Shipment");

		/** @var Sale\ShipmentCollection $collection */
		$collection = $entity->getCollection();

		return $collection->getOrder();
	}
}