• Модуль: catalogmobile
  • Путь к файлу: ~/bitrix/modules/catalogmobile/lib/Controller/StoreDocumentDetails.php
  • Класс: Bitrix\CatalogMobile\Controller\StoreDocumentDetails
  • Вызов: StoreDocumentDetails::updateDocumentProductRecords
private function updateDocumentProductRecords(int $documentId, array $products): void
{
	$isSuccess = true;

	$document = StoreDocumentTable::getList(['filter' => ['=ID' => $documentId]])->fetch();
	if (!$document)
	{
		return;
	}

	$existingElements = [];
	$existingElementsList = StoreDocumentElementTable::getList([
		'select' => ['*'],
		'filter' => ['=DOC_ID' => $documentId],
	]);
	while ($element = $existingElementsList->fetch())
	{
		$existingElements[$element['ID']] = $element;
	}

	/**
	 * Clean existing document barcodes
	 */
	$documentRecordIds = array_keys($existingElements);
	if (!empty($documentRecordIds))
	{
		$existingDocumentBarcodes = StoreDocumentBarcodeTable::getList([
			'select' => ['ID'],
			'filter' => ['DOC_ELEMENT_ID' => $documentRecordIds],
		]);
		while ($existingBarcode = $existingDocumentBarcodes->fetch())
		{
			CCatalogStoreDocsBarcode::delete($existingBarcode['ID']);
		}
	}

	/**
	 * Delete existing product elements
	 */
	$elementsToDelete = array_diff(
		array_column($existingElements, 'ID'),
		array_column($products, 'id')
	);
	foreach ($elementsToDelete as $elementToDelete)
	{
		$deleteResult = \CCatalogStoreDocsElement::delete($elementToDelete);
		if ($deleteResult !== true)
		{
			$isSuccess = false;
		}
	}

	/**
	 * Add / Update existing product elements
	 */
	foreach ($products as $productElement)
	{
		$productDto = new DocumentProductRecord($productElement);

		$price = $productDto->price ?? [];
		$pricePurchase = $price['purchase'] ?? [];
		$priceSell = $price['sell'] ?? [];

		$fields = [
			'DOC_ID' => $documentId,
			'ELEMENT_ID' => (int)$productDto->productId,
		];

		$skuEntity = null;
		if ($this->checkEditPurchasePriceRights())
		{
			$fields['PURCHASING_PRICE'] = isset($pricePurchase['amount']) ? (float)$pricePurchase['amount'] : null;
		}
		else if (isset($existingElements[(int)$productDto->id]))
		{
			$fields['PURCHASING_PRICE'] = (float)$existingElements[(int)$productDto->id]['PURCHASING_PRICE'];
		}
		else
		{
			$skuEntity ??= ServiceContainer::getRepositoryFacade()->loadVariation($productElement['productId']);
			$fields['PURCHASING_PRICE'] = $skuEntity ? $skuEntity->getField('PURCHASING_PRICE') : null;
		}

		if ($this->checkEditPriceRights())
		{
			$fields['BASE_PRICE'] = isset($priceSell['amount']) ? (float)$priceSell['amount'] : null;
		}
		else if (isset($existingElements[(int)$productDto->id]))
		{
			$fields['BASE_PRICE'] = (float)$existingElements[(int)$productDto->id]['BASE_PRICE'];
		}
		else
		{
			$skuEntity ??= ServiceContainer::getRepositoryFacade()->loadVariation($productElement['productId']);
			$basePriceEntity = $skuEntity->getPriceCollection()->findBasePrice();
			$fields['BASE_PRICE'] = $basePriceEntity ? $basePriceEntity->getPrice() : null;
		}

		$existingStoreTo = isset($existingElements[(int)$productDto->id]['STORE_TO'])
			? (int)$existingElements[(int)$productDto->id]['STORE_TO']
			: null;
		$hasAccessToExistingStoreTo = !$existingStoreTo || $this->checkStoreAccessRights($existingStoreTo);
		if ($hasAccessToExistingStoreTo)
		{
			$storeTo = isset($productDto->storeToId)
				? (int)$productDto->storeToId
				: null;
			$hasStoreToAccess = !$storeTo || $this->checkStoreAccessRights($storeTo);
			if (
				$hasStoreToAccess
				&& in_array(
					$document['DOC_TYPE'],
					[
						StoreDocumentTable::TYPE_ARRIVAL,
						StoreDocumentTable::TYPE_STORE_ADJUSTMENT,
						StoreDocumentTable::TYPE_MOVING,
					],
					true
				)
			)
			{
				$fields['STORE_TO'] = $storeTo;
				$fields['AMOUNT'] = (float)$productDto->amount;
			}
		}

		$existingStoreFrom = isset($existingElements[(int)$productDto->id]['STORE_FROM'])
			? (int)$existingElements[(int)$productDto->id]['STORE_FROM']
			: null;
		$hasAccessToExistingStoreFrom = !$existingStoreFrom || $this->checkStoreAccessRights($existingStoreFrom);
		if ($hasAccessToExistingStoreFrom)
		{
			$storeFrom = isset($productDto->storeFromId)
				? (int)$productDto->storeFromId
				: null;
			$hasStoreFromAccess = !$storeFrom || $this->checkStoreAccessRights($storeFrom);
			if (
				$hasStoreFromAccess
				&& in_array(
					$document['DOC_TYPE'],
					[
						StoreDocumentTable::TYPE_MOVING,
						StoreDocumentTable::TYPE_DEDUCT,
					],
					true
				)
			)
			{
				$fields['STORE_FROM'] = $storeFrom;
				$fields['AMOUNT'] = (float)$productDto->amount;
			}
		}

		if (isset($existingElements[$productDto->id]))
		{
			$documentRecordId = (int)$productDto->id;
			$saveResult = StoreDocumentElementTable::update($documentRecordId, $fields);
		}
		else
		{
			$saveResult = StoreDocumentElementTable::add($fields);
			$documentRecordId = $saveResult->getId();
		}

		if (!$saveResult->isSuccess())
		{
			$isSuccess = false;
		}

		if (!empty($productDto->barcode) && !empty($documentRecordId))
		{
			CCatalogStoreDocsBarcode::add([
				'BARCODE' => $productDto->barcode,
				'DOC_ELEMENT_ID' => $documentRecordId,
			]);
		}
	}

	if (!$isSuccess)
	{
		$this->addNonCriticalError(
			new Error(
				Loc::getMessage('MOBILE_CONTROLLER_CATALOG_DETAILS_ERROR_DOCUMENT_FILES_SAVE_ERROR')
			)
		);
	}

	/**
	 * Update document total
	 */
	$elementsList = StoreDocumentElementTable::getList([
		'select' => [
			'ID',
			'BASE_PRICE',
			'PURCHASING_PRICE',
			'AMOUNT',
		],
		'filter' => ['=DOC_ID' => $documentId],
	]);
	$documentTotal = 0.00;
	while ($element = $elementsList->fetch())
	{
		$documentTotal += PriceMaths::roundPrecision((float)$element['PURCHASING_PRICE']
			* (float)$element['AMOUNT']);
	}

	\CCatalogDocs::update($documentId, ['TOTAL' => $documentTotal]);
}