Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
provider.php
1<?php
2
3
5
6
10
11final class Provider
12{
16
17 private static $ignoreErrors = false;
18
27 public static function getProductData($basketList, array $context)
28 {
29 $result = new Sale\Result();
30
31 if (empty($context))
32 {
33 throw new Main\ArgumentNullException('context');
34 }
35
36 if (!is_array($basketList) && !($basketList instanceof Sale\BasketBase))
37 {
38 throw new Main\ArgumentTypeException('basketList');
39 }
40
41 $creator = Sale\Internals\ProviderCreator::create($context);
43 foreach ($basketList as $basketItem)
44 {
45 $creator->addBasketItem($basketItem);
46 }
47
48 $r = $creator->getProductData();
49 if ($r->isSuccess())
50 {
51 $data = $r->getData();
52 if (array_key_exists('PRODUCT_DATA_LIST', $data))
53 {
54 $result->setData($data);
55 }
56 }
57 else
58 {
59 $result->addErrors($r->getErrors());
60 }
61
62 return $result;
63 }
64
72 public static function getBundleItems(Sale\BasketItemBase $basketItem, array $context)
73 {
74 if (empty($context))
75 {
76 throw new Main\ArgumentNullException('context');
77 }
78
79 $result = new Sale\Result();
80
81 $creator = Sale\Internals\ProviderCreator::create($context);
83 $creator->addBasketItem($basketItem);
84
85 $r = $creator->getBundleItems();
86 if ($r->isSuccess())
87 {
88 return $r;
89 }
90 else
91 {
92 $result->addErrors($r->getErrors());
93 }
94
95 return $result;
96 }
97
104 public static function getAvailableQuantityAndPriceByBasketItem(Sale\BasketItemBase $basketItem, array $context = array())
105 {
106 $result = new Sale\Result();
107
109 $basket = $basketItem->getCollection();
110
111 $order = $basket->getOrder();
112
113 if (empty($context) && !$order)
114 {
115 $context = $basket->getContext();
116 }
117
118 if (empty($context) && $order)
119 {
120 $context = self::prepareContext($order, $context);
121 }
122
123 $r = self::checkContext($context);
124 if (!$r->isSuccess())
125 {
126 return $r;
127 }
128
129 $resultData = array();
130
131 $creator = Sale\Internals\ProviderCreator::create($context);
132
134 $creator->addBasketItem($basketItem);
135
136 $r = $creator->getAvailableQuantityAndPrice();
137 if ($r->isSuccess())
138 {
139 $providerName = $basketItem->getProviderName();
140
141 if (strval($providerName) == '')
142 {
143 $providerName = $basketItem->getCallbackFunction();
144 }
145
146 $providerName = self::clearProviderName($providerName);
147
148 $checkProviderName = $providerName;
149 $data = $r->getData();
150 if (array_key_exists('PRODUCT_DATA_LIST', $data) && isset($data['PRODUCT_DATA_LIST'][$checkProviderName]))
151 {
152 $productData = $data['PRODUCT_DATA_LIST'][$checkProviderName];
153
154 if (isset($productData['PRICE_LIST'][$basketItem->getProductId()][$basketItem->getBasketCode()]))
155 {
156 $resultData['PRICE_DATA'] = $productData['PRICE_LIST'][$basketItem->getProductId()][$basketItem->getBasketCode()];
157 }
158
159 if (isset($productData['AVAILABLE_QUANTITY_LIST'][$basketItem->getProductId()]))
160 {
161 $resultData['AVAILABLE_QUANTITY'] = $productData['AVAILABLE_QUANTITY_LIST'][$basketItem->getProductId()];
162 }
163 }
164 }
165 else
166 {
167 $result->addErrors($r->getErrors());
168 }
169
170 if (isset($resultData))
171 {
172 $result->setData(
173 $resultData
174 );
175 }
176
177 return $result;
178 }
179
188 public static function tryReserveShipment(Sale\Shipment $shipment)
189 {
190 $context = self::prepareContext($shipment->getOrder());
191 $r = self::checkContext($context);
192 if (!$r->isSuccess())
193 {
194 return $r;
195 }
196
197 $shipmentItemList = [];
199 foreach ($shipment->getShipmentItemCollection() as $item)
200 {
201 $basketItem = $item->getBasketItem();
202 if ($basketItem->isReservableItem())
203 {
204 $shipmentItemList[] = $item;
205 }
206 }
207
208 return self::tryReserveShipmentItemArray($shipmentItemList, $context);
209 }
210
219 protected static function tryReserveShipmentItemArray(array $shipmentItemList, array $context)
220 {
221 $result = new Sale\Result();
222
224 $shipmentItem = current($shipmentItemList);
225 if (!$shipmentItem)
226 {
227 return $result;
228 }
229
230 $availableQuantityList = [];
231
232 $needQuantityList = self::getNeedQuantityByShipmentItemList($shipmentItemList);
233 if (!$needQuantityList)
234 {
235 return $result;
236 }
237
238 $creator = Sale\Internals\ProviderCreator::create($context);
240 foreach ($shipmentItemList as $shipmentItem)
241 {
242 $productData = $creator->createItemForReserveByShipmentItem($shipmentItem);
243 $creator->addProductData($productData);
244 }
245
246 $r = $creator->getAvailableQuantityByStore();
247 if ($r->isSuccess())
248 {
249 $data = $r->getData();
250 if (array_key_exists('AVAILABLE_QUANTITY_LIST_BY_STORE', $data))
251 {
252 $availableQuantityList = $data['AVAILABLE_QUANTITY_LIST_BY_STORE'];
253 }
254 }
255 else
256 {
257 $result->addErrors($r->getErrors());
258 }
259
260 if ($r->hasWarnings())
261 {
262 $result->addWarnings($r->getWarnings());
263 }
264
265 if (!$result->isSuccess())
266 {
267 return $result;
268 }
269
270 $applyItemsList = [];
271
272 $pool = PoolQuantity::getInstance($shipmentItem->getCollection()->getShipment()->getOrder()->getInternalId());
273
274 foreach ($availableQuantityList as $providerName => $productAvailableQuantityList)
275 {
276 $providerName = trim($providerName);
277 foreach ($productAvailableQuantityList as $productId => $quantityByStore)
278 {
279 if (array_key_exists($productId, $needQuantityList[$providerName]))
280 {
281 if (Sale\Configuration::getProductReservationCondition() !== Sale\Reservation\Configuration\ReserveCondition::ON_SHIP)
282 {
283 if (!isset($applyItemsList[$providerName][$productId]))
284 {
285 $applyItemsList[$providerName][$productId] = [];
286 }
287
288 foreach ($quantityByStore as $storeId => $quantity)
289 {
290 if ($quantity < $needQuantityList[$providerName][$productId][$storeId])
291 {
292 $poolQuantity = (float)$pool->getByStore(
294 $productId,
295 $storeId
296 );
297
298 $delta = $needQuantityList[$providerName][$productId][$storeId] - $quantity;
299
300 if ($delta < $poolQuantity)
301 {
302 $applyItemsList[$providerName][$productId][$storeId] = $needQuantityList[$providerName][$productId][$storeId];
303 }
304 elseif ($poolQuantity > 0)
305 {
306 $applyItemsList[$providerName][$productId][$storeId] = $quantity + $poolQuantity;
307 }
308 else
309 {
310 $applyItemsList[$providerName][$productId][$storeId] = $quantity;
311 }
312 }
313 else
314 {
315 $applyItemsList[$providerName][$productId][$storeId] = $quantity;
316 }
317 }
318 }
319 }
320 else
321 {
323 foreach ($shipmentItemList as $shipmentItem)
324 {
325 $basketItem = $shipmentItem->getBasketItem();
326
327 if ($basketItem->getProductId() === $productId)
328 {
329 $result->addWarning(
330 new Sale\ResultWarning(
331 Main\Localization\Loc::getMessage(
332 'SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY',
333 ['#PRODUCT_NAME#' => $basketItem->getField('NAME')]
334 ),
335 'SALE_PROVIDER_RESERVE_SHIPMENT_ITEM_WRONG_AVAILABLE_QUANTITY'
336 )
337 );
338
339 break;
340 }
341 }
342 }
343 }
344 }
345
346 if (!empty($applyItemsList))
347 {
348 $shipmentItemMap = self::createProductShipmentItemMap($shipmentItemList);
349
350 self::setQuantityAfterReserve($shipmentItemMap, $applyItemsList);
351 }
352
353 return $result;
354 }
355
365 public static function tryReserveShipmentItem(Sale\ShipmentItem $shipmentItem, array $context = array())
366 {
368 $order = $shipmentItem->getCollection()->getShipment()->getOrder();
369
370 $context = self::prepareContext($order, $context);
371 $r = self::checkContext($context);
372 if (!$r->isSuccess())
373 {
374 return $r;
375 }
376
377 return self::tryReserveShipmentItemArray([$shipmentItem], $context);
378 }
379
387 public static function tryReserve(Sale\ReserveQuantity $reserveQuantity, array $context = array())
388 {
389 $result = new Sale\Result();
390
391 $basketItem = $reserveQuantity->getCollection()->getBasketItem();
392
393 $order = $basketItem->getBasket()->getOrder();
394
395 $context = self::prepareContext($order, $context);
396 $r = self::checkContext($context);
397 if (!$r->isSuccess())
398 {
399 return $r;
400 }
401
402 $creator = Sale\Internals\ProviderCreator::create($context);
403
404 $productData = $creator->createItemForReserve($reserveQuantity);
405 $creator->addProductData($productData);
406
407 $availableQuantityList = [];
408
409 $r = $creator->getAvailableQuantityByStore();
410 if ($r->isSuccess())
411 {
412 $data = $r->getData();
413 if (array_key_exists('AVAILABLE_QUANTITY_LIST_BY_STORE', $data))
414 {
415 $availableQuantityList = $data['AVAILABLE_QUANTITY_LIST_BY_STORE'];
416 }
417 }
418 else
419 {
420 return $result->addErrors($r->getErrors());
421 }
422
423 if ($r->hasWarnings())
424 {
425 $result->addWarnings($r->getWarnings());
426 }
427
428 $pool = PoolQuantity::getInstance($order->getInternalId());
429
430 $providerName = $basketItem->getProviderName();
431 $providerName = self::clearProviderName($providerName);
432
433 $storeId = $reserveQuantity->getStoreId();
434 $availableQuantity = $availableQuantityList[$providerName][$basketItem->getProductId()][$storeId] ?? 0;
435
436 if ($availableQuantity < $productData['QUANTITY'])
437 {
438 $result->addError(
439 new Sale\ResultError(
440 Main\Localization\Loc::getMessage('SALE_PROVIDER_RESERVE_WRONG_AVAILABLE_QUANTITY'),
441 'SALE_PROVIDER_RESERVE_WRONG_AVAILABLE_QUANTITY'
442 )
443 );
444 }
445 else
446 {
447 $pool->addByStore(
449 $basketItem->getProductId(),
450 $storeId,
451 $productData['QUANTITY']
452 );
453
454 $foundItem = false;
455 $poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $basketItem->getProductId());
456 if (!empty($poolItems))
457 {
458 foreach ($poolItems as $poolItem)
459 {
460 if (
461 $poolItem instanceof Sale\ReserveQuantity
462 && $poolItem->getInternalIndex() === $reserveQuantity->getInternalIndex()
463 && $poolItem->getCollection()->getBasketItem()->getInternalIndex() === $reserveQuantity->getCollection()->getBasketItem()->getInternalIndex()
464 )
465 {
466 $foundItem = true;
467 break;
468 }
469 }
470 }
471
472 if (!$foundItem)
473 {
474 Sale\Internals\ItemsPool::add(
475 $order->getInternalId(),
476 $basketItem->getProductId(),
477 $reserveQuantity
478 );
479 }
480 }
481
482 return $result;
483 }
484
492 public static function tryUnreserveShipmentItem(Sale\ShipmentItem $shipmentItem) : Sale\Result
493 {
494 $result = new Sale\Result();
495
497 $order = $shipmentItem->getCollection()->getShipment()->getOrder();
498
499 $pool = PoolQuantity::getInstance($order->getInternalId());
500
502 $basketItem = $shipmentItem->getBasketItem();
503
504 $productId = $basketItem->getProductId();
505
506 $reservedQuantity = $shipmentItem->getReservedQuantity();
507
508 if ($reservedQuantity == 0)
509 {
510 return $result;
511 }
512
513 $pool->add(Sale\Internals\PoolQuantity::POOL_RESERVE_TYPE, $productId, -1 * $reservedQuantity);
514
515 $foundItem = false;
516 $poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $productId);
517 if (!empty($poolItems))
518 {
520 foreach ($poolItems as $poolItem)
521 {
522 if (
523 $poolItem instanceof Sale\ShipmentItem
524 && $poolItem->getInternalIndex() == $shipmentItem->getInternalIndex()
525 )
526 {
527 $foundItem = true;
528 break;
529 }
530 }
531 }
532
533 if (!$foundItem)
534 {
535 Sale\Internals\ItemsPool::add($order->getInternalId(), $productId, $shipmentItem);
536 }
537
538 $r = $shipmentItem->setField('RESERVED_QUANTITY', $shipmentItem->getReservedQuantity() + -1 * $reservedQuantity);
539 if (!$r->isSuccess())
540 {
541 $result->addErrors($r->getErrors());
542 }
543
544 return $result;
545 }
546
552 private static function getNeedQuantityByShipmentItemList(array $shipmentItemList) : array
553 {
554 $needQuantityList = [];
555
557 foreach ($shipmentItemList as $shipmentItem)
558 {
559 $quantityList = self::getNeedQuantityByShipmentItem($shipmentItem);
560 $providerName = key($quantityList);
561 $productId = key($quantityList[$providerName]);
562
563 foreach ($quantityList[$providerName][$productId] as $storeId => $quantity)
564 {
565 if (!isset($needQuantityList[$providerName][$productId][$storeId]))
566 {
567 $needQuantityList[$providerName][$productId][$storeId] = 0;
568 }
569
570 $needQuantityList[$providerName][$productId][$storeId] += $quantity;
571 }
572 }
573
574 return $needQuantityList;
575 }
576
583 private static function getNeedQuantityByShipmentItem(Sale\ShipmentItem $shipmentItem) : array
584 {
585 $basketItem = $shipmentItem->getBasketItem();
586
587 $productId = $basketItem->getProductId();
588
589 $providerName = $basketItem->getProviderName();
590 $providerName = self::clearProviderName($providerName);
591
592 $quantity = $shipmentItem->getQuantity();
593 if ($quantity == 0)
594 {
595 return [
596 $providerName => [
597 $productId => [
598 Sale\Configuration::getDefaultStoreId() => -$shipmentItem->getReservedQuantity(),
599 ],
600 ],
601 ];
602 }
603 else
604 {
605 $quantityByStore = [];
606
608 $shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
609 if ($shipmentItemStoreCollection)
610 {
612 foreach ($shipmentItemStoreCollection as $shipmentItemStore)
613 {
614 if (!isset($quantityByStore[$shipmentItemStore->getStoreId()]))
615 {
616 $quantityByStore[$shipmentItemStore->getStoreId()] = 0;
617 }
618
619 $quantityByStore[$shipmentItemStore->getStoreId()] += $shipmentItemStore->getQuantity();
620
621 $quantity -= $shipmentItemStore->getQuantity();
622 }
623 }
624
625 if ($quantity)
626 {
627 $storeId = Sale\Configuration::getDefaultStoreId();
628
629 if (!isset($quantityByStore[$storeId]))
630 {
631 $quantityByStore[$storeId] = 0;
632 }
633
634 $quantityByStore[$storeId] += $quantity;
635 }
636
637 return [
638 $providerName => [
639 $productId => $quantityByStore,
640 ],
641 ];
642 }
643 }
644
653 public static function tryUnreserveShipment(Sale\Shipment $shipment)
654 {
655 $result = new Sale\Result();
656
658 $order = $shipment->getOrder();
659
660 $pool = PoolQuantity::getInstance($order->getInternalId());
661
663 foreach ($shipment->getShipmentItemCollection() as $shipmentItem)
664 {
666 if (!$basketItem = $shipmentItem->getBasketItem())
667 {
668 continue;
669 }
670
671 if ((int)$shipmentItem->getReservedQuantity() === 0)
672 {
673 continue;
674 }
675
676 $shipmentItemReserveQuantity = $shipmentItem->getReservedQuantity();
677
679 $reserveCollection = $basketItem->getReserveQuantityCollection();
680 if (!$reserveCollection)
681 {
682 continue;
683 }
684
686 $shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
687 if ($shipmentItemStoreCollection)
688 {
690 foreach ($shipmentItemStoreCollection as $itemStore)
691 {
692 if ($shipmentItemReserveQuantity == 0)
693 {
694 break;
695 }
696
698 foreach ($reserveCollection as $reserve)
699 {
700 if ($reserve->getStoreId() !== $itemStore->getStoreId())
701 {
702 continue;
703 }
704
705 // try to guess reserved quantity on shipment item store
706 if ($shipmentItemReserveQuantity > $itemStore->getQuantity())
707 {
708 $reserveStoreQuantity = $itemStore->getQuantity();
709 }
710 else
711 {
712 $reserveStoreQuantity = $shipmentItemReserveQuantity;
713 }
714
715 if ($reserveStoreQuantity >= $reserve->getQuantity())
716 {
717 $poolQuantity = $reserve->getQuantity();
718
719 $reserve->deleteNoDemand();
720 }
721 else
722 {
723 $poolQuantity = $reserveStoreQuantity;
724
725 $reserve->setFieldNoDemand('QUANTITY', $reserve->getQuantity() - $reserveStoreQuantity);
726 }
727
728 $shipmentItemReserveQuantity -= $reserveStoreQuantity;
729 $pool->addByStore(
731 $basketItem->getProductId(),
732 $itemStore->getStoreId(),
733 -$poolQuantity
734 );
735 }
736 }
737 }
738
739
740 if ($shipmentItemReserveQuantity > 0)
741 {
742 $storeId = Sale\Configuration::getDefaultStoreId();
743
744 foreach ($reserveCollection as $reserve)
745 {
746 if ($shipmentItemReserveQuantity == 0)
747 {
748 break;
749 }
750
751 if ($reserve->getStoreId() !== $storeId)
752 {
753 continue;
754 }
755
756 if ($shipmentItemReserveQuantity >= $reserve->getQuantity())
757 {
758 $poolQuantity = $reserve->getQuantity();
759 $shipmentItemReserveQuantity -= $poolQuantity;
760
761 $reserve->deleteNoDemand();
762 }
763 else
764 {
765 $reserve->setFieldNoDemand('QUANTITY', $reserve->getQuantity() - $shipmentItemReserveQuantity);
766 $shipmentItemReserveQuantity = 0;
767
768 $poolQuantity = $shipmentItemReserveQuantity;
769 }
770
771 $pool->addByStore(
773 $basketItem->getProductId(),
774 $storeId,
775 -$poolQuantity
776 );
777 }
778 }
779
780 $shipmentItem->getFields()->set('RESERVED_QUANTITY', 0);
781
782 if (!Sale\Internals\ActionEntity::isTypeExists(
783 $order->getInternalId(),
785 )
786 )
787 {
788 Sale\Internals\ActionEntity::add(
789 $order->getInternalId(),
791 [
792 'METHOD' => 'Bitrix\Sale\Shipment::updateReservedFlag',
793 'PARAMS' => [$shipment],
794 ]
795 );
796 }
797
798 $foundItem = false;
799 $poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $basketItem->getProductId());
800 if (!empty($poolItems))
801 {
803 foreach ($poolItems as $poolItem)
804 {
805 if (
806 $poolItem instanceof Sale\ShipmentItem
807 && $poolItem->getInternalIndex() == $shipmentItem->getInternalIndex()
808 )
809 {
810 $foundItem = true;
811 break;
812 }
813 }
814 }
815
816 if (!$foundItem)
817 {
818 Sale\Internals\ItemsPool::add($order->getInternalId(), $basketItem->getProductId(), $shipmentItem);
819 }
820 }
821
822 return $result;
823 }
824
830 private static function createProductShipmentItemMap(array $shipmentItemList)
831 {
832 $result = [];
833
835 foreach ($shipmentItemList as $shipmentItem)
836 {
837 $basketItem = $shipmentItem->getBasketItem();
838
839 $providerName = self::clearProviderName($basketItem->getProviderName());
840
841 $result[$providerName][$basketItem->getProductId()][$shipmentItem->getInternalIndex()] = $shipmentItem;
842 }
843
844 return $result;
845 }
846
855 private static function setQuantityAfterReserve(array $shipmentItemMap, array $availableQuantityList)
856 {
857 $result = new Sale\Result();
858
859 foreach ($availableQuantityList as $providerName => $productsList)
860 {
861 foreach ($productsList as $productId => $reservedQuantityByStore)
862 {
863 foreach ($reservedQuantityByStore as $storeId => $reservedQuantity)
864 {
865 $r = self::setReserveQuantityByProduct($shipmentItemMap[$providerName][$productId], $storeId, $reservedQuantity);
866 if (!$r->isSuccess())
867 {
868 $result->addErrors($r->getErrors());
869 }
870 }
871 }
872 }
873
874 return $result;
875 }
876
877 private static function setReserveQuantityByProduct(array $shipmentItemList, $storeId, $quantity) : Sale\Result
878 {
879 $result = new Sale\Result();
880
881 if ($quantity == 0)
882 {
883 return $result;
884 }
885
887 foreach ($shipmentItemList as $shipmentItem)
888 {
889 $basketItem = $shipmentItem->getBasketItem();
890 if (!$basketItem->isReservableItem())
891 {
892 continue;
893 }
894
896 $reserveQuantityCollection = $basketItem->getReserveQuantityCollection();
897 if (!$reserveQuantityCollection)
898 {
899 continue;
900 }
901
902 $productId = $basketItem->getProductId();
903
905 $order = $basketItem->getBasket()->getOrder();
906
907 $pool = PoolQuantity::getInstance($order->getInternalId());
908
909 $reserve = null;
910
912 foreach ($reserveQuantityCollection as $item)
913 {
914 if ($item->getStoreId() === $storeId)
915 {
916 $reserve = $item;
917 break;
918 }
919 }
920
921 if ($reserve === null)
922 {
923 $reserve = $reserveQuantityCollection->create();
924 $reserve->setStoreId($storeId);
925 }
926
927 if ($quantity < 0)
928 {
929 $settableQuantity = $quantity;
930 if ($shipmentItem->getReservedQuantity() < $quantity)
931 {
932 $settableQuantity = $shipmentItem->getReservedQuantity();
933 }
934 }
935 else
936 {
937 $needQuantity = $basketItem->getQuantity() - $reserve->getQuantity();
938 $settableQuantity = (abs($needQuantity) >= abs($quantity)) ? $quantity : $needQuantity;
939 }
940
941 $reserve->setFieldNoDemand('QUANTITY', $reserve->getQuantity() + $settableQuantity);
942
943 self::applyReserveToShipmentItem($shipmentItem, $settableQuantity);
944
945 $quantity -= $settableQuantity;
946
947 $pool->addByStore(Sale\Internals\PoolQuantity::POOL_RESERVE_TYPE, $productId, $storeId, $settableQuantity);
948
949 $foundItem = false;
950 $poolItems = Sale\Internals\ItemsPool::get($order->getInternalId(), $productId);
951 if (!empty($poolItems))
952 {
954 foreach ($poolItems as $poolItem)
955 {
956 if (
957 $poolItem instanceof Sale\ShipmentItem
958 && $poolItem->getInternalIndex() == $shipmentItem->getInternalIndex()
959 )
960 {
961 $foundItem = true;
962 break;
963 }
964 }
965 }
966
967 if (!$foundItem)
968 {
969 Sale\Internals\ItemsPool::add($order->getInternalId(), $productId, $shipmentItem);
970 }
971 }
972
973 return $result;
974 }
975
976 protected static function applyReserveToShipmentItem(Sale\ShipmentItem $item, $quantity)
977 {
978 $item->getFields()->set('RESERVED_QUANTITY', $item->getReservedQuantity() + $quantity);
979
980 $shipment = $item->getCollection()->getShipment();
981 $order = $shipment->getOrder();
982
983 if (!Sale\Internals\ActionEntity::isTypeExists(
984 $order->getInternalId(),
986 )
987 )
988 {
989 Sale\Internals\ActionEntity::add(
990 $order->getInternalId(),
992 [
993 'METHOD' => 'Bitrix\Sale\Shipment::updateReservedFlag',
994 'PARAMS' => [$shipment],
995 ]
996 );
997 }
998
999 }
1000
1008 public static function tryShipShipment(Sale\Shipment $shipment, array $context = array())
1009 {
1010 $result = new Sale\Result();
1011
1012 $order = $shipment->getOrder();
1013
1014 $context = self::prepareContext($order, $context);
1015
1016 $pool = PoolQuantity::getInstance($order->getInternalId());
1017
1019 $shipmentItemCollection = $shipment->getShipmentItemCollection();
1020
1021 $needShipList = array();
1022 $creator = Sale\Internals\ProviderCreator::create($context);
1024 foreach ($shipmentItemCollection as $shipmentItem)
1025 {
1026 $creator->addShipmentItem($shipmentItem);
1027 }
1028
1029 $r = $creator->isNeedShip();
1030 if ($r->isSuccess())
1031 {
1032 $data = $r->getData();
1033 if (array_key_exists('IS_NEED_SHIP', $data))
1034 {
1035 $needShipList = $data['IS_NEED_SHIP'] + $needShipList;
1036 }
1037 }
1038
1039 $creator = Sale\Internals\ProviderCreator::create($context);
1041 foreach ($shipmentItemCollection as $shipmentItem)
1042 {
1043 $shipmentProductData = $creator->createItemForShip($shipmentItem, $needShipList);
1044 $creator->addProductData($shipmentProductData);
1045 }
1046
1047 $tryShipProductList = array();
1048
1049 $isIgnoreErrors = false;
1050
1051 $r = $creator->tryShip();
1052
1053 $needSetAfterResult = false;
1054 if ($r->isSuccess())
1055 {
1056 if ($r->hasWarnings())
1057 {
1058 $result->addWarnings($r->getWarnings());
1059 }
1060 else
1061 {
1062 $needSetAfterResult = true;
1063 }
1064 }
1065 else
1066 {
1067 $result->addWarnings($r->getErrors());
1068
1069 if (self::isIgnoreErrors())
1070 {
1071 $isIgnoreErrors = true;
1072 $needSetAfterResult = true;
1073 }
1074 else
1075 {
1076 $result->addErrors($r->getErrors());
1077 }
1078
1079 }
1080
1081 $data = $r->getData();
1082 if (array_key_exists('TRY_SHIP_PRODUCTS_LIST', $data))
1083 {
1084 $tryShipProductList = $data['TRY_SHIP_PRODUCTS_LIST'] + $tryShipProductList;
1085 }
1086
1087 if ($needSetAfterResult && !empty($tryShipProductList))
1088 {
1089
1090 if ($isIgnoreErrors)
1091 {
1092 foreach ($tryShipProductList as &$productList)
1093 {
1094 $productList = array_fill_keys(array_keys($productList), true);
1095 }
1096 }
1097
1098 $creator->setItemsResultAfterTryShip($pool, $tryShipProductList);
1099 }
1100
1101 return $result;
1102 }
1103
1104 public static function deliver(Sale\Shipment $shipment)
1105 {
1106 $result = new Sale\Result();
1107
1108 $order = $shipment->getOrder();
1109
1110 $context = array(
1111 'USER_ID' => $order->getUserId(),
1112 'SITE_ID' => $order->getSiteId(),
1113 );
1114
1115 $creator = Sale\Internals\ProviderCreator::create($context);
1116
1117 foreach ($shipment->getShipmentItemCollection() as $shipmentItem)
1118 {
1119 $creator->addShipmentItem($shipmentItem);
1120 }
1121
1122 $r = $creator->deliver();
1123 if ($r->isSuccess())
1124 {
1125 $r = $creator->createItemsResultAfterDeliver($r);
1126 if ($r->isSuccess())
1127 {
1128 $data = $r->getData();
1129 if (
1130 !empty($data['RESULT_AFTER_DELIVER_LIST'])
1131 && is_array($data['RESULT_AFTER_DELIVER_LIST'])
1132 )
1133 {
1134 $result->setData($data['RESULT_AFTER_DELIVER_LIST']);
1135 }
1136 }
1137 }
1138 else
1139 {
1140 $result->addErrors($r->getErrors());
1141 }
1142
1143 return $result;
1144 }
1145
1146 public static function changeProductBatchBalance(Sale\Shipment $shipment): Sale\Result
1147 {
1148 $result = new Sale\Result();
1149
1150 $order = $shipment->getOrder();
1151
1152 $context = array(
1153 'USER_ID' => $order->getUserId(),
1154 'SITE_ID' => $order->getSiteId(),
1155 );
1156
1157 $creator = Sale\Internals\ProviderCreator::create($context);
1158
1159 foreach ($shipment->getShipmentItemCollection() as $shipmentItem)
1160 {
1161 $creator->addShipmentItem($shipmentItem);
1162 }
1163
1164 $r =
1165 $shipment->isShipped()
1166 ? $creator->writeOffProductBatches()
1167 : $creator->returnProductBatches()
1168 ;
1169
1170 if (!$r->isSuccess())
1171 {
1172 $result->addErrors($r->getErrors());
1173 }
1174
1175 return $result;
1176 }
1177
1185 public static function createMapShipmentItemStoreData(Sale\ShipmentItem $shipmentItem, $needUseReserve = true)
1186 {
1187 $resultList = array();
1188
1190 $basketItem = $shipmentItem->getBasketItem();
1191 if (!$basketItem->isReservableItem())
1192 {
1193 return false;
1194 }
1195
1197 $reserveQuantityCollection = $basketItem->getReserveQuantityCollection();
1198 if (!$reserveQuantityCollection)
1199 {
1200 return false;
1201 }
1202
1203 $reserveQuantityStoreList = [];
1204
1205 $countBarcode = 0;
1206
1208 $shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
1209 if ($shipmentItemStoreCollection)
1210 {
1212 foreach ($shipmentItemStoreCollection as $shipmentItemStore)
1213 {
1214 $productId = $basketItem->getProductId();
1215
1216 $storeId = $shipmentItemStore->getStoreId();
1217
1218 if (!isset($reserveQuantityStoreList[$storeId]))
1219 {
1220 $reserveQuantityStoreList[$storeId] = $reserveQuantityCollection->getQuantityByStoreId($shipmentItemStore->getStoreId());
1221 }
1222
1223 if (!isset($resultList[$storeId]))
1224 {
1225 $resultList[$storeId] = [
1226 'PRODUCT_ID' => $productId,
1227 'QUANTITY' => 0,
1228 'RESERVED_QUANTITY' => 0,
1229 'STORE_ID' => $storeId,
1230 'IS_BARCODE_MULTI' => $basketItem->isBarcodeMulti(),
1231 'BARCODE' => [],
1232 ];
1233 }
1234
1235 $barcodeId = ($shipmentItemStore->getId() > 0)? $shipmentItemStore->getId() : 'n'.$countBarcode;
1236 $countBarcode++;
1237 $resultList[$storeId]['QUANTITY'] += $basketItem->isBarcodeMulti()? 1 : $shipmentItemStore->getQuantity();
1238 $resultList[$storeId]['BARCODE'][$barcodeId] = $shipmentItemStore->getBarcode();
1239
1240 if ($needUseReserve)
1241 {
1242 if ($reserveQuantityStoreList[$storeId] > $resultList[$storeId]['QUANTITY'])
1243 {
1244 $resultList[$storeId]['RESERVED_QUANTITY'] = $resultList[$storeId]['QUANTITY'];
1245 }
1246 elseif ($reserveQuantityStoreList[$storeId] > 0)
1247 {
1248 $resultList[$storeId]['RESERVED_QUANTITY'] = $reserveQuantityStoreList[$storeId];
1249 }
1250
1251 $reserveQuantityStoreList[$storeId] -= $resultList[$storeId]['RESERVED_QUANTITY'];
1252 }
1253 }
1254 }
1255
1256 return $resultList;
1257 }
1258
1267 public static function createMapShipmentItemCollectionStoreData($shipmentItemList)
1268 {
1269 $resultList = array();
1270
1272 foreach ($shipmentItemList as $shipmentItem)
1273 {
1274 $basketCode = $shipmentItem->getBasketCode();
1275
1276 if (!isset($resultList[$basketCode]))
1277 {
1278 $resultList[$basketCode] = array();
1279 }
1280
1281 $map = self::createMapShipmentItemStoreData($shipmentItem);
1282 if (!empty($map) && is_array($map))
1283 {
1284 $resultList[$basketCode] = $map + $resultList[$basketCode];
1285 }
1286 }
1287
1288 return $resultList;
1289 }
1290
1291
1299 public static function save(Sale\Order $order, array $context = array())
1300 {
1301 $result = new Sale\Result();
1302
1303 $context = self::prepareContext($order, $context);
1304
1305 $r = self::checkContext($context);
1306 if (!$r->isSuccess())
1307 {
1308 $result->addErrors($r->getErrors());
1309 return $result;
1310 }
1311
1312 $pool = PoolQuantity::getInstance($order->getInternalId());
1313
1314 $rulesMap = Sale\Internals\ShipmentRules::createOrderRuleMap($order, $pool);
1315
1316 if (empty($rulesMap))
1317 {
1318 return $result;
1319 }
1320
1321 $r = Sale\Internals\ShipmentRules::saveRules($rulesMap, $context);
1322 if (!$r->isSuccess())
1323 {
1324 $result->addErrors($r->getErrors());
1325 }
1326
1327 if ($r->hasWarnings())
1328 {
1329 $result->addWarnings($r->getWarnings());
1330 }
1331
1333 $pool->reset(PoolQuantity::POOL_RESERVE_TYPE);
1334
1335 return $result;
1336 }
1337
1344 private static function prepareContext(Sale\OrderBase $order, array $context = array())
1345 {
1346 if (empty($context))
1347 {
1348 $context = [
1349 'SITE_ID' => $order->getSiteId(),
1350 'USER_ID' => $order->getUserId(),
1351 'CURRENCY' => $order->getCurrency(),
1352 ];
1353 }
1354
1355 if (!empty($context))
1356 {
1357 if (empty($context['SITE_ID']))
1358 {
1359 $context['SITE_ID'] = $order->getSiteId();
1360 }
1361
1362 if (empty($context['USER_ID']) && $order->getUserId() > 0)
1363 {
1364 $context['USER_ID'] = $order->getUserId();
1365 }
1366
1367 if (empty($context['CURRENCY']))
1368 {
1369 $context['CURRENCY'] = $order->getCurrency();
1370 }
1371 }
1372
1373 return $context;
1374 }
1375
1382 private static function checkContext(array $context)
1383 {
1384 $result = new Sale\Result();
1385
1386 if (empty($context['SITE_ID']))
1387 {
1388 throw new Main\ArgumentNullException('SITE_ID');
1389 }
1390
1391 if (empty($context['CURRENCY']))
1392 {
1393 throw new Main\ArgumentNullException('CURRENCY');
1394 }
1395
1396 return $result;
1397 }
1398
1406 public static function getProviderName($module, $name)
1407 {
1408 static $providerProxy = array();
1409 $code = $module."|".$name;
1410
1411 if (array_key_exists($code, $providerProxy))
1412 {
1413 return $providerProxy[$code];
1414 }
1415
1416 $providerName = null;
1417 if (strval($module) != '' && Main\Loader::includeModule($module) && class_exists($name))
1418 {
1419 $provider = self::getProviderEntity($name);
1420 if ($provider)
1421 {
1422 $providerName = $name;
1423 }
1424 }
1425
1426 if ($providerName !== null)
1427 {
1428 $providerProxy[$code] = $providerName;
1429 }
1430
1431 return $providerName;
1432 }
1433
1439 public static function getProviderEntity($name)
1440 {
1441 static $providerEntityProxy = array();
1442 if (array_key_exists($name, $providerEntityProxy))
1443 {
1444 return $providerEntityProxy[$name];
1445 }
1446
1447 if (
1448 class_exists($name)
1449 && (
1450 is_subclass_of($name, Sale\SaleProviderBase::class)
1451 || is_subclass_of($name, \IBXSaleProductProvider::class)
1452 )
1453 )
1454 {
1455 $providerEntityProxy[$name] = new $name();
1456 return $providerEntityProxy[$name];
1457 }
1458
1459 return null;
1460 }
1461
1462
1468 private static function clearProviderName($providerName)
1469 {
1470 if (empty($providerName) || !is_string($providerName))
1471 {
1472 return '';
1473 }
1474
1475 if (mb_substr($providerName, 0, 1) === "\\")
1476 {
1477 $providerName = mb_substr($providerName, 1);
1478 }
1479
1480 return trim($providerName);
1481 }
1482
1487 public static function setIgnoreErrors($value)
1488 {
1489 self::$ignoreErrors = ($value === true);
1490 }
1491
1496 public static function isIgnoreErrors()
1497 {
1498 return self::$ignoreErrors;
1499 }
1500
1501}
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getProviderName($module, $name)
static applyReserveToShipmentItem(Sale\ShipmentItem $item, $quantity)
Definition provider.php:976
static tryReserve(Sale\ReserveQuantity $reserveQuantity, array $context=array())
Definition provider.php:387
static changeProductBatchBalance(Sale\Shipment $shipment)
static deliver(Sale\Shipment $shipment)
static save(Sale\Order $order, array $context=array())