Bitrix-D7  20.5.0
basketbase.php
См. документацию.
1 <?php
2 namespace Bitrix\Sale;
3 
4 use Bitrix\Main;
9 
10 Loc::loadMessages(__FILE__);
11 
12 /**
13  * Class BasketBase
14  * @package Bitrix\Sale
15  */
16 abstract class BasketBase extends BasketItemCollection
17 {
18  /** @var string */
19  protected $siteId = null;
20 
21  /** @var int */
22  protected $fUserId = null;
23 
24  /** @var OrderBase */
25  protected $order = null;
26 
27  /** @var array $basketItemIndexMap */
28  protected $basketItemIndexMap = array();
29 
30  /** @var int $maxItemSort */
31  protected $maxItemSort = null;
32 
33  /** @var bool $isLoadForFUserId */
34  private $isLoadForFUserId = false;
35 
36  /** @var bool $isSaveExecuting */
37  protected $isSaveExecuting = false;
38 
39  /**
40  * @param $code
41  * @return BasketItemBase|null
42  * @throws Main\ArgumentNullException
43  * @throws Main\ArgumentNullException
44  */
45  public function getItemByBasketCode($code)
46  {
47  if (
48  isset($this->basketItemIndexMap[$code])
49  && isset($this->collection[$this->basketItemIndexMap[$code]])
50  )
51  {
52  return $this->collection[$this->basketItemIndexMap[$code]];
53  }
54 
55  return parent::getItemByBasketCode($code);
56  }
57 
58  /**
59  * @param BasketItemBase $item
60  * @return BasketItemBase|null
61  * @throws Main\ArgumentException
62  * @throws Main\ArgumentNullException
63  * @throws Main\NotImplementedException
64  */
65  public function getExistsItemByItem(BasketItemBase $item)
66  {
67  $propertyList = [];
68  $propertyCollection = $item->getPropertyCollection();
69  if ($propertyCollection)
70  {
71  $propertyList = $propertyCollection->getPropertyValues();
72  }
73 
74  return $this->getExistsItem($item->getField('MODULE'), $item->getField('PRODUCT_ID'), $propertyList);
75  }
76 
77 
78  /**
79  * @return OrderBase
80  */
81  protected function getEntityParent()
82  {
83  return $this->getOrder();
84  }
85 
86  /**
87  * @return BasketBase
88  * @throws Main\ArgumentException
89  * @throws Main\NotImplementedException
90  */
91  private static function createBasketObject()
92  {
93  $registry = Registry::getInstance(static::getRegistryType());
94  $basketClassName = $registry->getBasketClassName();
95 
96  return new $basketClassName;
97  }
98 
99  /**
100  * @param $fUserId
101  * @param $siteId
102  * @return BasketBase
103  * @throws Main\ArgumentException
104  * @throws Main\ArgumentTypeException
105  * @throws Main\NotImplementedException
106  */
107  public static function loadItemsForFUser($fUserId, $siteId)
108  {
109  /** @var BasketBase $basket */
110  $basket = static::create($siteId);
111 
112  $basket->setFUserId($fUserId);
113 
114  $basket->isLoadForFUserId = true;
115 
116  /** @var BasketBase $collection */
117  return $basket->loadFromDb([
118  "FUSER_ID" => $fUserId,
119  "=LID" => $siteId,
120  "ORDER_ID" => null
121  ]);
122  }
123 
124  /**
125  * @param array $filter
126  * @return BasketBase
127  * @throws Main\ArgumentException
128  * @throws Main\ArgumentTypeException
129  * @throws Main\NotImplementedException
130  */
131  protected function loadFromDb(array $filter)
132  {
133  $select = [
134  "ID", "LID", "MODULE", "PRODUCT_ID", "QUANTITY", "WEIGHT",
135  "DELAY", "CAN_BUY", "PRICE", "CUSTOM_PRICE", "BASE_PRICE",
136  'PRODUCT_PRICE_ID', 'PRICE_TYPE_ID', "CURRENCY", 'BARCODE_MULTI',
137  "RESERVED", "RESERVE_QUANTITY", "NAME", "CATALOG_XML_ID",
138  "VAT_RATE", "NOTES", "DISCOUNT_PRICE","PRODUCT_PROVIDER_CLASS",
139  "CALLBACK_FUNC", "ORDER_CALLBACK_FUNC", "PAY_CALLBACK_FUNC",
140  "CANCEL_CALLBACK_FUNC", "DIMENSIONS", "TYPE", "SET_PARENT_ID",
141  "DETAIL_PAGE_URL", "FUSER_ID", 'MEASURE_CODE', 'MEASURE_NAME',
142  'ORDER_ID', 'DATE_INSERT', 'DATE_UPDATE', 'PRODUCT_XML_ID',
143  'SUBSCRIBE', 'RECOMMENDATION', 'VAT_INCLUDED', 'SORT',
144  'DATE_REFRESH', 'DISCOUNT_NAME', 'DISCOUNT_VALUE', 'DISCOUNT_COUPON',
145  'XML_ID', 'MARKING_CODE_GROUP'
146  ];
147 
148  $itemList = [];
149  $first = true;
150 
151  $res = static::getList([
152  "select" => $select,
153  "filter" => $filter,
154  "order" => ['SORT' => 'ASC', 'ID' => 'ASC'],
155  ]);
156  while ($item = $res->fetch())
157  {
158  if ($first)
159  {
160  $this->setSiteId($item['LID']);
161  $this->setFUserId($item['FUSER_ID']);
162  $first = false;
163  }
164 
165  $itemList[$item['ID']] = $item;
166  }
167 
168  foreach ($itemList as $id => $item)
169  {
170  if ($item['SET_PARENT_ID'] > 0)
171  {
172  $itemList[$item['SET_PARENT_ID']]['ITEMS'][$id] = &$itemList[$id];
173  }
174  }
175 
176  $result = [];
177  foreach ($itemList as $id => $item)
178  {
179  if ($item['SET_PARENT_ID'] == 0)
180  {
181  $result[$id] = $item;
182  }
183  }
184 
185  $this->loadFromArray($result);
186 
187  return $this;
188  }
189 
190  /**
191  * Attach to the essence of the object of the order basket
192  *
193  * @param OrderBase $order - object of the order
194  */
195  public function setOrder(OrderBase $order)
196  {
197  $this->order = $order;
198  }
199 
200  /**
201  * Getting the object of the order
202  *
203  * @return OrderBase
204  */
205  public function getOrder()
206  {
207  return $this->order;
208  }
209 
210 
211  /**
212  * @param BasketItemBase $item
213  * @throws Main\ArgumentNullException
214  * @throws Main\ArgumentOutOfRangeException
215  */
216  protected function verifyItemSort(BasketItemBase $item)
217  {
218  $itemSort = (int)$item->getField('SORT') ?: 100;
219 
220  if ($this->maxItemSort === null)
221  {
222  $this->maxItemSort = $itemSort;
223  }
224  else
225  {
226  if ($itemSort > $this->maxItemSort)
227  {
228  $this->maxItemSort = $itemSort;
229  }
230  else
231  {
232  $this->maxItemSort += 100 + $this->maxItemSort % 100;
233  }
234  }
235 
236  $item->setFieldNoDemand('SORT', $this->maxItemSort);
237  }
238 
239  /**
240  * @param $siteId
241  * @return BasketBase
242  * @throws Main\ArgumentException
243  * @throws Main\NotImplementedException
244  */
245  public static function create($siteId)
246  {
247  $basket = static::createBasketObject();
248  $basket->setSiteId($siteId);
249 
250  return $basket;
251  }
252 
253  /**
254  * Getting basket price with discounts and taxes
255  *
256  * @return float
257  * @throws Main\ArgumentNullException
258  */
259  public function getPrice()
260  {
261  $orderPrice = 0;
262 
263  /** @var BasketItemBase $basketItem */
264  foreach ($this->collection as $basketItem)
265  {
266  $orderPrice += $basketItem->getFinalPrice();
267  }
268 
269  return $orderPrice;
270  }
271 
272  /**
273  * Getting basket price without discounts
274  *
275  * @return float
276  * @throws Main\ArgumentNullException
277  */
278  public function getBasePrice()
279  {
280  $orderPrice = 0;
281 
282  /** @var BasketItemBase $basketItem */
283  foreach ($this->collection as $basketItem)
284  {
285  $orderPrice += PriceMaths::roundPrecision($basketItem->getBasePriceWithVat() * $basketItem->getQuantity());
286  }
287 
288  return $orderPrice;
289  }
290 
291  /**
292  * Getting the value of the tax basket
293  *
294  * @return float
295  * @throws Main\ArgumentNullException
296  */
297  public function getVatSum()
298  {
299  $vatSum = 0;
300 
301  /** @var BasketItemBase $basketItem */
302  foreach ($this->collection as $basketItem)
303  {
304  // BasketItem that is removed is not involved
305  if ($basketItem->getQuantity() == 0)
306  {
307  continue;
308  }
309 
310  $vatSum += $basketItem->getVat();
311  }
312 
313  return $vatSum;
314  }
315 
316  /**
317  * Getting the value of the tax rate basket
318  *
319  * @return float
320  * @throws Main\ArgumentNullException
321  */
322  public function getVatRate()
323  {
324  $vatRate = 0;
325 
326  /** @var BasketItemBase $basketItem */
327  foreach ($this->collection as $basketItem)
328  {
329  // BasketItem that is removed is not involved
330  if ($basketItem->getQuantity() == 0)
331  {
332  continue;
333  }
334 
335  if ($basketItem->getVatRate() > $vatRate)
336  {
337  $vatRate = $basketItem->getVatRate();
338  }
339  }
340 
341  return $vatRate;
342  }
343 
344  /**
345  * @return Result
346  * @throws Main\ArgumentException
347  * @throws Main\NotImplementedException
348  * @throws Main\ObjectNotFoundException
349  */
350  public function verify()
351  {
352  $result = new Result();
353 
354  /** @var BasketItemBase $basketItem */
355  foreach ($this->collection as $basketItem)
356  {
357  $r = $basketItem->verify();
358  if (!$r->isSuccess())
359  {
360  $result->addErrors($r->getErrors());
361 
362  /** @var OrderBase $order */
363  if ($order = $this->getOrder())
364  {
365  $registry = Registry::getInstance(static::getRegistryType());
366 
367  /** @var EntityMarker $entityMarker */
368  $entityMarker = $registry->getEntityMarkerClassName();
369  $entityMarker::addMarker($order, $basketItem, $r);
370  $order->setField('MARKED', 'Y');
371  }
372  }
373  }
374 
375  return $result;
376  }
377 
378  /**
379  * Getting the weight basket
380  *
381  * @return int
382  */
383  public function getWeight()
384  {
385  $orderWeight = 0;
386 
387  /** @var BasketItemBase $basketItem */
388  foreach ($this->collection as $basketItem)
389  {
390  $orderWeight += $basketItem->getWeight() * $basketItem->getQuantity();
391  }
392 
393  return $orderWeight;
394  }
395 
396  /**
397  * @return array
398  */
399  private function getOriginalItemsValues()
400  {
401  $result = array();
402 
403  /** @var Order $order */
404  $order = $this->getOrder();
405  $isNew = $order && $order->isNew();
406 
407  $filter = array();
408  if (!$isNew && $order && $order->getId() > 0)
409  {
410  $filter['ORDER_ID'] = $order->getId();
411  }
412  else
413  {
414  if ($this->isLoadForFUserId)
415  {
416  $filter = array(
417  'FUSER_ID' => $this->getFUserId(),
418  'ORDER_ID' => null,
419  'LID' => $this->getSiteId()
420  );
421  }
422 
423  if ($isNew)
424  {
425  $fUserId = $this->getFUserId(true);
426  if ($fUserId <= 0)
427  {
428  $userId = $order->getUserId();
429  if (intval($userId) > 0)
430  {
431  $fUserId = Fuser::getIdByUserId($userId);
432  if ($fUserId > 0)
433  $this->setFUserId($fUserId);
434  }
435  }
436  }
437  }
438 
439  if ($filter)
440  {
441  $dbRes = static::getList(
442  array(
443  "select" => array("ID", 'TYPE', 'SET_PARENT_ID', 'PRODUCT_ID', 'NAME', 'QUANTITY', 'FUSER_ID', 'ORDER_ID'),
444  "filter" => $filter,
445  )
446  );
447 
448  while ($item = $dbRes->fetch())
449  {
450  if ((int)$item['SET_PARENT_ID'] > 0 && (int)$item['SET_PARENT_ID'] != $item['ID'])
451  {
452  continue;
453  }
454 
455  $result[$item["ID"]] = $item;
456  }
457  }
458 
459  return $result;
460  }
461 
462  /**
463  * @param array $itemValues
464  * @return Result
465  */
466  abstract protected function deleteInternal(array $itemValues);
467 
468  /**
469  * Save basket
470  *
471  * @return Result
472  * @throws Main\ArgumentException
473  * @throws Main\ArgumentNullException
474  * @throws Main\NotImplementedException
475  * @throws Main\ObjectNotFoundException
476  */
477  public function save()
478  {
479  $result = new Result();
480 
481  $this->isSaveExecuting = true;
482 
483  /** @var OrderBase $order */
484  $order = $this->getOrder();
485  if (!$order)
486  {
487  $r = $this->verify();
488  if (!$r->isSuccess())
489  {
490  return $result->addErrors($r->getErrors());
491  }
492 
493  $r = $this->callEventOnSaleBasketBeforeSaved();
494  if (!$r->isSuccess())
495  {
496  $this->isSaveExecuting = false;
497 
498  return $result->addErrors($r->getErrors());
499  }
500  }
501 
502  $originalItemsValues = $this->getOriginalItemsValues();
503 
504  /** @var BasketItemBase $basketItem */
505  foreach ($this->collection as $basketItem)
506  {
507  $r = $basketItem->save();
508  if (!$r->isSuccess())
509  {
510  $result->addErrors($r->getErrors());
511  }
512 
513  if (isset($originalItemsValues[$basketItem->getId()]))
514  {
515  unset($originalItemsValues[$basketItem->getId()]);
516  }
517  }
518 
519  if ($originalItemsValues)
520  {
521  foreach ($originalItemsValues as $id => $itemValues)
522  {
523  $this->callEventOnBeforeSaleBasketItemDeleted($itemValues);
524 
525  $this->deleteInternal($itemValues);
526 
527  $this->callEventOnSaleBasketItemDeleted($itemValues);
528  }
529  }
530 
531  if (!$order)
532  {
533  $r = $this->callEventOnSaleBasketSaved();
534  if (!$r->isSuccess())
535  {
536  $result->addErrors($r->getErrors());
537  }
538  }
539 
540  $this->clearChanged();
541 
542  $this->isSaveExecuting = false;
543 
544  return $result;
545  }
546 
547  /**
548  * @param $itemValues
549  * @return void
550  */
551  private function callEventOnBeforeSaleBasketItemDeleted($itemValues)
552  {
553  $itemValues['ENTITY_REGISTRY_TYPE'] = static::getRegistryType();
554 
555  /** @var Main\Event $event */
556  $event = new Main\Event('sale', "OnBeforeSaleBasketDeleted", array('VALUES' => $itemValues));
557  $event->send();
558  }
559 
560  /**
561  * @param $itemValues
562  * @return void
563  */
564  protected function callEventOnSaleBasketItemDeleted($itemValues)
565  {
566  $itemValues['ENTITY_REGISTRY_TYPE'] = static::getRegistryType();
567 
568  /** @var Main\Event $event */
569  $event = new Main\Event('sale', "OnSaleBasketDeleted", array('VALUES' => $itemValues));
570  $event->send();
571  }
572 
573  /**
574  * @return Result
575  */
576  protected function callEventOnSaleBasketBeforeSaved()
577  {
578  $result = new Result();
579 
580  /** @var Main\Entity\Event $event */
581  $event = new Main\Event(
582  'sale',
584  array('ENTITY' => $this)
585  );
586  $event->send();
587 
588  if ($event->getResults())
589  {
590  /** @var Main\EventResult $eventResult */
591  foreach ($event->getResults() as $eventResult)
592  {
593  if ($eventResult->getType() == Main\EventResult::ERROR)
594  {
595  $errorMsg = new ResultError(
596  Main\Localization\Loc::getMessage('SALE_EVENT_ON_BEFORE_BASKET_SAVED'),
597  'SALE_EVENT_ON_BEFORE_BASKET_SAVED'
598  );
599  if ($eventResultData = $eventResult->getParameters())
600  {
601  if (isset($eventResultData) && $eventResultData instanceof ResultError)
602  {
603  /** @var ResultError $errorMsg */
604  $errorMsg = $eventResultData;
605  }
606  }
607 
608  $result->addError($errorMsg);
609  }
610  }
611  }
612 
613  return $result;
614  }
615 
616  /**
617  * @return Result
618  */
619  protected function callEventOnSaleBasketSaved()
620  {
621  $result = new Result();
622 
623  /** @var Main\Entity\Event $event */
624  $event = new Main\Event('sale', EventActions::EVENT_ON_BASKET_SAVED, array(
625  'ENTITY' => $this
626  ));
627  $event->send();
628 
629  if ($event->getResults())
630  {
631  /** @var Main\EventResult $eventResult */
632  foreach($event->getResults() as $eventResult)
633  {
634  if($eventResult->getType() == Main\EventResult::ERROR)
635  {
636  $errorMsg = new ResultError(
637  Main\Localization\Loc::getMessage('SALE_EVENT_ON_BASKET_SAVED'),
638  'SALE_EVENT_ON_BASKET_SAVED'
639  );
640  if ($eventResultData = $eventResult->getParameters())
641  {
642  if (isset($eventResultData) && $eventResultData instanceof ResultError)
643  {
644  /** @var ResultError $errorMsg */
645  $errorMsg = $eventResultData;
646  }
647  }
648 
649  $result->addError($errorMsg);
650  }
651  }
652  }
653 
654  return $result;
655  }
656 
657  /**
658  * Setting Customer ID to basket
659  *
660  * @param $fUserId - customer ID
661  */
662  public function setFUserId($fUserId)
663  {
664  $this->fUserId = (int)$fUserId > 0 ? (int)$fUserId : null;
665  }
666 
667  /**
668  * Setting site ID to basket
669  *
670  * @param $siteId - site ID
671  */
672  protected function setSiteId($siteId)
673  {
674  $this->siteId = $siteId;
675  }
676 
677  /**
678  * Getting Customer ID
679  *
680  * @param bool $skipCreate - Creating a buyer if it is not found
681  * @return int|null
682  */
683  public function getFUserId($skipCreate = false)
684  {
685  if ($this->fUserId === null)
686  {
687  $this->fUserId = Fuser::getId($skipCreate);
688  }
689  return $this->fUserId;
690  }
691 
692  /**
693  * Getting Site ID
694  *
695  * @return string
696  */
697  public function getSiteId()
698  {
699  return $this->siteId;
700  }
701 
702  /**
703  * @param array $parameters
704  * @throws Main\NotImplementedException
705  * @return mixed
706  */
707  public static function getList(array $parameters = array())
708  {
709  throw new Main\NotImplementedException();
710  }
711 
712  /**
713  * @param Internals\CollectableEntity $item
714  * @param null $name
715  * @param null $oldValue
716  * @param null $value
717  * @return Result
718  * @throws Main\ArgumentTypeException
719  */
720  public function onItemModify(Internals\CollectableEntity $item, $name = null, $oldValue = null, $value = null)
721  {
722  if (!($item instanceof BasketItemBase))
723  throw new Main\ArgumentTypeException($item);
724 
725  $result = new Result();
726 
727  /** @var OrderBase $order */
728  if ($order = $this->getOrder())
729  {
730  $r = $order->onBasketModify(EventActions::UPDATE, $item, $name, $oldValue, $value);
731  if (!$r->isSuccess())
732  {
733  $result->addErrors($r->getErrors());
734  }
735  elseif ($r->hasWarnings())
736  {
737  $result->addWarnings($r->getWarnings());
738  }
739  }
740 
741  return $result;
742  }
743 
744  /**
745  * @param RefreshStrategy|null $strategy
746  * @return Result
747  */
748  public function refresh(RefreshStrategy $strategy = null)
749  {
750  $isStartField = $this->isStartField();
751 
752  /** @var OrderBase $order */
753  $order = $this->getOrder();
754  if ($order)
755  {
756  $r = $order->onBeforeBasketRefresh();
757  if (!$r->isSuccess())
758  {
759  return $r;
760  }
761  }
762 
763  if ($strategy === null)
764  {
765  $strategy = RefreshFactory::create();
766  }
767 
768  $result = $strategy->refresh($this);
769 
770  if ($order)
771  {
772  $r = $order->onAfterBasketRefresh();
773  if (!$r->isSuccess())
774  {
775  return $r;
776  }
777  }
778 
779  $changedBasketItems = $result->get('CHANGED_BASKET_ITEMS');
780  if (!empty($changedBasketItems))
781  {
782  /** @var OrderBase $order */
783  $order = $this->getOrder();
784  if ($order)
785  {
786  $r = $order->refreshData(array('PRICE', 'PRICE_DELIVERY'));
787  if (!$r->isSuccess())
788  {
789  $result->addErrors($r->getErrors());
790  }
791  }
792  }
793 
794  if ($isStartField)
795  {
796  $hasMeaningfulFields = $this->hasMeaningfulField();
797 
798  /** @var Result $r */
799  $r = $this->doFinalAction($hasMeaningfulFields);
800  if (!$r->isSuccess())
801  {
802  $result->addErrors($r->getErrors());
803  }
804  }
805 
806  return $result;
807  }
808 
809  /**
810  * @return BasketBase
811  * @throws Main\ArgumentNullException
812  */
813  public function getOrderableItems()
814  {
815  /** @var BasketBase $basket */
816  $basket = static::create($this->getSiteId());
817 
818  if ($this->isLoadForFUserId)
819  {
820  $basket->setFUserId($this->getFUserId(true));
821  }
822 
823  if ($order = $this->getOrder())
824  {
825  $basket->setOrder($order);
826  }
827 
828  $sortedCollection = $this->collection;
829  usort($sortedCollection, function(BasketItemBase $a, BasketItemBase $b){
830  return (int)$a->getField('SORT') - (int)$b->getField('SORT');
831  });
832 
833  /** @var BasketItemBase $item */
834  foreach ($sortedCollection as $item)
835  {
836  if (!$item->canBuy() || $item->isDelay())
837  continue;
838 
839  $item->setCollection($basket);
840  $basket->addItem($item);
841  }
842 
843  return $basket;
844  }
845 
846  /**
847  * @return BasketBase
848  */
849  public function getBasket()
850  {
851  return $this;
852  }
853 
854  /**
855  * @param $idOrder
856  * @throws Main\NotImplementedException
857  * @return Result
858  */
859  public static function deleteNoDemand($idOrder)
860  {
861  throw new Main\NotImplementedException();
862  }
863 
864  /**
865  * @return bool
866  */
867  public function isSaveRunning()
868  {
869  return $this->isSaveExecuting;
870  }
871 
872  /**
873  * @return array
874  * @throws Main\ArgumentException
875  * @throws Main\LoaderException
876  */
877  public function getContext()
878  {
879  $context = array();
880 
881  $order = $this->getOrder();
882  /** @var OrderBase $order */
883  if ($order)
884  {
885  $context['USER_ID'] = $order->getUserId();
886  $context['SITE_ID'] = $order->getSiteId();
887  $context['CURRENCY'] = $order->getCurrency();
888  }
889  else
890  {
891  $context = parent::getContext();
892  }
893 
894  return $context;
895  }
896 
897  /**
898  * Getting a list of a count of elements in the basket
899  *
900  * @return array
901  * @throws Main\ArgumentNullException
902  */
903  public function getQuantityList()
904  {
905  $quantityList = array();
906 
907  /**
908  * @var $basketKey
909  * @var BasketItemBase $basketItem
910  */
911  foreach ($this->collection as $basketKey => $basketItem)
912  {
913  $quantityList[$basketItem->getBasketCode()] = $basketItem->getQuantity();
914  }
915 
916  return $quantityList;
917  }
918 
919  /**
920  * @internal
921  *
922  * @param $index
923  * @return mixed
924  * @throws Main\ArgumentOutOfRangeException
925  * @throws Main\NotImplementedException
926  * @throws Main\NotSupportedException
927  * @throws Main\ObjectNotFoundException
928  */
929  public function deleteItem($index)
930  {
931  $oldItem = parent::deleteItem($index);
932 
933  unset($this->basketItemIndexMap[$oldItem->getBasketCode()]);
934 
935  /** @var OrderBase $order */
936  if ($order = $this->getOrder())
937  {
938  $order->onBasketModify(EventActions::DELETE, $oldItem);
939  }
940 
941  return $oldItem;
942  }
943 
944  /**
945  * Apply the result of the discounts to the basket.
946  * @internal
947  *
948  * @param array $basketRows
949  * @return Result
950  * @throws Main\ArgumentNullException
951  * @throws Main\ArgumentOutOfRangeException
952  */
953  public function applyDiscount(array $basketRows)
954  {
955  $result = new Result();
956 
957  if ($this->count() == 0 || empty($basketRows))
958  return $result;
959 
960  /** @var BasketItemBase $basketItem */
961  foreach ($this->collection as $basketItem)
962  {
963  if ($basketItem->isCustomPrice())
964  continue;
965  $basketCode = $basketItem->getBasketCode();
966  if (!isset($basketRows[$basketCode]))
967  continue;
968 
969  $fields = $basketRows[$basketCode];
970 
971  if (isset($fields['PRICE']) && isset($fields['DISCOUNT_PRICE']))
972  {
973  $fields['PRICE'] = (float)$fields['PRICE'];
974  $fields['DISCOUNT_PRICE'] = (float)$fields['DISCOUNT_PRICE'];
975 
976  if ($fields['PRICE'] >= 0
977  && $basketItem->getPrice() != $fields['PRICE'])
978  {
979  $fields['PRICE'] = PriceMaths::roundPrecision($fields['PRICE']);
980  $basketItem->setFieldNoDemand('PRICE', $fields['PRICE']);
981  }
982 
983  if ($basketItem->getDiscountPrice() != $fields['DISCOUNT_PRICE'])
984  {
985  $fields['DISCOUNT_PRICE'] = PriceMaths::roundPrecision($fields['DISCOUNT_PRICE']);
986  $basketItem->setFieldNoDemand('DISCOUNT_PRICE', $fields['DISCOUNT_PRICE']);
987  }
988 
989  if (isset($fields['DISCOUNT_VALUE']))
990  $basketItem->setFieldNoDemand('DISCOUNT_VALUE', $fields['DISCOUNT_VALUE']);
991  }
992  }
993  unset($fields, $basketCode, $basketItem);
994 
995  return $result;
996  }
997 
998  /**
999  * @internal
1000  * @param \SplObjectStorage $cloneEntity
1001  *
1002  * @return BasketItemCollection
1003  */
1004  public function createClone(\SplObjectStorage $cloneEntity = null)
1005  {
1006  if ($cloneEntity === null)
1007  {
1008  $cloneEntity = new \SplObjectStorage();
1009  }
1010 
1011  /** @var BasketBase $basketClone */
1012  $basketClone = parent::createClone($cloneEntity);
1013 
1014  if ($this->order)
1015  {
1016  if ($cloneEntity->contains($this->order))
1017  {
1018  $basketClone->order = $cloneEntity[$this->order];
1019  }
1020  }
1021 
1022  return $basketClone;
1023  }
1024 
1025  /**
1026  * Returns copy of current basket.
1027  * For example, the copy will be used to calculate discounts.
1028  * So, basket does not contain full information about BasketItem with bundleCollection, because now it is not
1029  * necessary.
1030  *
1031  * Attention! Don't save the basket.
1032  *
1033  * @internal
1034  * @return BasketBase
1035  * @throws Main\SystemException
1036  */
1037  public function copy()
1038  {
1039  if($this->order !== null)
1040  {
1041  throw new Main\SystemException('Could not clone basket which has order.');
1042  }
1043 
1044  $basket = static::create($this->siteId);
1045  /**@var BasketItemBase $item */
1046  foreach($this as $originalItem)
1047  {
1048  $item = $basket->createItem($originalItem->getField("MODULE"), $originalItem->getProductId());
1049  $item->initFields($originalItem->getFields()->getValues());
1050  }
1051 
1052  return $basket;
1053  }
1054 
1055  /**
1056  * @internal
1057  *
1058  * Load the contents of the basket to order
1059  *
1060  * @param OrderBase $order
1061  * @return BasketBase
1062  * @throws Main\ArgumentException
1063  * @throws Main\ArgumentTypeException
1064  * @throws Main\NotImplementedException
1065  */
1066  public static function loadItemsForOrder(OrderBase $order)
1067  {
1068  $basket = static::createBasketObject();
1069  $basket->setOrder($order);
1070  $basket->setSiteId($order->getSiteId());
1071 
1072  return $basket->loadFromDb(array("ORDER_ID" => $order->getId()));
1073  }
1074 
1075  /**
1076  * @internal
1077  *
1078  * @param Internals\CollectableEntity $basketItem
1079  * @return Internals\CollectableEntity|void
1080  * @throws Main\ArgumentNullException
1081  * @throws Main\ArgumentOutOfRangeException
1082  * @throws Main\ArgumentTypeException
1083  * @throws Main\NotImplementedException
1084  * @throws Main\NotSupportedException
1085  * @throws Main\ObjectNotFoundException
1086  */
1087  public function addItem(Internals\CollectableEntity $basketItem)
1088  {
1089  /** @var BasketItemBase $basketItem */
1090  $basketItem = parent::addItem($basketItem);
1091 
1092  $this->basketItemIndexMap[$basketItem->getBasketCode()] = $basketItem->getInternalIndex();
1093 
1094  $this->verifyItemSort($basketItem);
1095 
1096  $basketItem->setCollection($this);
1097 
1098  /** @var OrderBase $order */
1099  if ($order = $this->getOrder())
1100  {
1101  $order->onBasketModify(EventActions::ADD, $basketItem);
1102  }
1103  }
1104 
1105  /**
1106  * @deprecated Use \Bitrix\Sale\BasketBase::refresh instead
1107  *
1108  * @param array $select
1109  * @param BasketItemBase|null $refreshItem
1110  * @return Result
1111  * @throws Main\ArgumentNullException
1112  */
1113  public function refreshData($select = array(), BasketItemBase $refreshItem = null)
1114  {
1115  if ($refreshItem !== null)
1116  {
1117  $strategy = RefreshFactory::createSingle($refreshItem->getBasketCode());
1118  }
1119  else
1120  {
1122  }
1123 
1124  return $this->refresh($strategy);
1125  }
1126 }
Exception is thrown when the type of an argument is not accepted by function.
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 operation is not implemented but should be.
Base class for fatal exceptions.
static createSingle($basketItemCode)
static create($type='', $params=null)
applyDiscount(array $basketRows)
Apply the result of the discounts to the basket.
Definition: basketbase.php:953
setSiteId($siteId)
Setting site ID to basket.
Definition: basketbase.php:672
getVatSum()
Getting the value of the tax basket.
Definition: basketbase.php:297
static create($siteId)
Definition: basketbase.php:245
refresh(RefreshStrategy $strategy=null)
Definition: basketbase.php:748
refreshData($select=array(), BasketItemBase $refreshItem=null)
getPrice()
Getting basket price with discounts and taxes.
Definition: basketbase.php:259
getSiteId()
Getting Site ID.
Definition: basketbase.php:697
getExistsItemByItem(BasketItemBase $item)
Definition: basketbase.php:65
getOrder()
Getting the object of the order.
Definition: basketbase.php:205
loadFromDb(array $filter)
Definition: basketbase.php:131
static getList(array $parameters=array())
Definition: basketbase.php:707
static loadItemsForFUser($fUserId, $siteId)
Definition: basketbase.php:107
deleteInternal(array $itemValues)
addItem(Internals\CollectableEntity $basketItem)
getQuantityList()
Getting a list of a count of elements in the basket.
Definition: basketbase.php:903
static loadItemsForOrder(OrderBase $order)
verifyItemSort(BasketItemBase $item)
Definition: basketbase.php:216
setFUserId($fUserId)
Setting Customer ID to basket.
Definition: basketbase.php:662
callEventOnSaleBasketItemDeleted($itemValues)
Definition: basketbase.php:564
static deleteNoDemand($idOrder)
Definition: basketbase.php:859
setOrder(OrderBase $order)
Attach to the essence of the object of the order basket.
Definition: basketbase.php:195
getWeight()
Getting the weight basket.
Definition: basketbase.php:383
getFUserId($skipCreate=false)
Getting Customer ID.
Definition: basketbase.php:683
getBasePrice()
Getting basket price without discounts.
Definition: basketbase.php:278
copy()
Returns copy of current basket.
onItemModify(Internals\CollectableEntity $item, $name=null, $oldValue=null, $value=null)
Definition: basketbase.php:720
getVatRate()
Getting the value of the tax rate basket.
Definition: basketbase.php:322
createClone(\SplObjectStorage $cloneEntity=null)
save()
Save basket.
Definition: basketbase.php:477
getExistsItem($moduleId, $productId, array $properties=array())
static getId($skipCreate=false)
Return fuserId.
Definition: fuser.php:29
static getIdByUserId($userId)
Return fuserId for user.
Definition: fuser.php:89
count()
Count elements of an object.
doFinalAction($hasMeaningfulField=false)
isStartField($isMeaningfulField=false)
static roundPrecision($value)
Definition: pricemaths.php:17