1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
basketbuilder.php
См. документацию.
1<?
3
13use Bitrix\Sale\Helpers\Admin\Blocks\OrderBasket;
14use Bitrix\Sale\Helpers\Admin\OrderEdit;
15use Bitrix\Sale\Order;
18
24abstract class BasketBuilder
25{
26 const BASKET_CODE_NEW = 'new';
27
29 protected $delegate = null;
31 protected $builder = null;
33 protected $maxBasketCodeIdx = 0;
35 protected $formData = [];
37 protected $needDataUpdate = array();
39 protected $basketCodeMap = [];
41 protected $cacheProductProviderData = false;
43 protected $catalogProductsIds = [];
45 protected $catalogProductsData = [];
47 protected $providerData = [];
49 protected $trustData = [];
51 protected $isProductAdded = false;
52
54 {
55 $this->builder = $builder;
56 $this->cacheProductProviderData = $this->builder->getSettingsContainer()->getItemValue('cacheProductProviderData');
57 }
58
59 public function initBasket()
60 {
61 $this->formData = $this->builder->getFormData();
62 $this->delegate = $this->getDelegate($this->formData['ID']);
64 return $this;
65 }
66
71 protected function getDelegate($orderId)
72 {
73 return (int)$orderId > 0 ? new BasketBuilderExist($this) : new BasketBuilderNew($this);
74 }
75
80 {
81 return $this->builder->getSettingsContainer()->getItemValue('needUpdateNewProductPrice');
82 }
83
84 public function checkProductData(array $productData)
85 {
86 $result = true;
87
88 if((float)$productData['QUANTITY'] <= 0)
89 {
90 $this->getErrorsContainer()->addError(
91 new Error(
92 Loc::getMessage(
93 "SALE_HLP_ORDERBUILDER_QUANTITY_ERROR",
94 ['#PRODUCT_NAME#' => $productData['NAME']]
95 )));
96
97 $result = false;
98 }
99
100 if((int)$productData['PRICE'] < 0)
101 {
102 $this->getErrorsContainer()->addError(
103 new Error(
104 Loc::getMessage(
105 "SALE_HLP_ORDERBUILDER_PRICE_ERROR",
106 ['#PRODUCT_NAME#' => $productData['NAME']]
107 )));
108
109 $result = false;
110 }
111
112 return $result;
113 }
114
116 {
117 foreach($this->formData["PRODUCT"] as $basketCode => $productData)
118 {
119 if(!$this->checkProductData($productData))
120 {
121 throw new BuildingException();
122 }
123
124 if(self::isBasketItemNew($basketCode))
125 {
126 $basketInternalId = intval(mb_substr($basketCode, 1));
127
128 if($basketInternalId > $this->maxBasketCodeIdx)
129 $this->maxBasketCodeIdx = $basketInternalId;
130
131 // by the way let's mark rows for update data if need
132 if($this->isNeedUpdateNewProductPrice()) //???is it right for edit orders
133 {
134 $this->needDataUpdate[] = $basketCode; //???is it needed by new orders
135 unset($this->formData["PRODUCT"][$basketCode]["PROVIDER_DATA"]);
136 unset($this->formData["PRODUCT"][$basketCode]["SET_ITEMS_DATA"]);
137 }
138 }
139 }
140
141 /*
142 * Because of one of discounts, require that the first product must be the most expencsve.
143 * If we want to save the sorting of the products we must use field "SORT" - fill it earlier
144 * and use it during layout.
145 */
146
147 sortByColumn($this->formData["PRODUCT"], array("BASE_PRICE" => SORT_DESC, "PRICE" => SORT_DESC), '', null, true);
148 return $this;
149 }
150
154 protected function getExistsItem($moduleId, $productId, array $properties = array())
155 {
156 return $this->getBasket()->getExistsItem($moduleId, $productId, $properties);
157 }
158
159 public function removeDeletedItems()
160 {
161 $deleteBasketItemsIfNotExists = $this->builder->getSettingsContainer()->getItemValue('deleteBasketItemsIfNotExists');
162 $itemsBasketCodes = [];
163
164 foreach($this->formData["PRODUCT"] as $basketCode => $productData)
165 {
166 if (!isset($productData["PROPS"]))
167 {
168 $productData["PROPS"] = array();
169 }
170
171 $item = null;
172 if ($basketCode != \Bitrix\Sale\Helpers\Admin\OrderEdit::BASKET_CODE_NEW)
173 {
174 $item = $this->getBasket()->getItemByBasketCode($basketCode);
175 }
176
177 if ($item == null && $deleteBasketItemsIfNotExists)
178 {
180 }
181
182 if($item && $item->isBundleChild())
183 {
184 continue;
185 }
186
187 if(!$item)
188 {
189 continue;
190 }
191
192 $itemsBasketCodes[] = $item->getBasketCode();
193 }
194
196 $basketItems = $this->getBasket()->getBasketItems();
197
198 foreach($basketItems as $item)
199 {
200 if(!in_array($item->getBasketCode(), $itemsBasketCodes))
201 {
202 if ($deleteBasketItemsIfNotExists)
203 {
204 $itemDeleteResult = $item->delete();
205
206 if (!$itemDeleteResult->isSuccess())
207 {
208 $this->builder->getErrorsContainer()->addErrors($itemDeleteResult->getErrors());
209 throw new BuildingException();
210 }
211 }
212 elseif ($this->getSettingsContainer()->getItemValue('clearReservesIfEmpty') === true)
213 {
214 $this->clearReservesForItem($item);
215 }
216 }
217 }
218
219 return $this;
220 }
221
222 public function itemsDataPreparation()
223 {
224 foreach($this->formData["PRODUCT"] as $basketCode => $productData)
225 {
226 if (isset($productData["IS_SET_ITEM"]) && $productData["IS_SET_ITEM"] === "Y")
227 {
228 continue;
229 }
230
231 if(!isset($productData["PROPS"]) || !is_array($productData["PROPS"]))
232 $productData["PROPS"] = array();
233
235 $item = $this->getItemFromBasket($basketCode, $productData);
236
237 if($item)
238 {
239 $this->setItemData($basketCode, $productData, $item);
240 }
241 else
242 {
243 $item = $this->createItem($basketCode, $productData);
244
245 if(!$this->isProductAdded)
246 {
247 $this->isProductAdded = true;
248 }
249 }
250
251 /*
252 * Could be deleted and than added one more time product.
253 * Or just added product.
254 */
255 if($basketCode != $item->getBasketCode())
256 $this->basketCodeMap[$basketCode] = $item->getBasketCode();
257
258 if(!empty($productData["PROPS"]) && is_array($productData["PROPS"]))
259 {
261 $property = $item->getPropertyCollection();
262 if(!$property->isPropertyAlreadyExists($productData["PROPS"]))
263 {
264 $property->setProperty($productData["PROPS"]);
265 }
266 }
267 }
268
269 return $this;
270 }
271
272 public function basketCodeMap()
273 {
274 if(!empty($this->basketCodeMap))
275 {
276 foreach($this->basketCodeMap as $old => $new)
277 {
278 $this->formData['PRODUCT'][$new] = $this->formData['PRODUCT'][$old];
279 unset($this->formData['PRODUCT'][$old]);
280 }
281 }
282
283 return $this;
284 }
285
286 // Preparing fields needed by provider
287 protected function setItemsFieldsByFormData()
288 {
290 $basketItems = $this->getBasket()->getBasketItems();
291
292 foreach($basketItems as $item)
293 {
294 $basketCode = $item->getBasketCode();
295
296 if(empty($this->formData['PRODUCT'][$basketCode]))
297 continue;
298
299 $productData = $this->formData['PRODUCT'][$basketCode];
300 if (
301 isset($productData['MODULE'])
302 && $productData['MODULE'] === 'catalog'
303 && empty($productData['PRODUCT_PROVIDER_CLASS'])
304 && Loader::includeModule('catalog')
305 )
306 {
307 $productData['PRODUCT_PROVIDER_CLASS'] = '\\'.Product\CatalogProvider::class;
308 }
309
310 $isProductDataNeedUpdate = in_array($basketCode, $this->needDataUpdate);
311
312 if(isset($productData["PRODUCT_PROVIDER_CLASS"]) && $productData["PRODUCT_PROVIDER_CLASS"] <> '')
313 {
314 $item->setField("PRODUCT_PROVIDER_CLASS", trim($productData["PRODUCT_PROVIDER_CLASS"]));
315 }
316
317 /*
318 * Let's extract cached provider product data from field
319 * in case activity is through ajax.
320 */
321 if($this->cacheProductProviderData && !$isProductDataNeedUpdate)
322 {
323 self::sendProductCachedDataToProvider($item, $this->getOrder(), $productData);
324 }
325
326 if (isset($productData['NAME']))
327 {
328 $item->setField('NAME', $productData['NAME']);
329 }
330
331 $item->setField('TYPE', $productData['TYPE'] ?? null);
332
333 if (isset($productData['CUSTOM_PRICE']) && $productData['CUSTOM_PRICE'] === 'Y')
334 {
335 $item->markFieldCustom('PRICE');
336 }
337
338 $res = $item->setField("QUANTITY", $productData["QUANTITY"]);
339
340 if(!$res->isSuccess())
341 {
342 $this->getErrorsContainer()->addErrors($res->getErrors());
343 throw new BuildingException();
344 }
345
346 if (isset($productData['VAT_RATE']))
347 {
348 $item->markFieldCustom('VAT_RATE');
349 $item->setField('VAT_RATE', $productData['VAT_RATE']);
350 }
351
352 if (isset($productData['VAT_INCLUDED']))
353 {
354 $item->markFieldCustom('VAT_INCLUDED');
355 $item->setField('VAT_INCLUDED', $productData['VAT_INCLUDED']);
356 }
357
358 if(isset($productData["MODULE"]) && $productData["MODULE"] == "catalog")
359 {
360 $this->catalogProductsIds[] = $item->getField('PRODUCT_ID');
361 }
362 elseif(empty($productData["PRODUCT_PROVIDER_CLASS"]))
363 {
364 $availableFields = BasketItemBase::getAvailableFields();
365 $availableFields = array_fill_keys($availableFields, true);
366 $fillFields = array_intersect_key($productData, $availableFields);
367
368 $orderCurrency = $this->getOrder()->getCurrency();
369 if (
370 isset($fillFields['CURRENCY'])
371 && $fillFields['CURRENCY'] !== $orderCurrency
372 )
373 {
374 $fillFields['PRICE'] = \CCurrencyRates::ConvertCurrency(
375 (float)$fillFields['PRICE'],
376 $fillFields['CURRENCY'],
377 $orderCurrency
378 );
379 $fillFields['BASE_PRICE'] = \CCurrencyRates::ConvertCurrency(
380 (float)$fillFields['BASE_PRICE'],
381 $fillFields['CURRENCY'],
382 $orderCurrency
383 );
384 $fillFields['CURRENCY'] = $orderCurrency;
385 }
386
387 if (!empty($fillFields))
388 {
389 $r = $item->setFields($fillFields);
390
391 if(!$r->isSuccess())
392 {
393 $this->getErrorsContainer()->getErrors($r->addErrors());
394 }
395 }
396 }
397 }
398 }
399
401 {
402 if(empty($this->catalogProductsIds))
403 return;
404
405 $order = $this->getOrder();
406 //$this->catalogProductsIds = array();
407
408 foreach($this->catalogProductsIds as $id)
409 {
410 $details = OrderEdit::getProductDetails($id, $order->getUserId(), $order->getSiteId());
411
412 if($details !== false)
413 $this->catalogProductsData[$id] = $details;
414 }
415
416 $noCachedProductIds = array_diff($this->catalogProductsIds, array_keys($this->catalogProductsData));
417
418 if(!empty($noCachedProductIds))
419 {
420 $noCachedData = \Bitrix\Sale\Helpers\Admin\Product::getData($noCachedProductIds, $order->getSiteId(), array_keys($fields));
421
422 foreach($noCachedData as $productId => $productData)
423 {
424 $this->catalogProductsData[$productId] = $productData;
425 OrderEdit::setProductDetails($productId, $order->getUserId(), $order->getSiteId(), $this->catalogProductsData[$productId]);
426 }
427
428 $emptyData = array_diff($this->catalogProductsIds, array_keys($this->catalogProductsData));
429
430 foreach($emptyData as $productId)
431 $this->catalogProductsData[$productId] = array();
432 }
433 }
434
435 protected function obtainProviderProductsData()
436 {
437 $order = $this->getOrder();
438 $basketItems = $this->getBasket()->getBasketItems();
439
440 if($this->cacheProductProviderData && empty($this->needDataUpdate) && !$this->isNeedUpdateNewProductPrice())
441 return;
442
443 $params = array("AVAILABLE_QUANTITY");
444
445 if($order->getId() <= 0)
446 $params[] = "PRICE";
447
448 $this->providerData = Provider::getProductData($this->getBasket(), $params);
449
451 foreach($basketItems as $item)
452 {
453 $basketCode = $item->getBasketCode();
454
455 if($order->getId() <= 0 && !empty($this->providerData[$basketCode]) && empty($this->providerData[$basketCode]['QUANTITY']))
456 {
457
458 $this->getErrorsContainer()->addError(
459 new Error(
460 Loc::getMessage(
461 "SALE_ORDEREDIT_PRODUCT_QUANTITY_IS_EMPTY",
462 array(
463 "#NAME#" => $item->getField('NAME')
464 )
465 ),
466 'SALE_ORDEREDIT_PRODUCT_QUANTITY_IS_EMPTY'
467 )
468 );
469
470 throw new BuildingException();
471 }
472 }
473 }
474
475 protected function isProductAvailable($basketCode, $productFormData, $productProviderData, $isProductDataNeedUpdate)
476 {
477 $result = true;
478
479 if($this->getOrder()->getId() <= 0 && (empty($productProviderData[$basketCode]) || !$this->cacheProductProviderData || $isProductDataNeedUpdate))
480 {
481 if(empty($productProviderData[$basketCode]) && $productFormData["PRODUCT_PROVIDER_CLASS"] <> '')
482 {
483 $result = false;
484 }
485 }
486
487 return $result;
488 }
489
490 //todo: \Bitrix\Catalog\Product\Basket::addProductToBasket()
491 public function setItemsFields()
492 {
493 $order = $this->getOrder();
494 $basketItems = $this->getBasket()->getBasketItems();
495
496 $this->setItemsFieldsByFormData();
498 $this->obtainProviderProductsData();
499
500 $productProviderData = array();
501
503 $firstBasketItem = $basketItems[0] ?? null;
504 $vatIncludedFromFirstItem = $firstBasketItem?->getField('VAT_INCLUDED');
505
507 foreach($basketItems as $item)
508 {
509 $basketCode = $item->getBasketCode();
510 $productFormData = $this->formData['PRODUCT'][$basketCode] ?? [];
511 $isProductDataNeedUpdate = in_array($basketCode, $this->needDataUpdate);
512 $productProviderData[$basketCode] = $item->getFieldValues();
513
514 if(empty($productFormData))
515 continue;
516
517 if(!empty($this->providerData[$basketCode]))
518 {
519 if ($this->builder->getSettingsContainer()->getItemValue('isRefreshData') === true)
520 {
521 unset($this->providerData[$basketCode]['QUANTITY']);
522 }
523
524 $productProviderData[$basketCode] = $this->providerData[$basketCode];
525 }
526 elseif(!empty($trustData[$basketCode]))
527 {
528 $productProviderData[$basketCode] = $trustData[$basketCode];
529 }
530 else
531 {
532 $productProviderData = Provider::getProductData($this->getBasket(), array("PRICE", "AVAILABLE_QUANTITY"), $item);
533
534 if(is_array($productProviderData[$basketCode]) && !empty($productProviderData[$basketCode]))
535 OrderEdit::setProviderTrustData($item, $order, $productProviderData[$basketCode]);
536 }
537
538 /* Get actual info from provider
539 * cases:
540 * 1) add new product to basket;
541 * 2) saving operation;
542 * 3) changing quantity;
543 * 4) changing buyerId
544 */
545
546 if(!$this->isProductAvailable($basketCode, $productFormData, $productProviderData, $isProductDataNeedUpdate))
547 {
548 $this->getErrorsContainer()->addError(
549 new Error(
550 Loc::getMessage(
551 "SALE_HLP_ORDERBUILDER_PRODUCT_NOT_AVILABLE",
552 array(
553 "#NAME#" => $productFormData["NAME"] . (!empty($productFormData["PRODUCT_ID"]) ? " (".$productFormData['PRODUCT_ID'].")" : "")
554 )
555 )
556 )
557 );
558 }
559
560 $product = array();
561
562 //merge catalog data
563 if($item->getField("MODULE") == "catalog")
564 {
565 if(!empty($catalogData[$item->getProductId()]))
566 {
567 $product = array_merge($product, $catalogData[$item->getProductId()]);
568 unset($productFormData["CURRENCY"]);
569 }
570 }
571
572 //merge form data
573 if(!$this->cacheProductProviderData || $isProductDataNeedUpdate)
574 {
575 $product = array_merge($productFormData, $product);
576 }
577 else
578 {
579 $basePrice = (float)($productFormData['BASE_PRICE'] ?? 0);
580 $price = (float)($productFormData['PRICE'] ?? 0);
581
582 $needUpdateItemPrice = $this->isNeedUpdateNewProductPrice() && $this->isBasketItemNew($basketCode);
583 $isPriceCustom = isset($productFormData['CUSTOM_PRICE']) && $productFormData['CUSTOM_PRICE'] == 'Y';
584
585 if ($isPriceCustom)
586 {
587 $productFormData['DISCOUNT_PRICE'] = 0;
588 if ($basePrice > $price)
589 {
590 $productFormData['DISCOUNT_PRICE'] = $basePrice - $price;
591 }
592 }
593
594 if (($order->getId() === 0 && !$isPriceCustom) || $needUpdateItemPrice)
595 {
596 unset($productFormData['PRICE'], $productFormData['PRICE_BASE'], $productFormData['BASE_PRICE']);
597 }
598
599 $product = array_merge($product, $productFormData);
600 }
601
602 if (isset($product["OFFER_ID"]) && intval($product["OFFER_ID"]) > 0)
603 {
604 $product["PRODUCT_ID"] = $product["OFFER_ID"];
605 }
606
607 //discard BasketItem redundant fields
608 $product = array_intersect_key($product, array_flip($item::getAvailableFields()));
609
610 if (isset($product["MEASURE_CODE"]) && $product["MEASURE_CODE"] <> '')
611 {
612 $measures = OrderBasket::getCatalogMeasures();
613
614 if (!empty($measures[$product["MEASURE_CODE"]]))
615 {
616 $product["MEASURE_NAME"] = $measures[$product["MEASURE_CODE"]];
617 }
618 }
619
620 if (empty($product["CURRENCY"]))
621 {
622 $product["CURRENCY"] = $order->getCurrency();
623 }
624
625 if (
626 isset($productFormData["IS_SET_PARENT"])
627 && $productFormData["IS_SET_PARENT"] === "Y"
628 )
629 {
630 $product["TYPE"] = BasketItem::TYPE_SET;
631 }
632
633 OrderEdit::setProductDetails(
634 $productFormData["OFFER_ID"] ?? null,
635 $order->getUserId(),
636 $order->getSiteId(),
637 array_merge($product, $productFormData)
638 );
639
640 if ($product["CURRENCY"] !== $order->getCurrency())
641 {
642 $product["PRICE"] = \CCurrencyRates::ConvertCurrency($product["PRICE"], $product["CURRENCY"], $order->getCurrency());
643 if ($product["BASE_PRICE"] > 0)
644 {
645 $product["BASE_PRICE"] = \CCurrencyRates::ConvertCurrency($product["BASE_PRICE"], $product["CURRENCY"], $order->getCurrency());
646 }
647 if ($product["DISCOUNT_PRICE"] > 0)
648 {
649 $product["DISCOUNT_PRICE"] = \CCurrencyRates::ConvertCurrency($product["DISCOUNT_PRICE"], $product["CURRENCY"], $order->getCurrency());
650 }
651 if ($product["VAT_RATE"] > 0)
652 {
653 $product["VAT_RATE"] = \CCurrencyRates::ConvertCurrency($product["VAT_RATE"], $product["CURRENCY"], $order->getCurrency());
654 }
655
656 $product["CURRENCY"] = $order->getCurrency();
657 }
658
659 if ($vatIncludedFromFirstItem)
660 {
661 $product = $this->correctVatIncludedByFirstItem($product, $vatIncludedFromFirstItem);
662 }
663
664 $this->setBasketItemFields($item, $product);
665
666 if ($item->isReservableItem())
667 {
668 if (!empty($productFormData['RESERVE']) && is_array($productFormData['RESERVE']))
669 {
670 $reserveData = $productFormData['RESERVE'];
671 $this->setReserveDataForItem($item, $reserveData);
672 }
673 elseif ($this->getSettingsContainer()->getItemValue('clearReservesIfEmpty') === true)
674 {
675 $this->clearReservesForItem($item);
676 }
677 }
678 }
679
680 return $this;
681 }
682
683 protected function clearReservesForItem(BasketItem $item)
684 {
685 if (!$item->isReservableItem())
686 {
687 return;
688 }
689
691 $reserveCollection = $item->getReserveQuantityCollection();
692 if ($reserveCollection)
693 {
694 $reserveCollection->clearCollection();
695 }
696 }
697
698 protected function setReserveDataForItem(BasketItem $item, array $reserveData)
699 {
700 if (!$item->isReservableItem())
701 {
702 return;
703 }
704
705 $reserveCollection = $item->getReserveQuantityCollection();
706 if (!$reserveCollection)
707 {
708 return;
709 }
710
711 // if some reserves were created upon order creation, we have to clear them and set the manual reserves
712 if ($this->getOrder()->isNew())
713 {
714 $this->clearReservesForItem($item);
715 }
716
717 foreach ($reserveData as $reserveCode => $reserve)
718 {
719 $isNewReserve = mb_strpos($reserveCode, 'n') === 0;
720 if ($isNewReserve)
721 {
722 $reserveCollectionItem = $reserveCollection->create();
723 }
724 else
725 {
726 $reserveCollectionItem = $reserveCollection->getItemById($reserveCode);
727 if (!$reserveCollectionItem)
728 {
729 continue;
730 }
731 }
732
733 if (isset($reserve['STORE_ID']) && (int)$reserve['STORE_ID'] !== $reserveCollectionItem->getStoreId())
734 {
735 if (!$isNewReserve)
736 {
737 // drop the old reserve and create a new one instead since we can't just change the store id like that
738 $deleteResult = $reserveCollectionItem->delete();
739 if (!$deleteResult->isSuccess())
740 {
741 $this->getErrorsContainer()->addErrors($deleteResult->getErrors());
742 continue;
743 }
744
745 $reserveCollectionItem = $reserveCollection->create();
746 }
747
748 $reserveCollectionItem->setStoreId((int)$reserve['STORE_ID']);
749 }
750
751 if (isset($reserve['QUANTITY']))
752 {
753 $quantity = (float)$reserve['QUANTITY'];
754 if ($quantity < 0)
755 {
756 $quantity = 0;
757 }
758 $reserveCollectionItem->setQuantity($quantity);
759 }
760
761 if (isset($reserve['DATE_RESERVE_END']) && $reserve['DATE_RESERVE_END'] !== '')
762 {
763 $dateReserveEnd = new Date($reserve['DATE_RESERVE_END']);
764 $reserveCollectionItem->setField('DATE_RESERVE_END', $dateReserveEnd);
765 }
766
767 if (isset($reserve['RESERVED_BY']))
768 {
769 $reserveCollectionItem->setField('RESERVED_BY', $reserve['RESERVED_BY']);
770 }
771 }
772 }
773
774 public function getOrder()
775 {
776 return $this->builder->getOrder();
777 }
778
779 public function getSettingsContainer()
780 {
781 return $this->builder->getSettingsContainer();
782 }
783
784 public function getErrorsContainer()
785 {
786 return $this->builder->getErrorsContainer();
787 }
788
789 public function getFormData()
790 {
791 return $this->formData;
792 }
793
794 public function getBasket()
795 {
796 return $this->builder->getOrder()->getBasket();
797 }
798
799 public static function isBasketItemNew($basketCode)
800 {
801 return (mb_strpos($basketCode, 'n') === 0) && ($basketCode != self::BASKET_CODE_NEW);
802 }
803
804 protected function getItemFromBasket($basketCode, $productData)
805 {
807 $item = $this->delegate->getItemFromBasket($basketCode, $productData);
808
809 if($item && $item->isBundleChild())
810 $item = null;
811
812 return $item;
813 }
814
815 protected function setItemData($basketCode, &$productData, &$item)
816 {
817 return $this->delegate->setItemData($basketCode, $productData, $item);
818 }
819
820 protected function createItem($basketCode, &$productData)
821 {
822 //todo: is it stil working?
823 if($basketCode != self::BASKET_CODE_NEW)
824 $setBasketCode = $basketCode;
825 elseif(intval($this->maxBasketCodeIdx) > 0)
826 $setBasketCode = 'n'.strval($this->maxBasketCodeIdx+1); //Fix collision part 2.
827 else
828 $setBasketCode = null;
829
830 $item = $this->getBasket()->createItem(
831 $productData["MODULE"] ?? '',
832 $productData["OFFER_ID"] ?? null,
833 $setBasketCode
834 );
835
836 if (
837 !isset($productData['BASKET_CODE'])
838 || $basketCode != $productData['BASKET_CODE']
839 )
840 {
841 $productData["BASKET_CODE"] = $item->getBasketCode();
842 }
843
844 if($basketCode == self::BASKET_CODE_NEW)
845 {
846 //$result->setData(array("NEW_ITEM_BASKET_CODE" => $productData["BASKET_CODE"]));
847 $this->needDataUpdate[] = $item->getBasketCode();
848 }
849
850 if(!empty($productData['REPLACED']) && $productData['REPLACED'] == 'Y')
851 $this->needDataUpdate[] = $item->getBasketCode();
852
853 return $item;
854 }
855
856 public static function getCatalogMeasures()
857 {
858 static $result = null;
859 $catalogIncluded = null;
860
861 if(!is_array($result))
862 {
863 $result = array();
864
865 if ($catalogIncluded === null)
866 {
867 $catalogIncluded = Loader::includeModule('catalog');
868 }
869
870 if ($catalogIncluded)
871 {
872 $iterator = \CCatalogMeasure::getList();
873 while ($measure = $iterator->Fetch())
874 {
875 $result[$measure["CODE"]] = ($measure["SYMBOL_RUS"] != '' ? $measure["SYMBOL_RUS"] : $measure["SYMBOL_INTL"]);
876 }
877 }
878
879 if (empty($result))
880 {
881 $result[796] = GetMessage("SALE_ORDER_BASKET_SHTUKA");
882 }
883 }
884
885 return $result;
886 }
887
888 public function sendProductCachedDataToProvider(BasketItem $item, Order $order, array &$productData)
889 {
890 if(empty($productData["PROVIDER_DATA"]) || !CheckSerializedData($productData["PROVIDER_DATA"]))
891 return;
892
893 $trustData = unserialize($productData["PROVIDER_DATA"], ['allowed_classes' => false]);
894
895 //quantity was changed so data must be changed
896 if(empty($trustData) || $trustData["QUANTITY"] == $productData["QUANTITY"])
897 return;
898
899 Provider::setTrustData($order->getSiteId(), $item->getField('MODULE'), $item->getProductId(), $trustData);
900
901 if ($item->isBundleParent())
902 {
903 if ($bundle = $item->getBundleCollection())
904 {
906 foreach ($bundle as $bundleItem)
907 {
908 $bundleItemData = $bundleItem->getFields()->getValues();
909 Provider::setTrustData($order->getSiteId(), $bundleItem->getField('MODULE'), $bundleItem->getProductId(), $bundleItemData);
910 }
911 }
912 }
913
914 $this->trustData[$item->getBasketCode()] = $trustData;
915 }
916
918 {
919 $result = $item->setFields($fields);
920
921 if(!$result->isSuccess())
922 {
923 foreach($result->getErrors() as $error)
924 {
925 $containerErrors = $this->getErrorsContainer()->getErrors();
926
927 //avoid duplication
928 if(is_array($containerErrors) && !empty($containerErrors))
929 {
930 foreach($this->getErrorsContainer()->getErrors() as $existError)
931 {
932 if($error->getMessage() !== $existError->getMessage())
933 {
934 $this->getErrorsContainer()->addError($error);
935 }
936 }
937 }
938 else
939 {
940 $this->getErrorsContainer()->addError($error);
941 }
942 }
943
944 throw new BuildingException();
945 }
946 }
947
948 public function finalActions()
949 {
950 $this->delegate->finalActions();
951 return $this;
952 }
953
954 public function isProductAdded()
955 {
957 }
958
966 public function fillFUser()
967 {
968 $basket = $this->getBasket();
969 if ($basket && !$basket->getFUserId(true))
970 {
971 $fuserId = null;
972
973 $order = $this->getOrder();
974 if ($order && $order->getUserId())
975 {
976 $fuserId = Fuser::getUserIdById($order->getUserId());
977 }
978
979 $basket->setFUserId(
980 $fuserId ?: Fuser::getId(false)
981 );
982 }
983
984 return $this;
985 }
986
992 public function correctVatIncludedByFirstItem(array $product, string $vatIncludedFromFirstItem): array
993 {
994 if (
995 empty($product['PRICE'])
996 ||
997 empty($product['BASE_PRICE'])
998 ||
999 empty($product['VAT_RATE'])
1000 )
1001 {
1002 $product['VAT_INCLUDED'] = $vatIncludedFromFirstItem;
1003
1004 return $product;
1005 }
1006
1007 $vatIncludedFrom = $product['VAT_INCLUDED'];
1008 $price = (float)$product['PRICE'];
1009 $basePrice = (float)$product['BASE_PRICE'];
1010
1011 if ($vatIncludedFrom === 'Y' && $vatIncludedFromFirstItem === 'N')
1012 {
1013 $calculator = new \Bitrix\Sale\Tax\VatCalculator($product['VAT_RATE']);
1014 $price = $calculator->allocate($product['PRICE']);
1015 $basePrice = $calculator->allocate($product['BASE_PRICE']);
1016 }
1017
1018 $product['PRICE'] = $price;
1019 $product['BASE_PRICE'] = $basePrice;
1020
1021 // There can be only one value for all of them
1022 $product['VAT_INCLUDED'] = $vatIncludedFromFirstItem;
1023
1024 return $product;
1025 }
1026}
$catalogData
Определения options.php:2236
Определения error.php:15
Определения loader.php:13
Определения date.php:9
static getAvailableFields()
Определения basketitembase.php:243
getField($name)
Определения basketitembase.php:478
getBundleCollection()
Определения basketitem.php:587
const TYPE_SET
Определения basketitem.php:28
isReservableItem()
Определения basketitem.php:1176
isBundleParent()
Определения basketitem.php:490
static getId($skipCreate=false)
Определения fuser.php:33
static getUserIdById($fuserId)
Определения fuser.php:177
setBasketItemFields(\Bitrix\Sale\BasketItem &$item, array $fields=array())
Определения basketbuilder.php:917
isProductAvailable($basketCode, $productFormData, $productProviderData, $isProductDataNeedUpdate)
Определения basketbuilder.php:475
static isBasketItemNew($basketCode)
Определения basketbuilder.php:799
obtainCatalogProductsData(array $fields=array())
Определения basketbuilder.php:400
createItem($basketCode, &$productData)
Определения basketbuilder.php:820
setReserveDataForItem(BasketItem $item, array $reserveData)
Определения basketbuilder.php:698
setItemData($basketCode, &$productData, &$item)
Определения basketbuilder.php:815
correctVatIncludedByFirstItem(array $product, string $vatIncludedFromFirstItem)
Определения basketbuilder.php:992
checkProductData(array $productData)
Определения basketbuilder.php:84
__construct(OrderBuilder $builder)
Определения basketbuilder.php:53
getExistsItem($moduleId, $productId, array $properties=array())
Определения basketbuilder.php:154
static setUsingTrustData($value)
Определения providerbase.php:5185
static getProductData(BasketItemCollection $basketCollection, array $select=array(), BasketItem $refreshItem=null)
Определения providerbase.php:983
static setTrustData($siteId, $module, $productId, array $fields)
Определения providerbase.php:5221
$orderId
Определения payment.php:5
$new
Определения file_edit.php:48
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
$moduleId
CheckSerializedData($str, $max_depth=200)
Определения tools.php:4949
GetMessage($name, $aReplace=null)
Определения tools.php:3397
sortByColumn(array &$array, $columns, $callbacks='', $defaultValueIfNotSetValue=null, $preserveKeys=false)
Определения tools.php:5087
Определения tools.php:2
Определения basket.php:2
getErrors()
Определения errorableimplementation.php:34
$order
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$error
Определения subscription_card_product.php:20
$iterator
Определения yandex_run.php:610
$fields
Определения yandex_run.php:501