Bitrix-D7  20.5.0
basketitem.php
См. документацию.
1 <?php
2 /**
3  * Bitrix Framework
4  * @package bitrix
5  * @subpackage sale
6  * @copyright 2001-2012 Bitrix
7  */
8 namespace Bitrix\Sale;
9 
11 use Bitrix\Main;
19 
20 Loc::loadMessages(__FILE__);
21 
22 /**
23  * Class BasketItem
24  * @package Bitrix\Sale
25  */
27 {
28  const TYPE_SET = 1;
29 
30  /** @var BundleCollection */
31  private $bundleCollection = null;
32 
33  /**
34  * @return string
35  */
36  public static function getRegistryType()
37  {
39  }
40 
41  /**
42  * @return Result
43  * @throws ArgumentException
44  * @throws ArgumentNullException
45  * @throws \Exception
46  */
47  public function save()
48  {
49  $result = parent::save();
50  if (!$result->isSuccess())
51  {
52  return $result;
53  }
54 
55  if ($this->isBundleParent())
56  {
57  $bundleCollection = $this->getBundleCollection();
58  $itemsFromDb = [];
59 
60  $id = $this->getId();
61  if ($id != 0)
62  {
63  $register = Registry::getInstance(static::getRegistryType());
64  /** @var BasketBase $basketClassName */
65  $basketClassName = $register->getBasketClassName();
66 
67  $itemsFromDbList = $basketClassName::getList(
68  [
69  'select' => ['ID'],
70  'filter' => ['SET_PARENT_ID' => $id],
71  ]
72  );
73  while ($itemsFromDbItem = $itemsFromDbList->fetch())
74  {
75  if ($itemsFromDbItem['ID'] == $id)
76  continue;
77 
78  $itemsFromDb[$itemsFromDbItem['ID']] = true;
79  }
80  }
81 
82  /** @var BasketItem $bundleItem */
83  foreach ($bundleCollection as $bundleItem)
84  {
85  $parentId = (int)$bundleItem->getField('SET_PARENT_ID');
86  if ($parentId <= 0)
87  $bundleItem->setFieldNoDemand('SET_PARENT_ID', $id);
88 
89  $saveResult = $bundleItem->save();
90  if (!$saveResult->isSuccess())
91  $result->addErrors($saveResult->getErrors());
92 
93  if (isset($itemsFromDb[$bundleItem->getId()]))
94  unset($itemsFromDb[$bundleItem->getId()]);
95  }
96 
97  foreach ($itemsFromDb as $id => $value)
98  {
99  $this->deleteInternal($id);
100  }
101  }
102 
103  return $result;
104  }
105 
106  /**
107  * @return Result
108  * @throws ArgumentException
109  * @throws ArgumentNullException
110  * @throws ArgumentOutOfRangeException
111  * @throws Main\NotImplementedException
112  * @throws ObjectNotFoundException
113  */
114  protected function add()
115  {
116  $logFields = $this->getLoggedFields();
117 
118  $result = parent::add();
119 
120  /** @var BasketItemCollection $collection */
121  $collection = $this->getCollection();
122 
123  /** @var BasketBase $basket */
124  if (!$basket = $collection->getBasket())
125  {
126  throw new Main\ObjectNotFoundException('Entity "Basket" not found');
127  }
128 
129  if ($basket->getOrderId() > 0)
130  {
131  $registry = Registry::getInstance(static::getRegistryType());
132  /** @var OrderHistory $orderHistory */
133  $orderHistory = $registry->getOrderHistoryClassName();
134 
135  if (!$result->isSuccess())
136  {
137  $orderHistory::addAction(
138  'BASKET',
139  $basket->getOrderId(),
140  'BASKET_ITEM_ADD_ERROR',
141  null,
142  $this,
143  ["ERROR" => $result->getErrorMessages()]
144  );
145  }
146  else
147  {
148  $orderHistory::addLog(
149  'BASKET',
150  $basket->getOrderId(),
151  "BASKET_ITEM_ADD",
152  $this->getId(),
153  $this,
154  $logFields,
155  $orderHistory::SALE_ORDER_HISTORY_LOG_LEVEL_1
156  );
157 
158  $orderHistory::addAction(
159  'BASKET',
160  $basket->getOrderId(),
161  "BASKET_SAVED",
162  $this->getId(),
163  $this,
164  [],
165  $orderHistory::SALE_ORDER_HISTORY_ACTION_LOG_LEVEL_1
166  );
167  }
168  }
169 
170  return $result;
171  }
172 
173  /**
174  * @return Result
175  * @throws ArgumentException
176  * @throws ArgumentNullException
177  * @throws ArgumentOutOfRangeException
178  * @throws Main\NotImplementedException
179  * @throws Main\ObjectException
180  * @throws ObjectNotFoundException
181  */
182  protected function update()
183  {
184  $registry = Registry::getInstance(static::getRegistryType());
185  /** @var OrderHistory $orderHistory */
186  $orderHistory = $registry->getOrderHistoryClassName();
187 
188  /** @var BasketItemCollection $collection */
189  $collection = $this->getCollection();
190 
191  /** @var BasketBase $basket */
192  if (!$basket = $collection->getBasket())
193  {
194  throw new Main\ObjectNotFoundException('Entity "Basket" not found');
195  }
196 
197  $logFields = $this->getLoggedFields();
198 
199  $result = parent::update();
200 
201  if (!$result->isSuccess())
202  {
203  if ($basket->getOrderId() > 0)
204  {
205  $orderHistory::addAction(
206  'BASKET',
207  $basket->getOrderId(),
208  'BASKET_ITEM_UPDATE_ERROR',
209  null,
210  $this,
211  ["ERROR" => $result->getErrorMessages()]
212  );
213  }
214  }
215  else
216  {
217  $orderHistory::addLog(
218  'BASKET',
219  $basket->getOrderId(),
220  "BASKET_ITEM_UPDATE",
221  $this->getId(),
222  $this,
223  $logFields,
224  $orderHistory::SALE_ORDER_HISTORY_LOG_LEVEL_1
225  );
226 
227  $orderHistory::addAction(
228  'BASKET',
229  $basket->getOrderId(),
230  "BASKET_SAVED",
231  $this->getId(),
232  $this,
233  [],
234  $orderHistory::SALE_ORDER_HISTORY_ACTION_LOG_LEVEL_1
235  );
236  }
237 
238  return $result;
239  }
240 
241  /**
242  * @return array
243  * @throws ArgumentException
244  * @throws ArgumentNullException
245  * @throws Main\NotImplementedException
246  */
247  private function getLoggedFields()
248  {
249  /** @var Basket $basket */
250  $basket = $this->getCollection();
251 
252  $orderId = $basket->getOrderId();
253 
254  $changeMeaningfulFields = [
255  "PRODUCT_ID",
256  "QUANTITY",
257  "PRICE",
258  "DISCOUNT_VALUE",
259  "VAT_RATE",
260  "NAME",
261  ];
262 
263  $logFields = [];
264  if ($orderId > 0 && $this->isChanged())
265  {
266  $itemValues = $this->getFields();
267  $originalValues = $itemValues->getOriginalValues();
268 
269  foreach($originalValues as $originalFieldName => $originalFieldValue)
270  {
271  if (in_array($originalFieldName, $changeMeaningfulFields) && $this->getField($originalFieldName) != $originalFieldValue)
272  {
273  $logFields[$originalFieldName] = $this->getField($originalFieldName);
274  $logFields['OLD_'.$originalFieldName] = $originalFieldValue;
275  }
276  }
277  }
278 
279  return $logFields;
280  }
281 
282  /**
283  * @return Result
284  * @throws ArgumentNullException
285  * @throws ObjectNotFoundException
286  */
287  protected function checkBeforeDelete()
288  {
289  $result = new Result();
290 
291  /** @var BasketItemCollection $collection */
292  $collection = $this->getCollection();
293 
294  /** @var Basket $basket */
295  if (!$basket = $collection->getBasket())
296  {
297  throw new ObjectNotFoundException('Entity "Basket" not found');
298  }
299 
300  /** @var Order $order */
301  if ($order = $basket->getOrder())
302  {
303  /** @var ShipmentCollection $shipmentCollection */
304  if ($shipmentCollection = $order->getShipmentCollection())
305  {
306  /** @var Shipment $shipment */
307  foreach ($shipmentCollection as $shipment)
308  {
309  if ($shipment->isSystem())
310  {
311  continue;
312  }
313 
314  /** @var ShipmentItemCollection $shipmentItemCollection */
315  if ($shipmentItemCollection = $shipment->getShipmentItemCollection())
316  {
317  if ($shipmentItemCollection->getItemByBasketCode($this->getBasketCode()) && $shipment->isShipped())
318  {
319  $result->addError(
320  new ResultError(
322  'SALE_BASKET_ITEM_REMOVE_IMPOSSIBLE_BECAUSE_SHIPPED',
323  ['#PRODUCT_NAME#' => $this->getField('NAME')]
324  ),
325  'SALE_BASKET_ITEM_REMOVE_IMPOSSIBLE_BECAUSE_SHIPPED'
326  )
327  );
328 
329  return $result;
330  }
331  }
332  }
333  }
334  }
335 
336  return $result;
337  }
338 
339  /**
340  * @return Result
341  * @throws ArgumentOutOfRangeException
342  * @throws ObjectNotFoundException
343  * @throws \Exception
344  */
345  public function delete()
346  {
347  $result = new Result();
348 
349  $deleteResult = parent::delete();
350  if (!$deleteResult->isSuccess())
351  {
352  $result->addErrors($deleteResult->getErrors());
353  return $result;
354  }
355 
356  if ($this->isBundleParent())
357  {
358  $bundleCollection = $this->getBundleCollection();
359  if ($bundleCollection)
360  {
361  /** @var BasketItem $bundleItem */
362  foreach ($bundleCollection as $bundleItem)
363  {
364  $deleteResult = $bundleItem->delete();
365  if (!$deleteResult->isSuccess())
366  {
367  $result->addErrors($deleteResult->getErrors());
368  }
369  }
370  }
371  }
372 
373  return $result;
374  }
375 
376  /**
377  * @param array $fields
378  * @return array
379  * @throws Main\NotImplementedException
380  */
381  private function clearBundleItemFields(array $fields)
382  {
383  if (!empty($fields))
384  {
385  $settableFields = static::getAllFields();
386 
387  foreach ($fields as $name => $value)
388  {
389  if (!isset($settableFields[$name]))
390  {
391  unset($fields[$name]);
392  }
393  }
394  }
395 
396  return $fields;
397  }
398 
399  /**
400  * @return BasketItem|null
401  */
402  public function getParentBasketItem()
403  {
404  $collection = $this->getCollection();
405 
406  if ($collection instanceof BundleCollection)
407  {
408  return $collection->getParentBasketItem();
409  }
410 
411  return null;
412  }
413 
414  /**
415  * @return int|null|string
416  * @throws ArgumentNullException
417  */
418  public function getParentBasketItemId()
419  {
420  if ($parentBasketItem = $this->getParentBasketItem())
421  {
422  return $parentBasketItem->getId();
423  }
424  return null;
425  }
426 
427  /**
428  * @return bool
429  * @throws ArgumentNullException
430  */
431  public function isBundleParent()
432  {
433  return (int)$this->getField('TYPE') === static::TYPE_SET;
434  }
435 
436  /**
437  * @return bool
438  */
439  public function isBundleChild()
440  {
441  return $this->collection instanceof BundleCollection;
442  }
443 
444  /**
445  * @return array|bool
446  * @throws ArgumentException
447  * @throws ArgumentNullException
448  * @throws ArgumentOutOfRangeException
449  * @throws Main\ArgumentTypeException
450  * @throws Main\NotImplementedException
451  * @throws Main\ObjectException
452  * @throws ObjectNotFoundException
453  * @throws \Exception
454  */
455  public function getBundleBaseQuantity()
456  {
457  if ($this->isBundleParent())
458  {
459  /** @var BundleCollection $bundleCollection */
460  if (!($bundleCollection = $this->getBundleCollection()))
461  {
462  throw new ObjectNotFoundException('Entity "BasketBundleCollection" not found');
463  }
464 
465  $bundleChildList = [];
466  $result = [];
467 
468  $originalQuantity = $this->getQuantity();
469  $originalValues = $this->fields->getOriginalValues();
470  if (array_key_exists('QUANTITY', $originalValues) && $originalValues['QUANTITY'] !== null)
471  {
472  $originalQuantity = $originalValues['QUANTITY'];
473  }
474  /** @var BasketItem $bundleBasketItem */
475  foreach ($bundleCollection as $bundleBasketItem)
476  {
477  $originalBundleQuantity = $bundleBasketItem->getQuantity();
478  $originalBundleValues = $bundleBasketItem->getFields()->getOriginalValues();
479  if (array_key_exists('QUANTITY', $originalBundleValues) && $originalBundleValues['QUANTITY'] !== null)
480  {
481  $originalBundleQuantity = $originalBundleValues['QUANTITY'];
482  }
483 
484  if ($originalQuantity > 0)
485  {
486  $bundleQuantity = $originalBundleQuantity / $originalQuantity;
487  }
488  else
489  {
490  $bundleQuantity = 0;
491  }
492 
493  $bundleChildList[]["ITEMS"][] = [
494  "PRODUCT_ID" => $bundleBasketItem->getProductId(),
495  "QUANTITY" => $bundleQuantity
496  ];
497 
498  }
499 
500  if (empty($bundleChildList))
501  return false;
502 
503  foreach ($bundleChildList as $bundleBasketListDat)
504  {
505  foreach ($bundleBasketListDat["ITEMS"] as $bundleDat)
506  {
507  $result[$bundleDat['PRODUCT_ID']] = $bundleDat['QUANTITY'];
508  }
509  }
510 
511  return $result;
512  }
513 
514  return false;
515  }
516 
517  /**
518  * @return BundleCollection|null
519  * @throws ArgumentException
520  * @throws ArgumentNullException
521  * @throws ArgumentOutOfRangeException
522  * @throws Main\ArgumentTypeException
523  * @throws Main\NotImplementedException
524  * @throws Main\ObjectException
525  * @throws ObjectNotFoundException
526  * @throws \Exception
527  */
528  public function getBundleCollection()
529  {
530  if ($this->bundleCollection === null)
531  {
532  if ($this->getId() > 0)
533  {
534  $this->bundleCollection = $this->loadBundleCollectionFromDb();
535  }
536  else
537  {
538  $this->bundleCollection = $this->loadBundleCollectionFromProvider();
539  }
540  }
541 
542  return $this->bundleCollection;
543  }
544 
545  /**
546  * @return BundleCollection
547  * @throws ArgumentOutOfRangeException
548  * @throws \Exception
549  */
550  public function createBundleCollection()
551  {
552  if ($this->bundleCollection === null)
553  {
554  $registry = Registry::getInstance(static::getRegistryType());
555  /** @var BundleCollection $bundleClassName */
556  $bundleClassName = $registry->getBundleCollectionClassName();
557 
558  $this->bundleCollection = $bundleClassName::createBundleCollectionObject();
559  $this->bundleCollection->setParentBasketItem($this);
560 
561  $this->setField('TYPE', static::TYPE_SET);
562  }
563 
564  return $this->bundleCollection;
565  }
566 
567  /**
568  * @return BundleCollection
569  * @throws ArgumentNullException
570  * @throws ArgumentOutOfRangeException
571  * @throws \Exception
572  */
573  protected function loadBundleCollectionFromDb()
574  {
576 
577  if ($this->getId() > 0)
578  {
579  return $collection->loadFromDb(["SET_PARENT_ID" => $this->getId(), "TYPE" => false]);
580  }
581 
582  return $collection;
583  }
584 
585  /**
586  * @return BundleCollection|null
587  * @throws ArgumentException
588  * @throws ArgumentNullException
589  * @throws ArgumentOutOfRangeException
590  * @throws Main\ArgumentTypeException
591  * @throws Main\NotImplementedException
592  * @throws Main\ObjectException
593  * @throws ObjectNotFoundException
594  * @throws \Exception
595  */
596  protected function loadBundleCollectionFromProvider()
597  {
598  global $USER;
599 
600  $bundleChildList = [];
601 
602  /** @var BasketItemCollection $basket */
603  if (!$basket = $this->getCollection())
604  {
605  throw new Main\ObjectNotFoundException('Entity "Basket" not found');
606  }
607 
608  /** @var Order $order */
609  $order = $basket->getOrder();
610  if ($order)
611  {
612  $context = [
613  'SITE_ID' => $order->getSiteId(),
614  'USER_ID' => $order->getUserId(),
615  'CURRENCY' => $order->getCurrency(),
616  ];
617  }
618  else
619  {
620  $context = [
621  'SITE_ID' => SITE_ID,
622  'USER_ID' => $USER && $USER->GetID() > 0 ? $USER->GetID() : 0,
623  'CURRENCY' => CurrencyManager::getBaseCurrency(),
624  ];
625  }
626 
627  $creator = Internals\ProviderCreator::create($context);
628  $creator->addBasketItem($this);
629  $r = $creator->getBundleItems();
630  if ($r->isSuccess())
631  {
632  $resultProductListData = $r->getData();
633  if (!empty($resultProductListData['BUNDLE_LIST']))
634  {
635  $bundleChildList = $resultProductListData['BUNDLE_LIST'];
636  }
637  }
638 
639  if (empty($bundleChildList))
640  {
641  return null;
642  }
643 
644  $this->bundleCollection = $this->setItemsAfterGetBundle($bundleChildList);
645  return $this->bundleCollection;
646  }
647 
648  /**
649  * @param array $items
650  * @return BundleCollection
651  * @throws ArgumentException
652  * @throws ArgumentNullException
653  * @throws ArgumentOutOfRangeException
654  * @throws Main\ArgumentTypeException
655  * @throws Main\NotImplementedException
656  * @throws Main\ObjectException
657  * @throws \Exception
658  */
659  private function setItemsAfterGetBundle(array $items)
660  {
661  /** @var BundleCollection $bundleCollection */
662  $bundleCollection = $this->createBundleCollection();
663  foreach ($items as $providerClassName => $products)
664  {
665  foreach ($products as $productId => $bundleBasketListDat)
666  {
667  foreach ($bundleBasketListDat["ITEMS"] as $bundleDat)
668  {
669  $bundleFields = $this->clearBundleItemFields($bundleDat);
670  unset($bundleFields['ID']);
671 
672  $bundleFields['CURRENCY'] = $this->getCurrency();
673 
674  if ($this->getId() > 0)
675  {
676  $bundleFields['SET_PARENT_ID'] = $this->getId();
677  }
678 
679  /** @var BasketItem $basketItem */
680  $bundleBasketItem = static::create($bundleCollection, $bundleFields['MODULE'], $bundleFields['PRODUCT_ID']);
681 
682  if (!empty($bundleDat["PROPS"]) && is_array($bundleDat["PROPS"]))
683  {
684  /** @var BasketPropertiesCollection $property */
685  $property = $bundleBasketItem->getPropertyCollection();
686  $property->setProperty($bundleDat["PROPS"]);
687  }
688 
689  $bundleQuantity = $bundleFields['QUANTITY'] * $this->getQuantity();
690  unset($bundleFields['QUANTITY']);
691 
692  $bundleBasketItem->setFieldsNoDemand($bundleFields);
693  $bundleBasketItem->setField('QUANTITY', $bundleQuantity);
694  $bundleCollection->addItem($bundleBasketItem);
695  }
696  }
697  }
698 
699  return $bundleCollection;
700  }
701 
702  /**
703  * @param $basketCode
704  * @return BasketItemBase|null
705  * @throws ArgumentException
706  * @throws ArgumentNullException
707  * @throws ArgumentOutOfRangeException
708  * @throws Main\ArgumentTypeException
709  * @throws Main\NotImplementedException
710  * @throws Main\ObjectException
711  * @throws ObjectNotFoundException
712  * @throws \Exception
713  */
714  public function findItemByBasketCode($basketCode)
715  {
716  $item = parent::findItemByBasketCode($basketCode);
717  if ($item !== null)
718  return $item;
719 
720  if ($this->isBundleParent())
721  {
722  $collection = $this->getBundleCollection();
723  /** @var BasketItemBase $basketItem */
724  foreach ($collection as $basketItem)
725  {
726  $item = $basketItem->findItemByBasketCode($basketCode);
727  if ($item !== null)
728  return $item;
729  }
730  }
731 
732  return null;
733  }
734 
735  /**
736  * @param $id
737  * @return BasketItemBase|null
738  * @throws ArgumentException
739  * @throws ArgumentNullException
740  * @throws ArgumentOutOfRangeException
741  * @throws Main\ArgumentTypeException
742  * @throws Main\NotImplementedException
743  * @throws Main\ObjectException
744  * @throws ObjectNotFoundException
745  * @throws \Exception
746  */
747  public function findItemById($id)
748  {
749  $item = parent::findItemById($id);
750  if ($item !== null)
751  return $item;
752 
753  if ($this->isBundleParent())
754  {
755  $collection = $this->getBundleCollection();
756  /** @var BasketItemBase $basketItem */
757  foreach ($collection as $basketItem)
758  {
759  $item = $basketItem->findItemById($id);
760  if ($item !== null)
761  return $item;
762  }
763  }
764 
765  return null;
766  }
767 
768  /**
769  * @param string $name
770  * @param null $oldValue
771  * @param null $value
772  * @throws ArgumentNullException
773  * @throws ObjectNotFoundException
774  */
775  protected function addChangesToHistory($name, $oldValue = null, $value = null)
776  {
777  if ($this->getId() > 0)
778  {
779  $fields = [];
780  /** @var Basket $basket */
781  if (!$basket = $this->getCollection())
782  {
783  throw new ObjectNotFoundException('Entity "Basket" not found');
784  }
785 
786  if ($basket->getOrder() && $basket->getOrderId() > 0)
787  {
788  if ($name == "QUANTITY")
789  {
790  if (floatval($value) == 0)
791  {
792  return;
793  }
794  $fields = [
795  'PRODUCT_ID' => $this->getProductId(),
796  'QUANTITY' => $this->getQuantity(),
797  'NAME' => $this->getField('NAME'),
798  ];
799  }
800 
801  $registry = Registry::getInstance(static::getRegistryType());
802 
803  /** @var OrderHistory $orderHistory */
804  $orderHistory = $registry->getOrderHistoryClassName();
805  $orderHistory::addField(
806  'BASKET',
807  $basket->getOrderId(),
808  $name,
809  $oldValue,
810  $value,
811  $this->getId(),
812  $this,
813  $fields
814  );
815  }
816  }
817  }
818 
819  /**
820  * @param $quantity
821  * @return float|string
822  * @throws ArgumentNullException
823  * @throws ArgumentOutOfRangeException
824  */
825  public static function formatQuantity($quantity)
826  {
827  $format = Config\Option::get('sale', 'format_quantity', 'AUTO');
828  if ($format == 'AUTO' || intval($format) <= 0)
829  {
830  $quantity = round($quantity, SALE_VALUE_PRECISION);
831  }
832  else
833  {
834  $quantity = number_format($quantity, intval($format), '.', '');
835  }
836 
837  return $quantity;
838  }
839 
840  /**
841  * @return array
842  */
843  protected static function getFieldsMap()
844  {
846  }
847 
848  /**
849  * @internal
850  *
851  * @param \SplObjectStorage $cloneEntity
852  * @return BasketItem|Internals\CollectableEntity|object
853  * @throws ArgumentException
854  * @throws ArgumentNullException
855  * @throws ArgumentOutOfRangeException
856  * @throws Main\ArgumentTypeException
857  * @throws Main\NotImplementedException
858  * @throws Main\ObjectException
859  * @throws ObjectNotFoundException
860  * @throws \Exception
861  */
862  public function createClone(\SplObjectStorage $cloneEntity)
863  {
864  if ($this->isClone() && $cloneEntity->contains($this))
865  {
866  return $cloneEntity[$this];
867  }
868 
869  /** @var BasketItem $basketItemClone */
870  $basketItemClone = parent::createClone($cloneEntity);
871 
872  /** @var Internals\Fields $calculatedFields */
873  if ($calculatedFields = $this->calculatedFields)
874  {
875  $basketItemClone->calculatedFields = $calculatedFields->createClone($cloneEntity);
876  }
877 
878  if (!$cloneEntity->contains($this))
879  {
880  $cloneEntity[$this] = $basketItemClone;
881  }
882 
883  /** @var BasketPropertiesCollection $propertyCollection */
885  {
886  if (!$cloneEntity->contains($propertyCollection))
887  {
888  $cloneEntity[$propertyCollection] = $propertyCollection->createClone($cloneEntity);
889  }
890 
891  if ($cloneEntity->contains($propertyCollection))
892  {
893  $basketItemClone->propertyCollection = $cloneEntity[$propertyCollection];
894  }
895  }
896 
897  if ($this->isBundleParent())
898  {
899  /** @var BundleCollection $bundleCollection */
900  if ($bundleCollection = $this->getBundleCollection())
901  {
902  if (!$cloneEntity->contains($bundleCollection))
903  {
904  $cloneEntity[$bundleCollection] = $bundleCollection->createClone($cloneEntity);
905  }
906 
907  if ($cloneEntity->contains($bundleCollection))
908  {
909  $basketItemClone->bundleCollection = $cloneEntity[$bundleCollection];
910  }
911  }
912  }
913 
914  return $basketItemClone;
915  }
916 
917  /**
918  * @param string $name
919  * @param mixed $oldValue
920  * @param mixed $value
921  * @return Result
922  * @throws ArgumentException
923  * @throws ArgumentNullException
924  * @throws ArgumentOutOfRangeException
925  * @throws Main\LoaderException
926  * @throws Main\SystemException
927  * @throws ObjectNotFoundException
928  * @throws \Exception
929  */
930  protected function onFieldModify($name, $oldValue, $value)
931  {
932  $result = new Result();
933 
934  $r = parent::onFieldModify($name, $oldValue, $value);
935  if (!$r->isSuccess())
936  {
937  $result->addErrors($r->getErrors());
938  return $result;
939  }
940  elseif ($r->hasWarnings())
941  {
942  $result->addWarnings($r->getWarnings());
943  }
944 
945  if (!$this->isBundleParent())
946  return $result;
947 
948  if ($name === 'QUANTITY')
949  {
950  $deltaQuantity = $value - $oldValue;
951  if ($deltaQuantity != 0)
952  {
953  if ($bundleCollection = $this->getBundleCollection())
954  {
955  $bundleBaseQuantity = $this->getBundleBaseQuantity();
956 
957  /** @var BasketItemBase $bundleItem */
958  foreach ($bundleCollection as $bundleItem)
959  {
960  $bundleProductId = $bundleItem->getProductId();
961 
962  if (!isset($bundleBaseQuantity[$bundleProductId]))
963  throw new ArgumentOutOfRangeException('bundle product id');
964 
965  $quantity = $bundleBaseQuantity[$bundleProductId] * $value;
966 
967  $r = $bundleItem->setField('QUANTITY', $quantity);
968  if (!$r->isSuccess())
969  {
970  $result->addErrors($r->getErrors());
971  }
972  }
973  }
974  }
975  }
976  elseif ($name == "DELAY")
977  {
978  /** @var BundleCollection $bundleCollection */
979  if ($bundleCollection = $this->getBundleCollection())
980  {
981  /** @var BasketItemBase $bundleItem */
982  foreach ($bundleCollection as $bundleItem)
983  {
984  $r = $bundleItem->setField('DELAY', $value);
985  if (!$r->isSuccess())
986  {
987  $result->addErrors($r->getErrors());
988  }
989  }
990  }
991  }
992  elseif ($name == "CAN_BUY")
993  {
994  /** @var BundleCollection $bundleCollection */
995  if ($bundleCollection = $this->getBundleCollection())
996  {
997  /** @var BasketItemBase $bundleItem */
998  foreach ($bundleCollection as $bundleItem)
999  {
1000  $r = $bundleItem->setField('CAN_BUY', $value);
1001  if (!$r->isSuccess())
1002  {
1003  $result->addErrors($r->getErrors());
1004  }
1005  }
1006  }
1007  }
1008 
1009  return $result;
1010  }
1011 
1012  /**
1013  * @param BasketItemCollection $basket
1014  * @param $data
1015  * @return BasketItem|mixed
1016  * @throws ArgumentException
1017  * @throws ArgumentOutOfRangeException
1018  * @throws Main\ArgumentTypeException
1019  * @throws Main\NotImplementedException
1020  * @throws \Exception
1021  */
1022  public static function load(BasketItemCollection $basket, $data)
1023  {
1024  $bundleItems = [];
1025  if (isset($data['ITEMS']))
1026  {
1027  $bundleItems = $data['ITEMS'];
1028  unset($data['ITEMS']);
1029  }
1030 
1031  /** @var BasketItem $basketItem */
1032  $basketItem = parent::load($basket, $data);
1033 
1034  if ($bundleItems)
1035  {
1036  $bundleCollection = $basketItem->createBundleCollection();
1037  $bundleCollection->loadFromArray($bundleItems);
1038  }
1039 
1040  return $basketItem;
1041  }
1042 
1043  /**
1044  * @param array $fields
1045  * @return Main\Entity\AddResult
1046  * @throws \Exception
1047  */
1048  protected function addInternal(array $fields)
1049  {
1050  return Internals\BasketTable::add($fields);
1051  }
1052 
1053  /**
1054  * @param $primary
1055  * @param array $fields
1056  * @return Main\Entity\UpdateResult
1057  * @throws \Exception
1058  */
1059  protected function updateInternal($primary, array $fields)
1060  {
1061  return Internals\BasketTable::update($primary, $fields);
1062  }
1063 
1064  /**
1065  * @param $primary
1066  * @return Main\Entity\DeleteResult
1067  * @throws \Exception
1068  */
1069  protected function deleteInternal($primary)
1070  {
1072  }
1073 
1074  /**
1075  * @return float|int
1076  * @throws ArgumentNullException
1077  */
1078  public function getReservedQuantity()
1079  {
1080  $reservedQuantity = 0;
1081 
1082  /** @var BasketItemCollection $basketItemCollection */
1083  $basketItemCollection = $this->getCollection();
1084 
1085  /** @var Order $order */
1086  $order = $basketItemCollection->getOrder();
1087  if ($order)
1088  {
1089  $shipmentCollection = $order->getShipmentCollection();
1090  /** @var Shipment $shipment */
1091  foreach ($shipmentCollection as $shipment)
1092  {
1093  $shipmentItemCollection = $shipment->getShipmentItemCollection();
1094  $shipmentItem = $shipmentItemCollection->getItemByBasketCode($this->getBasketCode());
1095  if ($shipmentItem)
1096  $reservedQuantity += $shipmentItem->getReservedQuantity();
1097  }
1098  }
1099 
1100  return $reservedQuantity;
1101  }
1102 
1103 }
static getBaseCurrency()
Return base currency.
Exception is thrown when function argument is not valid.
Exception is thrown when "empty" value is passed to a function that does not accept it as a valid arg...
Exception is thrown when the value of an argument is outside the allowable range of values.
static get($moduleId, $name, $default="", $siteId=false)
Returns a value of an option.
static loadMessages($file)
Loads language messages for specified file in a lazy way.
Definition: loc.php:67
static getMessage($code, $replace=null, $language=null)
Returns translation by message code.
Definition: loc.php:29
Exception is thrown when an object is not present.
onFieldModify($name, $oldValue, $value)
Definition: basketitem.php:930
createClone(\SplObjectStorage $cloneEntity)
Definition: basketitem.php:862
static load(BasketItemCollection $basket, $data)
updateInternal($primary, array $fields)
addInternal(array $fields)
static formatQuantity($quantity)
Definition: basketitem.php:825
addChangesToHistory($name, $oldValue=null, $value=null)
Definition: basketitem.php:775
findItemByBasketCode($basketCode)
Definition: basketitem.php:714