58 $this->cacheProductProviderData = $this->builder->getSettingsContainer()->getItemValue(
'cacheProductProviderData');
63 $this->formData = $this->builder->getFormData();
64 $this->delegate = $this->
getDelegate($this->formData[
'ID']);
65 \Bitrix\Sale\ProviderBase::setUsingTrustData(
true);
83 return $this->builder->getSettingsContainer()->getItemValue(
'needUpdateNewProductPrice');
90 if((
float)$productData[
'QUANTITY'] <= 0)
95 "SALE_HLP_ORDERBUILDER_QUANTITY_ERROR",
96 [
'#PRODUCT_NAME#' => $productData[
'NAME']]
102 if((
int)$productData[
'PRICE'] < 0)
107 "SALE_HLP_ORDERBUILDER_PRICE_ERROR",
108 [
'#PRODUCT_NAME#' => $productData[
'NAME']]
119 foreach($this->formData[
"PRODUCT"] as $basketCode => $productData)
126 if(self::isBasketItemNew($basketCode))
128 $basketInternalId = intval(mb_substr($basketCode, 1));
130 if($basketInternalId > $this->maxBasketCodeIdx)
131 $this->maxBasketCodeIdx = $basketInternalId;
136 $this->needDataUpdate[] = $basketCode;
137 unset($this->formData[
"PRODUCT"][$basketCode][
"PROVIDER_DATA"]);
138 unset($this->formData[
"PRODUCT"][$basketCode][
"SET_ITEMS_DATA"]);
149 sortByColumn($this->formData[
"PRODUCT"], array(
"BASE_PRICE" => SORT_DESC,
"PRICE" => SORT_DESC),
'',
null,
true);
156 protected function getExistsItem($moduleId, $productId, array $properties = array())
158 return $this->
getBasket()->getExistsItem($moduleId, $productId, $properties);
161 public function removeDeletedItems()
163 $deleteBasketItemsIfNotExists = $this->builder->getSettingsContainer()->getItemValue(
'deleteBasketItemsIfNotExists');
164 $itemsBasketCodes = [];
166 foreach($this->formData[
"PRODUCT"] as $basketCode => $productData)
168 if (!isset($productData[
"PROPS"]))
170 $productData[
"PROPS"] = array();
176 $item = $this->
getBasket()->getItemByBasketCode($basketCode);
179 if ($item ==
null && $deleteBasketItemsIfNotExists)
184 if($item && $item->isBundleChild())
194 $itemsBasketCodes[] = $item->getBasketCode();
198 $basketItems = $this->
getBasket()->getBasketItems();
200 foreach($basketItems as $item)
202 if(!in_array($item->getBasketCode(), $itemsBasketCodes))
204 if ($deleteBasketItemsIfNotExists)
206 $itemDeleteResult = $item->delete();
208 if (!$itemDeleteResult->isSuccess())
210 $this->builder->getErrorsContainer()->addErrors($itemDeleteResult->getErrors());
211 throw new BuildingException();
216 $this->clearReservesForItem($item);
224 public function itemsDataPreparation()
226 foreach($this->formData[
"PRODUCT"] as $basketCode => $productData)
228 if (isset($productData[
"IS_SET_ITEM"]) && $productData[
"IS_SET_ITEM"] ===
"Y")
233 if(!isset($productData[
"PROPS"]) || !is_array($productData[
"PROPS"]))
234 $productData[
"PROPS"] = array();
237 $item = $this->getItemFromBasket($basketCode, $productData);
241 $this->
setItemData($basketCode, $productData, $item);
245 $item = $this->
createItem($basketCode, $productData);
257 if($basketCode != $item->getBasketCode())
260 if(!empty($productData[
"PROPS"]) && is_array($productData[
"PROPS"]))
263 $property = $item->getPropertyCollection();
264 if(!$property->isPropertyAlreadyExists($productData[
"PROPS"]))
266 $property->setProperty($productData[
"PROPS"]);
280 $this->formData[
'PRODUCT'][$new] = $this->formData[
'PRODUCT'][$old];
281 unset($this->formData[
'PRODUCT'][$old]);
289 protected function setItemsFieldsByFormData()
292 $basketItems = $this->
getBasket()->getBasketItems();
294 foreach($basketItems as $item)
296 $basketCode = $item->getBasketCode();
298 if(empty($this->formData[
'PRODUCT'][$basketCode]))
301 $productData = $this->formData[
'PRODUCT'][$basketCode];
302 $isProductDataNeedUpdate = in_array($basketCode, $this->needDataUpdate);
304 if(isset($productData[
"PRODUCT_PROVIDER_CLASS"]) && $productData[
"PRODUCT_PROVIDER_CLASS"] <>
'')
306 $item->setField(
"PRODUCT_PROVIDER_CLASS", trim($productData[
"PRODUCT_PROVIDER_CLASS"]));
313 if($this->cacheProductProviderData && !$isProductDataNeedUpdate)
315 self::sendProductCachedDataToProvider($item, $this->
getOrder(), $productData);
318 if (isset($productData[
'NAME']))
320 $item->setField(
'NAME', $productData[
'NAME']);
323 $item->setField(
'TYPE', $productData[
'TYPE'] ??
null);
325 if (isset($productData[
'CUSTOM_PRICE']) && $productData[
'CUSTOM_PRICE'] ===
'Y')
327 $item->markFieldCustom(
'PRICE');
330 $res = $item->setField(
"QUANTITY", $productData[
"QUANTITY"]);
332 if(!$res->isSuccess())
335 throw new BuildingException();
338 if (isset($productData[
'VAT_RATE']))
340 $item->markFieldCustom(
'VAT_RATE');
341 $item->setField(
'VAT_RATE', $productData[
'VAT_RATE']);
344 if (isset($productData[
'VAT_INCLUDED']))
346 $item->markFieldCustom(
'VAT_INCLUDED');
347 $item->setField(
'VAT_INCLUDED', $productData[
'VAT_INCLUDED']);
350 if(isset($productData[
"MODULE"]) && $productData[
"MODULE"] ==
"catalog")
352 $this->catalogProductsIds[] = $item->getField(
'PRODUCT_ID');
354 elseif(empty($productData[
"PRODUCT_PROVIDER_CLASS"]))
357 $availableFields = array_fill_keys($availableFields,
true);
358 $fillFields = array_intersect_key($productData, $availableFields);
360 $orderCurrency = $this->
getOrder()->getCurrency();
362 isset($fillFields[
'CURRENCY'])
363 && $fillFields[
'CURRENCY'] !== $orderCurrency
366 $fillFields[
'PRICE'] = \CCurrencyRates::ConvertCurrency(
367 (
float)$fillFields[
'PRICE'],
368 $fillFields[
'CURRENCY'],
371 $fillFields[
'BASE_PRICE'] = \CCurrencyRates::ConvertCurrency(
372 (
float)$fillFields[
'BASE_PRICE'],
373 $fillFields[
'CURRENCY'],
376 $fillFields[
'CURRENCY'] = $orderCurrency;
379 if (!empty($fillFields))
381 $r = $item->setFields($fillFields);
394 if(empty($this->catalogProductsIds))
400 foreach($this->catalogProductsIds as $id)
404 if($details !==
false)
405 $this->catalogProductsData[$id] = $details;
408 $noCachedProductIds = array_diff($this->catalogProductsIds, array_keys($this->catalogProductsData));
410 if(!empty($noCachedProductIds))
412 $noCachedData = \Bitrix\Sale\Helpers\Admin\Product::getData($noCachedProductIds, $order->getSiteId(), array_keys($fields));
414 foreach($noCachedData as $productId => $productData)
416 $this->catalogProductsData[$productId] = $productData;
420 $emptyData = array_diff($this->catalogProductsIds, array_keys($this->catalogProductsData));
422 foreach($emptyData as $productId)
423 $this->catalogProductsData[$productId] = array();
427 protected function obtainProviderProductsData()
430 $basketItems = $this->
getBasket()->getBasketItems();
435 $params = array(
"AVAILABLE_QUANTITY");
437 if($order->getId() <= 0)
443 foreach($basketItems as $item)
445 $basketCode = $item->getBasketCode();
447 if($order->getId() <= 0 && !empty($this->providerData[$basketCode]) && empty($this->providerData[$basketCode][
'QUANTITY']))
453 "SALE_ORDEREDIT_PRODUCT_QUANTITY_IS_EMPTY",
455 "#NAME#" => $item->getField(
'NAME')
458 'SALE_ORDEREDIT_PRODUCT_QUANTITY_IS_EMPTY'
467 protected function isProductAvailable($basketCode, $productFormData, $productProviderData, $isProductDataNeedUpdate)
471 if($this->
getOrder()->getId() <= 0 && (empty($productProviderData[$basketCode]) || !$this->cacheProductProviderData || $isProductDataNeedUpdate))
473 if(empty($productProviderData[$basketCode]) && $productFormData[
"PRODUCT_PROVIDER_CLASS"] <>
'')
483 public function setItemsFields()
486 $basketItems = $this->
getBasket()->getBasketItems();
488 $this->setItemsFieldsByFormData();
490 $this->obtainProviderProductsData();
492 $productProviderData = array();
495 foreach($basketItems as $item)
497 $basketCode = $item->getBasketCode();
498 $productFormData = $this->formData[
'PRODUCT'][$basketCode] ?? [];
499 $isProductDataNeedUpdate = in_array($basketCode, $this->needDataUpdate);
500 $productProviderData[$basketCode] = $item->getFieldValues();
502 if(empty($productFormData))
505 if(!empty($this->providerData[$basketCode]))
507 if ($this->builder->getSettingsContainer()->getItemValue(
'isRefreshData') ===
true)
509 unset($this->providerData[$basketCode][
'QUANTITY']);
512 $productProviderData[$basketCode] = $this->providerData[$basketCode];
516 $productProviderData[$basketCode] =
$trustData[$basketCode];
522 if(is_array($productProviderData[$basketCode]) && !empty($productProviderData[$basketCode]))
523 OrderEdit::setProviderTrustData($item, $order, $productProviderData[$basketCode]);
534 if(!$this->
isProductAvailable($basketCode, $productFormData, $productProviderData, $isProductDataNeedUpdate))
539 "SALE_HLP_ORDERBUILDER_PRODUCT_NOT_AVILABLE",
541 "#NAME#" => $productFormData[
"NAME"] . (!empty($productFormData[
"PRODUCT_ID"]) ?
" (".$productFormData[
'PRODUCT_ID'].
")" :
"")
551 if($item->getField(
"MODULE") ==
"catalog")
553 if(!empty($catalogData[$item->getProductId()]))
555 $product = array_merge($product, $catalogData[$item->getProductId()]);
556 unset($productFormData[
"CURRENCY"]);
561 if(!$this->cacheProductProviderData || $isProductDataNeedUpdate)
563 $product = array_merge($productFormData, $product);
567 $basePrice = (float)($productFormData[
'BASE_PRICE'] ?? 0);
568 $price = (float)($productFormData[
'PRICE'] ?? 0);
571 $isPriceCustom = isset($productFormData[
'CUSTOM_PRICE']) && $productFormData[
'CUSTOM_PRICE'] ==
'Y';
575 $productFormData[
'DISCOUNT_PRICE'] = 0;
576 if ($basePrice > $price)
578 $productFormData[
'DISCOUNT_PRICE'] = $basePrice - $price;
582 if (($order->getId() === 0 && !$isPriceCustom) || $needUpdateItemPrice)
584 unset($productFormData[
'PRICE'], $productFormData[
'PRICE_BASE'], $productFormData[
'BASE_PRICE']);
587 $product = array_merge($product, $productFormData);
590 if (isset($product[
"OFFER_ID"]) && intval($product[
"OFFER_ID"]) > 0)
592 $product[
"PRODUCT_ID"] = $product[
"OFFER_ID"];
596 $product = array_intersect_key($product, array_flip($item::getAvailableFields()));
598 if (isset($product[
"MEASURE_CODE"]) && $product[
"MEASURE_CODE"] <>
'')
600 $measures = OrderBasket::getCatalogMeasures();
602 if (!empty($measures[$product[
"MEASURE_CODE"]]))
604 $product[
"MEASURE_NAME"] = $measures[$product[
"MEASURE_CODE"]];
608 if (empty($product[
"CURRENCY"]))
610 $product[
"CURRENCY"] = $order->getCurrency();
614 isset($productFormData[
"IS_SET_PARENT"])
615 && $productFormData[
"IS_SET_PARENT"] ===
"Y"
622 $productFormData[
"OFFER_ID"],
625 array_merge($product, $productFormData)
628 if ($product[
"CURRENCY"] !== $order->getCurrency())
630 $product[
"PRICE"] = \CCurrencyRates::ConvertCurrency($product[
"PRICE"], $product[
"CURRENCY"], $order->getCurrency());
631 if ($product[
"BASE_PRICE"] > 0)
633 $product[
"BASE_PRICE"] = \CCurrencyRates::ConvertCurrency($product[
"BASE_PRICE"], $product[
"CURRENCY"], $order->getCurrency());
635 if ($product[
"DISCOUNT_PRICE"] > 0)
637 $product[
"DISCOUNT_PRICE"] = \CCurrencyRates::ConvertCurrency($product[
"DISCOUNT_PRICE"], $product[
"CURRENCY"], $order->getCurrency());
639 if ($product[
"VAT_RATE"] > 0)
641 $product[
"VAT_RATE"] = \CCurrencyRates::ConvertCurrency($product[
"VAT_RATE"], $product[
"CURRENCY"], $order->getCurrency());
644 $product[
"CURRENCY"] = $order->getCurrency();
649 if ($item->isReservableItem())
651 if (!empty($productFormData[
'RESERVE']) && is_array($productFormData[
'RESERVE']))
653 $reserveData = $productFormData[
'RESERVE'];
658 $this->clearReservesForItem($item);
666 protected function clearReservesForItem(BasketItem $item)
668 if (!$item->isReservableItem())
674 $reserveCollection = $item->getReserveQuantityCollection();
675 if ($reserveCollection)
677 $reserveCollection->clearCollection();
688 $reserveCollection = $item->getReserveQuantityCollection();
689 if (!$reserveCollection)
697 $this->clearReservesForItem($item);
700 foreach ($reserveData as $reserveCode => $reserve)
702 $isNewReserve = mb_strpos($reserveCode,
'n') === 0;
705 $reserveCollectionItem = $reserveCollection->create();
709 $reserveCollectionItem = $reserveCollection->getItemById($reserveCode);
710 if (!$reserveCollectionItem)
716 if (isset($reserve[
'STORE_ID']) && (
int)$reserve[
'STORE_ID'] !== $reserveCollectionItem->getStoreId())
721 $deleteResult = $reserveCollectionItem->delete();
722 if (!$deleteResult->isSuccess())
728 $reserveCollectionItem = $reserveCollection->create();
731 $reserveCollectionItem->setStoreId((
int)$reserve[
'STORE_ID']);
734 if (isset($reserve[
'QUANTITY']))
736 $quantity = (float)$reserve[
'QUANTITY'];
741 $reserveCollectionItem->setQuantity($quantity);
744 if (isset($reserve[
'DATE_RESERVE_END']) && $reserve[
'DATE_RESERVE_END'] !==
'')
746 $dateReserveEnd =
new Date($reserve[
'DATE_RESERVE_END']);
747 $reserveCollectionItem->setField(
'DATE_RESERVE_END', $dateReserveEnd);
750 if (isset($reserve[
'RESERVED_BY']))
752 $reserveCollectionItem->setField(
'RESERVED_BY', $reserve[
'RESERVED_BY']);
759 return $this->builder->getOrder();
764 return $this->builder->getSettingsContainer();
769 return $this->builder->getErrorsContainer();
779 return $this->builder->getOrder()->getBasket();
787 protected function getItemFromBasket($basketCode, $productData)
790 $item = $this->delegate->getItemFromBasket($basketCode, $productData);
792 if($item && $item->isBundleChild())
798 protected function setItemData($basketCode, &$productData, &$item)
800 return $this->delegate->setItemData($basketCode, $productData, $item);
806 if($basketCode != self::BASKET_CODE_NEW)
807 $setBasketCode = $basketCode;
808 elseif(intval($this->maxBasketCodeIdx) > 0)
809 $setBasketCode =
'n'.strval($this->maxBasketCodeIdx+1);
811 $setBasketCode =
null;
814 $productData[
"MODULE"] ??
'',
815 $productData[
"OFFER_ID"],
819 if ($basketCode != $productData[
"BASKET_CODE"])
820 $productData[
"BASKET_CODE"] = $item->getBasketCode();
822 if($basketCode == self::BASKET_CODE_NEW)
825 $this->needDataUpdate[] = $item->getBasketCode();
828 if(!empty($productData[
'REPLACED']) && $productData[
'REPLACED'] ==
'Y')
829 $this->needDataUpdate[] = $item->getBasketCode();
836 static $result =
null;
837 $catalogIncluded =
null;
839 if(!is_array($result))
843 if ($catalogIncluded ===
null)
845 $catalogIncluded = Loader::includeModule(
'catalog');
848 if ($catalogIncluded)
850 $dbList = \CCatalogMeasure::getList();
852 while($arList = $dbList->Fetch())
854 $result[$arList[
"CODE"]] = ($arList[
"SYMBOL_RUS"] !=
'' ? $arList[
"SYMBOL_RUS"] : $arList[
"SYMBOL_INTL"]);
860 $result[796] = GetMessage(
"SALE_ORDER_BASKET_SHTUKA");
867 public function sendProductCachedDataToProvider(
BasketItem $item,
Order $order, array &$productData)
869 if(empty($productData[
"PROVIDER_DATA"]) || !CheckSerializedData($productData[
"PROVIDER_DATA"]))
872 $trustData = unserialize($productData[
"PROVIDER_DATA"], [
'allowed_classes' =>
false]);
885 foreach ($bundle as $bundleItem)
887 $bundleItemData = $bundleItem->getFields()->getValues();
888 Provider::setTrustData($order->getSiteId(), $bundleItem->getField(
'MODULE'), $bundleItem->getProductId(), $bundleItemData);
898 $result = $item->setFields($fields);
900 if(!$result->isSuccess())
902 foreach($result->getErrors() as $error)
907 if(is_array($containerErrors) && !empty($containerErrors))
911 if($error->getMessage() !== $existError->getMessage())
929 $this->delegate->finalActions();
948 if ($basket && !$basket->getFUserId(
true))
953 if ($order && $order->getUserId())