• Модуль: sale
  • Путь к файлу: ~/bitrix/modules/sale/lib/helpers/order/builder/orderbuilder.php
  • Класс: BitrixSaleHelpersOrderBuilderOrderBuilder
  • Вызов: OrderBuilder::buildShipments
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();
	}

	global $USER;
	$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 BitrixSaleBasketItem $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'] = $USER->GetID();
		}

		$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 = DeliveryServicesManager::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'] != $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'] = $USER->getID();
			}
		}

		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 MainError($error->getMessage(), $error->getCode(), 'SHIPMENT_PROPERTIES')
					);
				}
			}

			/** @var BitrixSalePropertyValue $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 MainError($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 MainError($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;
}