Bitrix-D7  20.5.0
orderbase.php
См. документацию.
1 <?php
2 /**
3  * Bitrix Framework
4  * @package bitrix
5  * @subpackage sale
6  * @copyright 2001-2012 Bitrix
7  */
8 namespace Bitrix\Sale;
9 
10 use Bitrix\Currency;
11 use Bitrix\Main;
15 
16 Loc::loadMessages(__FILE__);
17 
18 /**
19  * Class OrderBase
20  * @package Bitrix\Sale
21  */
22 abstract class OrderBase extends Internals\Entity
23 {
24  /** @var Internals\Fields */
25  protected $calculatedFields = null;
26 
27  /** @var BasketBase */
28  protected $basketCollection;
29 
30  /** @var PropertyValueCollectionBase */
32 
33  /** @var Discount $discount */
34  protected $discount = null;
35 
36  /** @var Tax $tax */
37  protected $tax = null;
38 
39  /** @var int */
40  protected $internalId = 0;
41 
42  /** @var bool $isNew */
43  protected $isNew = true;
44 
45  /** @var bool */
46  protected $isSaveExecuting = false;
47 
48  /** @var bool $isClone */
49  protected $isClone = false;
50 
51  /** @var bool $isOnlyMathAction */
52  protected $isOnlyMathAction = null;
53 
54  /** @var bool $isMeaningfulField */
55  protected $isMeaningfulField = false;
56 
57  /** @var bool $isStartField */
58  protected $isStartField = null;
59 
60 
61  /** @var null|string $calculateType */
62  protected $calculateType = null;
63 
67 
68  /**
69  * OrderBase constructor.
70  * @param array $fields
71  * @throws Main\ArgumentNullException
72  */
73  protected function __construct(array $fields = array())
74  {
75  $priceFields = ['PRICE', 'PRICE_DELIVERY', 'SUM_PAID', 'PRICE_PAYMENT', 'DISCOUNT_VALUE'];
76 
77  foreach ($priceFields as $code)
78  {
79  if (isset($fields[$code]))
80  {
82  }
83  }
84 
86  $this->isNew = (empty($fields['ID']));
87  }
88 
89  /**
90  * Return internal index of order
91  *
92  * @return int
93  */
94  public function getInternalId()
95  {
96  static $idPool = 0;
97  if ($this->internalId == 0)
98  {
99  $idPool++;
100  $this->internalId = $idPool;
101  }
102 
103  return $this->internalId;
104  }
105 
106  /**
107  * Return field names that can set in \Bitrix\Sale\OrderBase::setField
108  *
109  * @return array
110  */
111  public static function getAvailableFields()
112  {
113  $result = array(
114  "LID", "PERSON_TYPE_ID", "CANCELED", "DATE_CANCELED",
115  "EMP_CANCELED_ID", "REASON_CANCELED", "STATUS_ID", "DATE_STATUS", "EMP_STATUS_ID", "DEDUCTED",
116  "MARKED", "DATE_MARKED", "EMP_MARKED_ID", "REASON_MARKED",
117  "PRICE", "CURRENCY", "DISCOUNT_VALUE", "USER_ID",
118  "DATE_INSERT", "DATE_UPDATE", "USER_DESCRIPTION", "ADDITIONAL_INFO", "COMMENTS", "TAX_VALUE",
119  "STAT_GID", "RECURRING_ID", "LOCKED_BY", "IS_RECURRING",
120  "DATE_LOCK", "RECOUNT_FLAG", "AFFILIATE_ID", "DELIVERY_DOC_NUM", "DELIVERY_DOC_DATE", "UPDATED_1C",
121  "STORE_ID", "ORDER_TOPIC", "RESPONSIBLE_ID", "DATE_BILL", "DATE_PAY_BEFORE", "ACCOUNT_NUMBER",
122  "XML_ID", "ID_1C", "VERSION_1C", "VERSION", "EXTERNAL_ORDER", "COMPANY_ID", "IS_SYNC_B24"
123  );
124 
125  return array_merge($result, static::getCalculatedFields());
126  }
127 
128  /**
129  * Return virtual field names
130  *
131  * @return array
132  */
133  protected static function getCalculatedFields()
134  {
135  return array(
136  'PRICE_WITHOUT_DISCOUNT',
137  'ORDER_WEIGHT',
138  'DISCOUNT_PRICE',
139  'BASE_PRICE_DELIVERY',
140 
141  'DELIVERY_LOCATION',
142  'DELIVERY_LOCATION_ZIP',
143  'TAX_LOCATION',
144  'TAX_PRICE',
145 
146  'VAT_RATE',
147  'VAT_VALUE',
148  'VAT_SUM',
149  'VAT_DELIVERY',
150  'USE_VAT',
151  );
152  }
153 
154  /**
155  * @return bool
156  */
157  public function isSaveRunning()
158  {
159  return $this->isSaveExecuting;
160  }
161 
162  /**
163  * @return array
164  */
165  protected static function getMeaningfulFields()
166  {
167  return array('PERSON_TYPE_ID', 'PRICE');
168  }
169 
170  /**
171  * @param array $fields
172  * @return mixed
173  * @throws Main\ArgumentException
174  * @throws Main\NotImplementedException
175  */
176  private static function createOrderObject(array $fields = array())
177  {
178  $registry = Registry::getInstance(static::getRegistryType());
179  $orderClassName = $registry->getOrderClassName();
180 
181  return new $orderClassName($fields);
182  }
183 
184  /**
185  * @return string
186  */
187  public static function getRegistryEntity()
188  {
189  return Registry::ENTITY_ORDER;
190  }
191 
192  /**
193  * Create \Bitrix\Sale\OrderBase object
194  *
195  * @param $siteId
196  * @param null $userId
197  * @param null $currency
198  * @return Order
199  * @throws Main\ArgumentOutOfRangeException
200  * @throws Main\NotImplementedException
201  * @throws Main\ObjectException
202  */
203  public static function create($siteId, $userId = null, $currency = null)
204  {
205  $fields = [
206  'CANCELED' => 'N',
207  'DEDUCTED' => 'N',
208  'ALLOW_DELIVERY' => 'N',
209  'PAYED' => 'N',
210  ];
211 
212  $order = static::createOrderObject($fields);
213  $order->setFieldNoDemand('LID', $siteId);
214  if (intval($userId) > 0)
215  {
216  $order->setFieldNoDemand('USER_ID', $userId);
217  }
218 
219  if ($currency == null)
220  {
222  }
223 
224  if ($currency == null)
225  {
227  }
228 
229  $order->setFieldNoDemand('CURRENCY', $currency);
230  $order->setField('STATUS_ID', static::getInitialStatus());
231  $order->setFieldNoDemand('XML_ID', static::generateXmlId());
232 
233  $order->calculateType = static::SALE_ORDER_CALC_TYPE_NEW;
234 
235  return $order;
236  }
237 
238  /**
239  * @return string
240  */
241  protected static function generateXmlId()
242  {
243  return uniqid('bx_');
244  }
245 
246  /**
247  * Load order object by id
248  *
249  * @param $id
250  * @return null|static
251  * @throws Main\ArgumentNullException
252  */
253  public static function load($id)
254  {
255  if (intval($id) <= 0)
256  {
257  throw new Main\ArgumentNullException("id");
258  }
259 
260  $filter = [
261  'filter' => ['ID' => $id],
262  'select' => ['*'],
263  ];
264 
265  $list = static::loadByFilter($filter);
266  if (!empty($list) && is_array($list))
267  {
268  return reset($list);
269  }
270 
271  return null;
272  }
273 
274  /**
275  * Return object order list satisfying filter
276  *
277  * @param array $parameters
278  * @return array|null
279  * @throws Main\ArgumentException
280  * @throws Main\NotImplementedException
281  */
282  public static function loadByFilter(array $parameters)
283  {
284  $list = [];
285 
286  $parameters = static::prepareParams($parameters);
287 
288  /** @var Main\DB\Result $res */
289  $res = static::loadFromDb($parameters);
290  while($orderData = $res->fetch())
291  {
292  $order = static::createOrderObject($orderData);
293 
294  $order->calculateType = static::SALE_ORDER_CALC_TYPE_CHANGE;
295  $list[] = $order;
296  }
297 
298  return $list;
299  }
300 
301  /**
302  * @param $parameters
303  * @return array
304  */
305  private static function prepareParams($parameters)
306  {
307  $result = array(
308  'select' => array('*')
309  );
310 
311  if (isset($parameters['filter']))
312  {
313  $result['filter'] = $parameters['filter'];
314  }
315  if (isset($parameters['limit']))
316  {
317  $result['limit'] = $parameters['limit'];
318  }
319  if (isset($parameters['order']))
320  {
321  $result['order'] = $parameters['order'];
322  }
323  if (isset($parameters['offset']))
324  {
325  $result['offset'] = $parameters['offset'];
326  }
327  if (isset($parameters['runtime']))
328  {
329  $result['runtime'] = $parameters['runtime'];
330  }
331 
332  return $result;
333  }
334 
335  /**
336  * Load object order by account number
337  *
338  * @param $value
339  * @return mixed|null
340  * @throws Main\ArgumentException
341  * @throws Main\ArgumentNullException
342  * @throws Main\NotImplementedException
343  */
344  public static function loadByAccountNumber($value)
345  {
346  if (trim($value) == '')
347  {
348  throw new Main\ArgumentNullException("value");
349  }
350 
351  $parameters = [
352  'filter' => ['=ACCOUNT_NUMBER' => $value],
353  'select' => ['*'],
354  ];
355 
356  $list = static::loadByFilter($parameters);
357 
358  return reset($list);
359  }
360 
361  /**
362  * @param array $parameters
363  * @return Main\DB\Result
364  * @throws Main\NotImplementedException
365  */
366  static protected function loadFromDb(array $parameters)
367  {
368  return static::getList($parameters);
369  }
370 
371  /**
372  * Append basket to order and refresh it
373  *
374  * @param BasketBase $basket
375  * @return Result
376  * @throws Main\NotSupportedException
377  */
378  public function setBasket(BasketBase $basket)
379  {
380  $result = self::appendBasket($basket);
381 
382  if (!$this->isMathActionOnly())
383  {
384  /** @var Result $r */
385  $r = $basket->refreshData(['PRICE', 'QUANTITY', 'COUPONS']);
386  if (!$r->isSuccess())
387  {
388  $result->addErrors($r->getErrors());
389  return $result;
390  }
391  }
392 
393  return $result;
394  }
395 
396  /**
397  * Append basket to order
398  *
399  * @param BasketBase $basket
400  *
401  * @return Result
402  * @throws Main\NotSupportedException
403  */
404  public function appendBasket(BasketBase $basket)
405  {
406  if ($this->getId())
407  {
408  throw new Main\NotSupportedException();
409  }
410 
411  $basket->setOrder($this);
412  $this->basketCollection = $basket;
413 
414  return new Result();
415  }
416 
417  /**
418  * Return order basket.
419  *
420  * @return BasketBase
421  */
422  public function getBasket()
423  {
424  if (!isset($this->basketCollection) || empty($this->basketCollection))
425  {
426  $this->basketCollection = $this->loadBasket();
427  }
428 
430  }
431 
432  /**
433  * Load basket appended to order
434  *
435  * @return BasketBase|null
436  * @throws Main\ArgumentException
437  * @throws Main\NotImplementedException
438  */
439  protected function loadBasket()
440  {
441  if ((int)$this->getId() > 0)
442  {
443  $registry = Registry::getInstance(static::getRegistryType());
444  /** @var BasketBase $basketClassName */
445  $basketClassName = $registry->getBasketClassName();
446 
447  return $basketClassName::loadItemsForOrder($this);
448  }
449 
450  return null;
451  }
452 
453  /**
454  * Set value with call events on field modify
455  *
456  * @param $name
457  * @param $value
458  * @return Result
459  * @throws Main\ArgumentNullException
460  * @throws Main\ArgumentOutOfRangeException
461  * @throws Main\NotImplementedException
462  */
463  public function setField($name, $value)
464  {
465  $priceFields = array(
466  'PRICE' => 'PRICE',
467  'PRICE_DELIVERY' => 'PRICE_DELIVERY',
468  'SUM_PAID' => 'SUM_PAID',
469  'PRICE_PAYMENT' => 'PRICE_PAYMENT',
470  'DISCOUNT_VALUE' => 'DISCOUNT_VALUE',
471  );
472  if (isset($priceFields[$name]))
473  {
474  $value = PriceMaths::roundPrecision($value);
475  }
476 
477  if ($this->isCalculatedField($name))
478  {
479  $this->calculatedFields->set($name, $value);
480  return new Result();
481  }
482 
483  return parent::setField($name, $value);
484  }
485 
486  /**
487  * @param $name
488  * @param $value
489  * @return Result
490  * @throws Main\NotImplementedException
491  */
492  protected function checkValueBeforeSet($name, $value)
493  {
494  $result = parent::checkValueBeforeSet($name, $value);
495 
496  if ($name === 'ACCOUNT_NUMBER')
497  {
498  $dbRes = static::getList([
499  'select' => ['ID'],
500  'filter' => ['=ACCOUNT_NUMBER' => $value]
501  ]);
502 
503  if ($dbRes->fetch())
504  {
505  $result->addError(
506  new ResultError(
507  Loc::getMessage('SALE_ORDER_ACCOUNT_NUMBER_EXISTS')
508  )
509  );
510  }
511  }
512 
513  return $result;
514  }
515 
516  /**
517  * @internal
518  * Set value without call events on field modify
519  *
520  * @param $name
521  * @param $value
522  * @throws Main\ArgumentNullException
523  * @throws Main\ArgumentOutOfRangeException
524  * @throws Main\NotImplementedException
525  */
526  public function setFieldNoDemand($name, $value)
527  {
528  $priceFields = array(
529  'PRICE' => 'PRICE',
530  'PRICE_DELIVERY' => 'PRICE_DELIVERY',
531  'SUM_PAID' => 'SUM_PAID',
532  'PRICE_PAYMENT' => 'PRICE_PAYMENT',
533  'DISCOUNT_VALUE' => 'DISCOUNT_VALUE',
534  );
535  if (isset($priceFields[$name]))
536  {
537  $value = PriceMaths::roundPrecision($value);
538  }
539 
540  if ($this->isCalculatedField($name))
541  {
542  $this->calculatedFields->set($name, $value);
543  return;
544  }
545 
546  if (!$this->fields->isChanged("UPDATED_1C") && $name != 'UPDATED_1C')
547  {
548  $this->setField("UPDATED_1C", "N");
549  }
550 
551  if ($this->isSaveExecuting === false)
552  {
553  if ($name === 'ID')
554  {
555  $this->isNew = false;
556  }
557  }
558 
559  parent::setFieldNoDemand($name, $value);
560  }
561 
562  /**
563  * Return field value
564  *
565  * @param $name
566  * @return null|string
567  */
568  public function getField($name)
569  {
570  if ($this->isCalculatedField($name))
571  {
572  return $this->calculatedFields->get($name);
573  }
574 
575  return parent::getField($name);
576  }
577 
578  /**
579  * @internal
580  *
581  * Init field
582  *
583  * @param $name
584  * @param $value
585  * @return void
586  * @throws Main\ArgumentOutOfRangeException
587  */
588  public function initField($name, $value)
589  {
590  if ($this->isCalculatedField($name))
591  {
592  $this->calculatedFields->set($name, $value);
593  }
594 
595  if ($name === 'ID')
596  {
597  $this->isNew = false;
598  }
599 
600  parent::initField($name, $value);
601  }
602 
603  /**
604  * @return PropertyValueCollectionBase
605  * @throws Main\ArgumentException
606  * @throws Main\NotImplementedException
607  * @throws Main\ObjectPropertyException
608  * @throws Main\SystemException
609  */
610  public function getPropertyCollection()
611  {
612  if(empty($this->propertyCollection))
613  {
614  $this->propertyCollection = $this->loadPropertyCollection();
615  }
616 
618  }
619 
620  /**
621  * @return PropertyValueCollectionBase
622  * @throws Main\ArgumentException
623  * @throws Main\NotImplementedException
624  * @throws Main\ObjectPropertyException
625  * @throws Main\SystemException
626  */
627  public function loadPropertyCollection()
628  {
629  $registry = Registry::getInstance(static::getRegistryType());
630  /** @var PropertyValueCollectionBase $propertyCollectionClassName */
631  $propertyCollectionClassName = $registry->getPropertyValueCollectionClassName();
632 
633  return $propertyCollectionClassName::load($this);
634  }
635 
636  /**
637  * @internal
638  *
639  * @param string $action Action.
640  * @param PropertyValueBase $property Property.
641  * @param null|string $name Field name.
642  * @param null|string|int|float $oldValue Old value.
643  * @param null|string|int|float $value New value.
644  * @return Result
645  */
646  public function onPropertyValueCollectionModify($action, PropertyValueBase $property, $name = null, $oldValue = null, $value = null)
647  {
648  return new Result();
649  }
650 
651  /**
652  * Full order refresh
653  *
654  * @return Result
655  * @throws Main\ArgumentException
656  * @throws Main\ArgumentNullException
657  * @throws Main\ArgumentOutOfRangeException
658  * @throws Main\ObjectNotFoundException
659  */
660  public function refreshData()
661  {
662  $result = new Result();
663 
664  $isStartField = $this->isStartField();
665 
666  $this->calculateType = ($this->getId() > 0 ? static::SALE_ORDER_CALC_TYPE_REFRESH : static::SALE_ORDER_CALC_TYPE_NEW);
667 
668  $this->resetData();
669 
670  $this->refreshInternal();
671 
672  if ($isStartField)
673  {
674  $hasMeaningfulFields = $this->hasMeaningfulField();
675 
676  /** @var Result $r */
677  $r = $this->doFinalAction($hasMeaningfulFields);
678  if (!$r->isSuccess())
679  {
680  $result->addErrors($r->getErrors());
681  }
682  }
683 
684  return $result;
685 
686  }
687 
688  /**
689  * @return Result
690  * @throws Main\ArgumentNullException
691  * @throws Main\ArgumentOutOfRangeException
692  * @throws Main\NotImplementedException
693  */
694  protected function refreshInternal()
695  {
696  $result = new Result();
697 
698  /** @var Basket $basket */
699  $basket = $this->getBasket();
700  if (!$basket)
701  {
702  return $result;
703  }
704 
705  /** @var Result $r */
706  $r = $this->setField('PRICE', $basket->getPrice());
707  if (!$r->isSuccess())
708  {
709  $result->addErrors($r->getErrors());
710  return $result;
711  }
712 
713  return $result;
714  }
715 
716  /**
717  * Return person type id of order
718  *
719  * @return int
720  */
721  public function getPersonTypeId()
722  {
723  return $this->getField('PERSON_TYPE_ID');
724  }
725 
726  /**
727  * Set person type id of order
728  *
729  * @param $personTypeId
730  *
731  * @return Result
732  */
733  public function setPersonTypeId($personTypeId)
734  {
735  return $this->setField('PERSON_TYPE_ID', intval($personTypeId));
736  }
737 
738  /**
739  * Return order price
740  *
741  * @return float
742  */
743  public function getPrice()
744  {
745  return floatval($this->getField('PRICE'));
746  }
747 
748  /**
749  * Return paid sum
750  *
751  * @return float
752  */
753  public function getSumPaid()
754  {
755  return floatval($this->getField('SUM_PAID'));
756  }
757 
758  /**
759  * @return float
760  */
761  public function getDeliveryPrice()
762  {
763  return floatval($this->getField('PRICE_DELIVERY'));
764  }
765 
766  /**
767  * @return float
768  */
769  public function getDeliveryLocation()
770  {
771  return $this->getField('DELIVERY_LOCATION');
772  }
773 
774  /**
775  * @return float
776  */
777  public function getTaxPrice()
778  {
779  return floatval($this->getField('TAX_PRICE'));
780  }
781 
782  /**
783  * @return float
784  */
785  public function getTaxValue()
786  {
787  return floatval($this->getField('TAX_VALUE'));
788  }
789 
790  /**
791  * Return discount price
792  *
793  * @return float
794  */
795  public function getDiscountPrice()
796  {
797  return floatval($this->getField('DISCOUNT_PRICE'));
798  }
799 
800  /**
801  * Return currency
802  *
803  * @return string
804  */
805  public function getCurrency()
806  {
807  return $this->getField('CURRENCY');
808  }
809 
810  /**
811  * Return user id
812  *
813  * @return int
814  */
815  public function getUserId()
816  {
817  return $this->getField('USER_ID');
818  }
819 
820  /**
821  * Return site id
822  *
823  * @return null|string
824  */
825  public function getSiteId()
826  {
827  return $this->getField('LID');
828  }
829 
830  /**
831  * Return TRUE if VAT is used. Else return FALSE
832  *
833  * @return bool
834  */
835  public function isUsedVat()
836  {
837  $useVat = $this->getField('USE_VAT');
838  if ($useVat === null)
839  {
840  $this->refreshVat();
841  }
842 
843  return $this->getField('USE_VAT') === 'Y';
844  }
845 
846  /**
847  * Return order vat rate
848  *
849  * @return mixed|null
850  */
851  public function getVatRate()
852  {
853  $vatRate = $this->getField('VAT_RATE');
854  if ($vatRate === null && $this->getId() > 0)
855  {
856  $this->refreshVat();
857  return $this->getField('VAT_RATE');
858  }
859  return $vatRate;
860  }
861 
862  /**
863  * Return order vat sum
864  *
865  * @return float
866  */
867  public function getVatSum()
868  {
869  $vatSum = $this->getField('VAT_SUM');
870  if ($vatSum === null && $this->getId() > 0)
871  {
872  $this->refreshVat();
873  return $this->getField('VAT_SUM');
874  }
875  return $vatSum;
876  }
877 
878  /**
879  * Return TRUE if order has problems. Else return FALSE
880  * @return null|string
881  */
882  public function isMarked()
883  {
884  return $this->getField('MARKED') === "Y";
885  }
886 
887  /**
888  * Clear VAT info
889  * @throws Main\ArgumentOutOfRangeException
890  */
891  protected function resetVat()
892  {
893  $this->setFieldNoDemand('USE_VAT', 'N');
894  $this->setFieldNoDemand('VAT_RATE', 0);
895 
896  $this->setFieldNoDemand('VAT_SUM', 0);
897  $this->setFieldNoDemand('VAT_DELIVERY', 0);
898  }
899 
900  /**
901  * @internal
902  *
903  * Recalculate VAT
904  */
905  public function refreshVat()
906  {
907  $this->resetVat();
908 
909  $vatInfo = $this->calculateVat();
910  if ($vatInfo && $vatInfo['VAT_RATE'] > 0)
911  {
912  return $this->applyCalculatedVat($vatInfo);
913  }
914 
915  return new Result();
916  }
917 
918  /**
919  * Calculate VAT
920  *
921  * @return array
922  */
923  protected function calculateVat()
924  {
925  $result = array();
926 
927  $basket = $this->getBasket();
928  if ($basket)
929  {
930  $result['VAT_RATE'] = $basket->getVatRate();
931  $result['VAT_SUM'] = $basket->getVatSum();
932  }
933 
934  return $result;
935  }
936 
937  /**
938  * @param array $vatInfo
939  * @return Result
940  */
941  private function applyCalculatedVat(array $vatInfo)
942  {
943  $result = new Result();
944 
945  /** @var Result $r */
946  $r = $this->setField('USE_VAT', 'Y');
947  if (!$r->isSuccess())
948  {
949  $result->addErrors($r->getErrors());
950  }
951 
952  /** @var Result $r */
953  $r = $this->setField('VAT_RATE', $vatInfo['VAT_RATE']);
954  if (!$r->isSuccess())
955  {
956  $result->addErrors($r->getErrors());
957  }
958 
959  /** @var Result $r */
960  $r = $this->setField('VAT_SUM', $vatInfo['VAT_SUM']);
961  if (!$r->isSuccess())
962  {
963  $result->addErrors($r->getErrors());
964  }
965 
966  return $result;
967  }
968 
969  /**
970  * Return TRUE if order is deducted. Else return FALSE
971  *
972  * @return string
973  */
974  public function isShipped()
975  {
976  return $this->getField('DEDUCTED') === 'Y';
977  }
978 
979  /**
980  * Return TRUE if order is external. Else return FALSE
981  *
982  * @return bool
983  */
984  public function isExternal()
985  {
986  return $this->getField('EXTERNAL_ORDER') == "Y";
987  }
988 
989  /**
990  * @param $field
991  * @return bool
992  */
993  protected function isCalculatedField($field)
994  {
995  if ($this->calculatedFields == null )
996  {
997  $this->calculatedFields = new Internals\Fields();
998  }
999 
1000  return (in_array($field, static::getCalculatedFields()));
1001  }
1002 
1003  /**
1004  * @return mixed
1005  * @throws Main\ArgumentException
1006  * @throws Main\NotImplementedException
1007  */
1008  protected static function getInitialStatus()
1009  {
1010  $registry = Registry::getInstance(static::getRegistryType());
1011 
1012  /** @var OrderStatus $orderStatus */
1013  $orderStatus = $registry->getOrderStatusClassName();
1014  return $orderStatus::getInitialStatus();
1015  }
1016 
1017  /**
1018  * @return mixed
1019  * @throws Main\ArgumentException
1020  * @throws Main\NotImplementedException
1021  */
1022  protected static function getFinalStatus()
1023  {
1024  $registry = Registry::getInstance(static::getRegistryType());
1025 
1026  /** @var OrderStatus $orderStatus */
1027  $orderStatus = $registry->getOrderStatusClassName();
1028  return $orderStatus::getFinalStatus();
1029  }
1030 
1031  /**
1032  * Save order
1033  *
1034  * @return Result
1035  * @throws Main\ArgumentException
1036  * @throws Main\ArgumentOutOfRangeException
1037  * @throws Main\NotImplementedException
1038  * @throws Main\ObjectException
1039  */
1040  public function save()
1041  {
1042  if ($this->isSaveExecuting)
1043  {
1044  trigger_error("Order saving in recursion", E_USER_WARNING);
1045  }
1046 
1047  $this->isSaveExecuting = true;
1048 
1049  $result = new Result();
1050 
1051  $id = $this->getId();
1052  $this->isNew = ($id == 0);
1053  $needUpdateDateInsert = $this->getDateInsert() === null;
1054 
1055  $r = $this->callEventOnBeforeOrderSaved();
1056  if (!$r->isSuccess())
1057  {
1058  $this->isSaveExecuting = false;
1059  return $r;
1060  }
1061 
1062  $r = $this->verify();
1063  if (!$r->isSuccess())
1064  {
1065  $result->addWarnings($r->getErrors());
1066  }
1067 
1068  $r = $this->onBeforeSave();
1069  if (!$r->isSuccess())
1070  {
1071  $this->isSaveExecuting = false;
1072  return $r;
1073  }
1074  elseif ($r->hasWarnings())
1075  {
1076  $result->addWarnings($r->getWarnings());
1077  }
1078 
1079  if ($id > 0)
1080  {
1081  $r = $this->update();
1082  }
1083  else
1084  {
1085  $r = $this->add();
1086  if ($r->getId() > 0)
1087  {
1088  $id = $r->getId();
1089  }
1090  }
1091 
1092  if ($r->hasWarnings())
1093  {
1094  $result->addWarnings($r->getWarnings());
1095  }
1096 
1097  if (!$r->isSuccess())
1098  {
1099  $this->isSaveExecuting = false;
1100  return $r;
1101  }
1102 
1103  if ($id > 0)
1104  {
1105  $result->setId($id);
1106  }
1107 
1109 
1110  $r = $this->saveEntities();
1111  if (!$r->isSuccess())
1112  {
1113  $result->addWarnings($r->getErrors());
1114  }
1115 
1116  if ($r->hasWarnings())
1117  {
1118  $result->addWarnings($r->getWarnings());
1119  }
1120 
1121  /** @var Discount $discount */
1122  $discount = $this->getDiscount();
1123 
1124  /** @var Result $r */
1125  $r = $discount->save();
1126  if (!$r->isSuccess())
1127  {
1128  $result->addWarnings($r->getErrors());
1129  }
1130 
1131  $r = $this->completeSaving($needUpdateDateInsert);
1132  if (!$r->isSuccess())
1133  {
1134  $result->addWarnings($r->getErrors());
1135  }
1136 
1137  $this->callEventOnSaleOrderSaved();
1138  $this->callDelayedEvents();
1139 
1140  $this->onAfterSave();
1141 
1142  $this->isNew = false;
1143  $this->isSaveExecuting = false;
1144  $this->clearChanged();
1145 
1146  return $result;
1147  }
1148 
1149  /**
1150  * @return Result
1151  */
1152  protected function onAfterSave()
1153  {
1154  return new Result();
1155  }
1156 
1157  /**
1158  * @throws Main\ArgumentException
1159  * @throws Main\NotImplementedException
1160  * @return void
1161  */
1162  protected function callDelayedEvents()
1163  {
1164  $registry = Registry::getInstance(static::getRegistryType());
1165  $notifyClassName = $registry->getNotifyClassName();
1166 
1167  $eventList = Internals\EventsPool::getEvents($this->getInternalId());
1168  if ($eventList)
1169  {
1170  foreach ($eventList as $eventName => $eventData)
1171  {
1172  $event = new Main\Event('sale', $eventName, $eventData);
1173  $event->send();
1174 
1175  $notifyClassName::callNotify($this, $eventName);
1176  }
1177 
1179  }
1180 
1181  $notifyClassName::callNotify($this, EventActions::EVENT_ON_ORDER_SAVED);
1182  }
1183 
1184  /**
1185  * @param $needUpdateDateInsert
1186  * @return Result
1187  * @throws Main\ArgumentOutOfRangeException
1188  * @throws Main\NotImplementedException
1189  * @throws Main\ObjectException
1190  */
1191  protected function completeSaving($needUpdateDateInsert)
1192  {
1193  $result = new Result();
1194 
1195  $currentDateTime = new Type\DateTime();
1196  $updateFields = array('RUNNING' => 'N');
1197 
1198  $changedFields = $this->fields->getChangedValues();
1199  if ($this->isNew
1200  || (
1201  $this->isChanged()
1202  && !array_key_exists('DATE_UPDATE', $changedFields)
1203  )
1204  )
1205  {
1206  $updateFields['DATE_UPDATE'] = $currentDateTime;
1207  }
1208 
1209  if ($needUpdateDateInsert)
1210  {
1211  $updateFields['DATE_INSERT'] = $currentDateTime;
1212  }
1213 
1214  $this->setFieldsNoDemand($updateFields);
1215  $r = static::updateInternal($this->getId(), $updateFields);
1216  if (!$r->isSuccess())
1217  {
1218  $result->addErrors($r->getErrors());
1219  }
1220 
1221  return $result;
1222  }
1223 
1224  /**
1225  * @return Result
1226  * @throws Main\ArgumentException
1227  * @throws Main\ArgumentNullException
1228  * @throws Main\ArgumentOutOfRangeException
1229  * @throws Main\NotImplementedException
1230  * @throws Main\ObjectException
1231  * @throws Main\SystemException
1232  */
1233  protected function add()
1234  {
1235  global $USER;
1236 
1237  $result = new Result();
1238 
1239  $currentDateTime = new Type\DateTime();
1240 
1241  if (!$this->getField('DATE_UPDATE'))
1242  {
1243  $this->setField('DATE_UPDATE', $currentDateTime);
1244  }
1245 
1246  if (!$this->getField('DATE_INSERT'))
1247  {
1248  $this->setField('DATE_INSERT', $currentDateTime);
1249  }
1250 
1251  $fields = $this->fields->getValues();
1252 
1253  if (is_object($USER) && $USER->isAuthorized())
1254  {
1255  $fields['CREATED_BY'] = $USER->getID();
1256  $this->setFieldNoDemand('CREATED_BY', $fields['CREATED_BY']);
1257  }
1258 
1259  if (array_key_exists('REASON_MARKED', $fields) && mb_strlen($fields['REASON_MARKED']) > 255)
1260  {
1261  $fields['REASON_MARKED'] = mb_substr($fields['REASON_MARKED'], 0, 255);
1262  }
1263 
1264  $fields['RUNNING'] = 'Y';
1265 
1266  $r = $this->addInternal($fields);
1267  if (!$r->isSuccess())
1268  {
1269  return $result->addErrors($r->getErrors());
1270  }
1271 
1272  if ($resultData = $r->getData())
1273  {
1274  $result->setData($resultData);
1275  }
1276 
1277  $id = $r->getId();
1278  $this->setFieldNoDemand('ID', $id);
1279  $result->setId($id);
1280 
1281  $this->setAccountNumber();
1282 
1283  return $result;
1284  }
1285 
1286  /**
1287  * @return Result
1288  * @throws Main\ArgumentOutOfRangeException
1289  * @throws Main\NotImplementedException
1290  */
1291  protected function update()
1292  {
1293  $result = new Result();
1294 
1295  $fields = $this->fields->getChangedValues();
1296 
1297  if ($this->isChanged())
1298  {
1299  if (array_key_exists('DATE_UPDATE', $fields) && $fields['DATE_UPDATE'] === null)
1300  {
1301  unset($fields['DATE_UPDATE']);
1302  }
1303 
1304  $fields['VERSION'] = intval($this->getField('VERSION')) + 1;
1305  $this->setFieldNoDemand('VERSION', $fields['VERSION']);
1306 
1307  if (array_key_exists('REASON_MARKED', $fields) && mb_strlen($fields['REASON_MARKED']) > 255)
1308  {
1309  $fields['REASON_MARKED'] = mb_substr($fields['REASON_MARKED'], 0, 255);
1310  }
1311 
1312  $r = static::updateInternal($this->getId(), $fields);
1313 
1314  if (!$r->isSuccess())
1315  {
1316  return $result->addErrors($r->getErrors());
1317  }
1318 
1319  if ($resultData = $r->getData())
1320  {
1321  $result->setData($resultData);
1322  }
1323  }
1324 
1325  return $result;
1326  }
1327 
1328  /**
1329  * @return void
1330  */
1331  protected function callEventOnSaleOrderEntitySaved()
1332  {
1333  $oldEntityValues = $this->fields->getOriginalValues();
1334 
1335  if (!empty($oldEntityValues))
1336  {
1337  $eventManager = Main\EventManager::getInstance();
1338  if ($eventsList = $eventManager->findEventHandlers('sale', 'OnSaleOrderEntitySaved'))
1339  {
1340  /** @var Main\Event $event */
1341  $event = new Main\Event('sale', 'OnSaleOrderEntitySaved', array(
1342  'ENTITY' => $this,
1343  'VALUES' => $oldEntityValues,
1344  ));
1345  $event->send();
1346  }
1347  }
1348  }
1349 
1350  /**
1351  * @return void
1352  */
1353  protected function callEventOnSaleOrderSaved()
1354  {
1355  $eventManager = Main\EventManager::getInstance();
1356  if ($eventsList = $eventManager->findEventHandlers('sale', EventActions::EVENT_ON_ORDER_SAVED))
1357  {
1358  $event = new Main\Event('sale', EventActions::EVENT_ON_ORDER_SAVED, array(
1359  'ENTITY' => $this,
1360  'IS_NEW' => $this->isNew,
1361  'IS_CHANGED' => $this->isChanged(),
1362  'VALUES' => $this->fields->getOriginalValues(),
1363  ));
1364  $event->send();
1365  }
1366  }
1367 
1368  /**
1369  * @return Result
1370  */
1371  protected function callEventOnBeforeOrderSaved()
1372  {
1373  $result = new Result();
1374 
1375  /** @var array $oldEntityValues */
1376  $oldEntityValues = $this->fields->getOriginalValues();
1377 
1378  $eventManager = Main\EventManager::getInstance();
1379  if ($eventsList = $eventManager->findEventHandlers('sale', EventActions::EVENT_ON_ORDER_BEFORE_SAVED))
1380  {
1381  /** @var Main\Entity\Event $event */
1382  $event = new Main\Event('sale', EventActions::EVENT_ON_ORDER_BEFORE_SAVED, array(
1383  'ENTITY' => $this,
1384  'VALUES' => $oldEntityValues
1385  ));
1386  $event->send();
1387 
1388  if ($event->getResults())
1389  {
1390  /** @var Main\EventResult $eventResult */
1391  foreach($event->getResults() as $eventResult)
1392  {
1393  if($eventResult->getType() == Main\EventResult::ERROR)
1394  {
1395  $errorMsg = new ResultError(Main\Localization\Loc::getMessage('SALE_EVENT_ON_BEFORE_ORDER_SAVED_ERROR'), 'SALE_EVENT_ON_BEFORE_ORDER_SAVED_ERROR');
1396  if ($eventResultData = $eventResult->getParameters())
1397  {
1398  if (isset($eventResultData) && $eventResultData instanceof ResultError)
1399  {
1400  /** @var ResultError $errorMsg */
1401  $errorMsg = $eventResultData;
1402  }
1403  }
1404 
1405  $result->addError($errorMsg);
1406  }
1407  }
1408  }
1409  }
1410 
1411  return $result;
1412  }
1413 
1414  /**
1415  * @return Result
1416  * @throws Main\ArgumentException
1417  * @throws Main\ArgumentNullException
1418  * @throws Main\NotImplementedException
1419  * @throws Main\ObjectNotFoundException
1420  * @throws Main\ObjectPropertyException
1421  * @throws Main\SystemException
1422  */
1423  protected function saveEntities()
1424  {
1425  $result = new Result();
1426 
1427  /** @var BasketBase $basket */
1428  $basket = $this->getBasket();
1429 
1430  /** @var Result $r */
1431  $r = $basket->save();
1432  if (!$r->isSuccess())
1433  {
1434  $result->addWarnings($r->getErrors());
1435  }
1436 
1437  /** @var Tax $tax */
1438  $tax = $this->getTax();
1439 
1440  /** @var Result $r */
1441  $r = $tax->save();
1442  if (!$r->isSuccess())
1443  {
1444  $result->addWarnings($r->getErrors());
1445  }
1446 
1447  /** @var PropertyValueCollectionBase $propertyCollection */
1449 
1450  /** @var Result $r */
1451  $r = $propertyCollection->save();
1452  if (!$r->isSuccess())
1453  {
1454  $result->addWarnings($r->getErrors());
1455  }
1456 
1457 
1458 
1459  return $result;
1460  }
1461 
1462  /**
1463  * Set account number.
1464  *
1465  * @throws Main\ArgumentNullException
1466  * @throws Main\ArgumentOutOfRangeException
1467  * @throws Main\NotImplementedException
1468  * @throws Main\SystemException
1469  */
1470  protected function setAccountNumber()
1471  {
1473  if ($accountNumber !== false)
1474  {
1475  $this->setField('ACCOUNT_NUMBER', $accountNumber);
1476 
1477  static::updateInternal($this->getId(), ['ACCOUNT_NUMBER' => $accountNumber]);
1478  }
1479  }
1480 
1481  /**
1482  * Set VAT sum
1483  *
1484  * @param $price
1485  */
1486  public function setVatSum($price)
1487  {
1488  $this->setField('VAT_SUM', $price);
1489  }
1490 
1491  /**
1492  * Set VAT delivery sum
1493  *
1494  * @param $price
1495  */
1496  public function setVatDelivery($price)
1497  {
1498  $this->setField('VAT_DELIVERY', $price);
1499  }
1500 
1501  /**
1502  * Return date order insert
1503  *
1504  * @return mixed
1505  */
1506  public function getDateInsert()
1507  {
1508  return $this->getField('DATE_INSERT');
1509  }
1510 
1511  /**
1512  * Return value: OrderBase::SALE_ORDER_CALC_TYPE_REFRESH, OrderBase::SALE_ORDER_CALC_TYPE_CHANGE, OrderBase::SALE_ORDER_CALC_TYPE_NEW
1513  *
1514  * @return null|string
1515  */
1516  public function getCalculateType()
1517  {
1518  return $this->calculateType;
1519  }
1520 
1521  /**
1522  * @param string $name
1523  * @param mixed $oldValue
1524  * @param mixed $value
1525  * @return Result
1526  * @throws Main\ArgumentException
1527  * @throws Main\ArgumentNullException
1528  * @throws Main\ArgumentOutOfRangeException
1529  * @throws Main\NotImplementedException
1530  * @throws Main\ObjectException
1531  */
1532  protected function onFieldModify($name, $oldValue, $value)
1533  {
1534  global $USER;
1535 
1536  $result = new Result();
1537 
1538  if ($name !== 'UPDATED_1C' && !$this->getFields()->isChanged('UPDATED_1C'))
1539  {
1540  $this->setField("UPDATED_1C", "N");
1541  }
1542 
1543  if ($name == "PRICE")
1544  {
1545  /** @var Result $r */
1546  $r = $this->refreshVat();
1547  if (!$r->isSuccess())
1548  {
1549  $result->addErrors($r->getErrors());
1550  return $result;
1551  }
1552  }
1553  elseif ($name == "CURRENCY")
1554  {
1555  throw new Main\NotImplementedException('field CURRENCY');
1556  }
1557  elseif ($name == "CANCELED")
1558  {
1559  $event = new Main\Event('sale', EventActions::EVENT_ON_BEFORE_ORDER_CANCELED, array(
1560  'ENTITY' => $this
1561  ));
1562  $event->send();
1563 
1564  if ($event->getResults())
1565  {
1566  /** @var Main\EventResult $eventResult */
1567  foreach($event->getResults() as $eventResult)
1568  {
1569  if($eventResult->getType() == Main\EventResult::ERROR)
1570  {
1571  $errorMsg = new ResultError(
1572  Main\Localization\Loc::getMessage('SALE_EVENT_ON_BEFORE_ORDER_CANCELED_ERROR'),
1573  'SALE_EVENT_ON_BEFORE_ORDER_CANCELED_ERROR'
1574  );
1575  if ($eventResultData = $eventResult->getParameters())
1576  {
1577  if (isset($eventResultData) && $eventResultData instanceof ResultError)
1578  {
1579  /** @var ResultError $errorMsg */
1580  $errorMsg = $eventResultData;
1581  }
1582  }
1583 
1584  $result->addError($errorMsg);
1585  }
1586  }
1587  }
1588 
1589  if (!$result->isSuccess())
1590  {
1591  return $result;
1592  }
1593 
1594  $r = $this->onOrderModify($name, $oldValue, $value);
1595  if (!$r->isSuccess())
1596  {
1597  $result->addErrors($r->getErrors());
1598  return $result;
1599  }
1600 
1601  $this->setField('DATE_CANCELED', new Type\DateTime());
1602 
1603  if (is_object($USER) && $USER->isAuthorized())
1604  {
1605  $this->setField('EMP_CANCELED_ID', $USER->getID());
1606  }
1607 
1609  $this->getInternalId(),
1611  array('ENTITY' => $this)
1612  );
1613 
1615  $this->getInternalId(),
1617  array('ENTITY' => $this)
1618  );
1619  }
1620  elseif ($name == "USER_ID")
1621  {
1622  throw new Main\NotImplementedException('field USER_ID');
1623  }
1624  elseif($name == "MARKED")
1625  {
1626  if ($oldValue != "Y")
1627  {
1628  $this->setField('DATE_MARKED', new Type\DateTime());
1629 
1630  if (is_object($USER) && $USER->isAuthorized())
1631  {
1632  $this->setField('EMP_MARKED_ID', $USER->getID());
1633  }
1634  }
1635  elseif ($value == "N")
1636  {
1637  $this->setField('REASON_MARKED', '');
1638  }
1639  }
1640  elseif ($name == "STATUS_ID")
1641  {
1643  'ENTITY' => $this,
1644  'VALUE' => $value,
1645  'OLD_VALUE' => $oldValue,
1646  ));
1647  $event->send();
1648 
1649  if ($event->getResults())
1650  {
1651  /** @var Main\EventResult $eventResult */
1652  foreach($event->getResults() as $eventResult)
1653  {
1654  if($eventResult->getType() == Main\EventResult::ERROR)
1655  {
1656  $errorMsg = new ResultError(
1657  Main\Localization\Loc::getMessage('SALE_EVENT_ON_BEFORE_ORDER_STATUS_CHANGE_ERROR'),
1658  'SALE_EVENT_ON_BEFORE_ORDER_STATUS_CHANGE_ERROR'
1659  );
1660  if ($eventResultData = $eventResult->getParameters())
1661  {
1662  if (isset($eventResultData) && $eventResultData instanceof ResultError)
1663  {
1664  /** @var ResultError $errorMsg */
1665  $errorMsg = $eventResultData;
1666  }
1667  }
1668 
1669  $result->addError($errorMsg);
1670  }
1671  }
1672  }
1673 
1674  if (!$result->isSuccess())
1675  {
1676  return $result;
1677  }
1678 
1679  $this->setField('DATE_STATUS', new Type\DateTime());
1680 
1681  if (is_object($USER) && $USER->isAuthorized())
1682  {
1683  $this->setField('EMP_STATUS_ID', $USER->GetID());
1684  }
1685 
1687  'ENTITY' => $this,
1688  'VALUE' => $value,
1689  'OLD_VALUE' => $oldValue,
1690  ));
1691 
1693  'ENTITY' => $this,
1694  'VALUE' => $value,
1695  'OLD_VALUE' => $oldValue,
1696  ));
1697 
1698  if ($this->isStatusChangedOnPay($value, $oldValue))
1699  {
1701  'ENTITY' => $this,
1702  'VALUE' => $value,
1703  'OLD_VALUE' => $oldValue,
1704  ));
1705  }
1706  }
1707 
1708  return $result;
1709  }
1710 
1711  /**
1712  * @param $name
1713  * @param $oldValue
1714  * @param $value
1715  * @return Result
1716  */
1717  protected function onOrderModify($name, $oldValue, $value)
1718  {
1719  return new Result();
1720  }
1721 
1722  /**
1723  * Modify basket.
1724  *
1725  * @param string $action Action.
1726  * @param BasketItemBase $basketItem Basket item.
1727  * @param null|string $name Field name.
1728  * @param null|string|int|float $oldValue Old value.
1729  * @param null|string|int|float $value New value.
1730  * @return Result
1731  * @throws Main\NotImplementedException
1732  * @throws Main\NotSupportedException
1733  * @throws Main\ObjectNotFoundException
1734  */
1735  public function onBasketModify($action, BasketItemBase $basketItem, $name = null, $oldValue = null, $value = null)
1736  {
1737  $result = new Result();
1738 
1739  if ($action === EventActions::DELETE)
1740  {
1741  /** @var Result $r */
1742  $r = $this->refreshVat();
1743  if (!$r->isSuccess())
1744  {
1745  $result->addErrors($r->getErrors());
1746  return $result;
1747  }
1748 
1749  if ($tax = $this->getTax())
1750  {
1751  $tax->resetTaxList();
1752  }
1753 
1754  /** @var Result $result */
1755  $r = $this->refreshOrderPrice();
1756  if (!$r->isSuccess())
1757  {
1758  $result->addErrors($r->getErrors());
1759  }
1760 
1761  return $result;
1762  }
1763  elseif ($action !== EventActions::UPDATE)
1764  {
1765  return $result;
1766  }
1767 
1768  if ($name == "QUANTITY" || $name == "PRICE")
1769  {
1770  /** @var Result $result */
1771  $r = $this->refreshOrderPrice();
1772  if (!$r->isSuccess())
1773  {
1774  $result->addErrors($r->getErrors());
1775  }
1776  }
1777  elseif ($name == "CURRENCY")
1778  {
1779  if ($value != $this->getField("CURRENCY"))
1780  {
1781  throw new Main\NotSupportedException("CURRENCY");
1782  }
1783  }
1784 
1785  return $result;
1786  }
1787 
1788  /**
1789  * @internal
1790  * @return Result
1791  */
1792  public function onBeforeBasketRefresh()
1793  {
1794  return new Result();
1795  }
1796 
1797  /**
1798  * @internal
1799  * @return Result
1800  */
1801  public function onAfterBasketRefresh()
1802  {
1803  return new Result();
1804  }
1805 
1806  /**
1807  * Get the entity of taxes
1808  *
1809  * @return Tax
1810  */
1811  public function getTax()
1812  {
1813  if ($this->tax === null)
1814  {
1815  $this->tax = $this->loadTax();
1816  }
1817  return $this->tax;
1818  }
1819 
1820  /**
1821  * @internal
1822  *
1823  * Return TRUE if order is new. Else return FALSE
1824  *
1825  * @return null|bool
1826  */
1827  public function isNew()
1828  {
1829  return $this->isNew;
1830  }
1831 
1832  /**
1833  * Reset the value of taxes
1834  *
1835  * @internal
1836  */
1837  public function resetTax()
1838  {
1839  $this->setFieldNoDemand('TAX_PRICE', 0);
1840  $this->setFieldNoDemand('TAX_VALUE', 0);
1841  }
1842 
1843  /**
1844  * Return TRUE if order is changed. Else return FALSE
1845  *
1846  * @return bool
1847  */
1848  public function isChanged()
1849  {
1850  if (parent::isChanged())
1851  return true;
1852 
1853  /** @var PropertyValueCollectionBase $propertyCollection */
1855  {
1856  if ($propertyCollection->isChanged())
1857  {
1858  return true;
1859  }
1860  }
1861 
1862  /** @var BasketBase $basket */
1863  if ($basket = $this->getBasket())
1864  {
1865  if ($basket->isChanged())
1866  {
1867  return true;
1868  }
1869 
1870  }
1871 
1872  return false;
1873  }
1874 
1875  /**
1876  * @internal
1877  *
1878  * Reset flag of order change
1879  *
1880  * @return void
1881  */
1882  public function clearChanged()
1883  {
1884  parent::clearChanged();
1885 
1886  if ($basket = $this->getBasket())
1887  {
1888  $basket->clearChanged();
1889  }
1890 
1891  if ($property = $this->getPropertyCollection())
1892  {
1893  $property->clearChanged();
1894  }
1895 
1896  }
1897 
1898  /**
1899  * Return TRUE, if this order is cloned. Else return FALSE
1900  *
1901  * @return bool
1902  */
1903  public function isClone()
1904  {
1905  return $this->isClone;
1906  }
1907 
1908  /**
1909  * Return TRUE, if order is payed. Else return FALSE
1910  *
1911  * @return bool
1912  */
1913  public function isPaid()
1914  {
1915  return $this->getField('PAYED') === 'Y';
1916  }
1917 
1918  /**
1919  * Return TRUE, if order is allowed delivery. Else return FALSE
1920  *
1921  * @return bool
1922  */
1923  public function isAllowDelivery()
1924  {
1925  return $this->getField('ALLOW_DELIVERY') === 'Y';
1926  }
1927 
1928  /**
1929  * Return TRUE, if order is deducted. Else return FALSE
1930  *
1931  * @return bool
1932  */
1933  public function isDeducted()
1934  {
1935  return $this->getField('DEDUCTED') === 'Y';
1936  }
1937 
1938  /**
1939  * Return TRUE, if order is canceled. Else return FALSE
1940  *
1941  * @return bool
1942  */
1943  public function isCanceled()
1944  {
1945  return $this->getField('CANCELED') === 'Y';
1946  }
1947 
1948  /**
1949  * Return order hash
1950  *
1951  * @return mixed
1952  */
1953  public function getHash()
1954  {
1955  /** @var Main\Type\DateTime $dateInsert */
1956  $dateInsert = $this->getDateInsert()->setTimeZone(new \DateTimeZone("Europe/Moscow"));
1957  $timestamp = $dateInsert->getTimestamp();
1958  return md5(
1959  $this->getId().
1960  $timestamp.
1961  $this->getUserId().
1962  $this->getField('ACCOUNT_NUMBER')
1963  );
1964  }
1965 
1966  /**
1967  * Verify object to correctness
1968  *
1969  * @return Result
1970  */
1971  public function verify()
1972  {
1973  $result = new Result();
1974 
1975  /** @var BasketBase $basket */
1976  if ($basket = $this->getBasket())
1977  {
1978  $r = $basket->verify();
1979  if (!$r->isSuccess())
1980  {
1981  $result->addErrors($r->getErrors());
1982  }
1983  }
1984 
1985  /** @var PropertyValueCollectionBase $propertyCollection */
1987  {
1988  $r = $propertyCollection->verify();
1989  if (!$r->isSuccess())
1990  {
1991  $result->addErrors($r->getErrors());
1992  }
1993  }
1994 
1995  /** @var DiscountBase $discounts */
1996  if ($discounts = $this->getDiscount())
1997  {
1998  $r = $discounts->verify();
1999  if (!$r->isSuccess())
2000  {
2001  $result->addErrors($r->getErrors());
2002  }
2003  unset($r);
2004  }
2005  unset($discounts);
2006 
2007  return $result;
2008  }
2009 
2010  /**
2011  * Get order information
2012  *
2013  * @param array $parameters
2014  * @throws Main\NotImplementedException
2015  * @return Main\DB\Result
2016  */
2017  public static function getList(array $parameters = array())
2018  {
2019  throw new Main\NotImplementedException();
2020  }
2021 
2022  /**
2023  * Return tax location
2024  *
2025  * @return null|string
2026  */
2027  public function getTaxLocation()
2028  {
2029  if (strval(($this->getField('TAX_LOCATION')) == ""))
2030  {
2031  /** @var PropertyValueCollectionBase $propertyCollection */
2033 
2034  if ($property = $propertyCollection->getTaxLocation())
2035  {
2036  $this->setField('TAX_LOCATION', $property->getValue());
2037  }
2038 
2039  }
2040 
2041  return $this->getField('TAX_LOCATION');
2042  }
2043 
2044  /**
2045  * Return TRUE if calculations are based on current values. Data from the provider is not requested. Else return false
2046  *
2047  * @return bool
2048  */
2049  public function isMathActionOnly()
2050  {
2051  return $this->isOnlyMathAction;
2052  }
2053 
2054  /**
2055  * @return bool
2056  */
2057  public function hasMeaningfulField()
2058  {
2059  return $this->isMeaningfulField;
2060  }
2061 
2062  /**
2063  * Reset order flags: \Bitrix\Sale\OrderBase::$isStartField, \Bitrix\Sale\OrderBase::$isMeaningfulField
2064  *
2065  * @return void
2066  */
2067  public function clearStartField()
2068  {
2069  $this->isStartField = null;
2070  $this->isMeaningfulField = false;
2071  }
2072 
2073  /**
2074  * @param bool $isMeaningfulField
2075  * @return bool
2076  */
2077  public function isStartField($isMeaningfulField = false)
2078  {
2079  if ($this->isStartField === null)
2080  {
2081  $this->isStartField = true;
2082  }
2083  else
2084  {
2085  $this->isStartField = false;
2086  }
2087 
2088  if ($isMeaningfulField === true)
2089  {
2090  $this->isMeaningfulField = true;
2091  }
2092 
2093  return $this->isStartField;
2094  }
2095 
2096  /**
2097  * @internal
2098  *
2099  * Set TRUE if calculations should be held on current values. Data from the provider is not requested
2100  *
2101  * @param bool $value
2102  */
2103  public function setMathActionOnly($value = false)
2104  {
2105  $this->isOnlyMathAction = $value;
2106  }
2107 
2108  /**
2109  * @internal
2110  *
2111  * Delete order without demands.
2112  *
2113  * @param $id
2114  * @return Result
2115  * @throws Main\NotImplementedException
2116  */
2117  public static function deleteNoDemand($id)
2118  {
2119  $result = new Result();
2120 
2121  if (!static::isExists($id))
2122  {
2123  $result->addError(new ResultError(Loc::getMessage('SALE_ORDER_ENTITY_NOT_FOUND'), 'SALE_ORDER_ENTITY_NOT_FOUND'));
2124  return $result;
2125  }
2126 
2127  /** @var Result $deleteResult */
2128  $deleteResult = static::deleteEntitiesNoDemand($id);
2129  if (!$deleteResult->isSuccess())
2130  {
2131  $result->addErrors($deleteResult->getErrors());
2132  return $result;
2133  }
2134 
2135  $r = static::deleteInternal($id);
2136  if (!$r->isSuccess())
2137  $result->addErrors($r->getErrors());
2138 
2139  static::deleteExternalEntities($id);
2140 
2141  return $result;
2142  }
2143 
2144  /**
2145  * Delete order
2146  *
2147  * @param int $id Order id.
2148  * @return Result
2149  * @throws Main\ArgumentNullException
2150  */
2151  public static function delete($id)
2152  {
2153  $result = new Result();
2154 
2155  $registry = Registry::getInstance(static::getRegistryType());
2156  /** @var OrderBase $orderClassName */
2157  $orderClassName = $registry->getOrderClassName();
2158 
2159  if (!$order = $orderClassName::load($id))
2160  {
2161  $result->addError(new ResultError(Loc::getMessage('SALE_ORDER_ENTITY_NOT_FOUND'), 'SALE_ORDER_ENTITY_NOT_FOUND'));
2162  return $result;
2163  }
2164 
2165  /** @var Notify $notifyClassName */
2166  $notifyClassName = $registry->getNotifyClassName();
2167  $notifyClassName::setNotifyDisable(true);
2168 
2169  /** @var Result $r */
2170  $r = $order->setField('CANCELED', 'Y');
2171  if (!$r->isSuccess())
2172  {
2173  $result->addErrors($r->getErrors());
2174  return $result;
2175  }
2176 
2177  $r = $order->save();
2178  if (!$r->isSuccess())
2179  {
2180  $result->addErrors($r->getErrors());
2181  return $result;
2182  }
2183 
2184  static::deleteEntities($order);
2185 
2186  $event = new Main\Event(
2187  'sale',
2189  array('ENTITY' => $order)
2190  );
2191  $event->send();
2192 
2193  foreach ($event->getResults() as $eventResult)
2194  {
2195  $return = null;
2196  if ($eventResult->getType() == Main\EventResult::ERROR)
2197  {
2198  if ($eventResultData = $eventResult->getParameters())
2199  {
2200  if (isset($eventResultData) && $eventResultData instanceof ResultError)
2201  {
2202  /** @var ResultError $errorMsg */
2203  $errorMsg = $eventResultData;
2204  }
2205  }
2206 
2207  if (!isset($errorMsg))
2208  $errorMsg = new ResultError('EVENT_ORDER_DELETE_ERROR');
2209 
2210  $result->addError($errorMsg);
2211  return $result;
2212  }
2213  }
2214 
2215  /** @var Result $r */
2216  $r = $order->save();
2217  if ($r->isSuccess())
2218  {
2219  /** @var Main\Entity\DeleteResult $r */
2220  $r = static::deleteInternal($id);
2221  if ($r->isSuccess())
2222  static::deleteExternalEntities($id);
2223  }
2224  else
2225  {
2226  $result->addErrors($r->getErrors());
2227  }
2228 
2229  $notifyClassName::setNotifyDisable(false);
2230 
2231  $event = new Main\Event(
2232  'sale',
2234  array('ENTITY' => $order, 'VALUE' => $r->isSuccess())
2235  );
2236  $event->send();
2237 
2238  $result->addData(array('ORDER' => $order));
2239 
2240  return $result;
2241  }
2242 
2243  /**
2244  * @param OrderBase $order
2245  * @return void
2246  */
2247  protected static function deleteEntities(OrderBase $order)
2248  {
2249  /** @var BasketBase $basketCollection */
2250  if ($basketCollection = $order->getBasket())
2251  {
2252  /** @var BasketItemBase $basketItem */
2253  foreach ($basketCollection as $basketItem)
2254  {
2255  $basketItem->delete();
2256  }
2257  }
2258 
2259  /** @var PropertyValueCollectionBase $propertyCollection */
2261  {
2262  /** @var PropertyValue $property */
2263  foreach ($propertyCollection as $property)
2264  {
2265  $property->delete();
2266  }
2267  }
2268  }
2269 
2270  /**
2271  * @param $id
2272  * @return bool
2273  * @throws Main\NotImplementedException
2274  */
2275  protected static function isExists($id)
2276  {
2277  $dbRes = static::getList(array('filter' => array('ID' => $id)));
2278  if ($dbRes->fetch())
2279  return true;
2280 
2281  return false;
2282  }
2283 
2284  /**
2285  * @deprecated Use OrderStatus::isAllowPay instead
2286  *
2287  * @return bool
2288  * @throws Main\ArgumentException
2289  * @throws Main\ArgumentNullException
2290  * @throws Main\ArgumentOutOfRangeException
2291  * @throws Main\NotImplementedException
2292  */
2293  public function isAllowPay()
2294  {
2295  $registry = Registry::getInstance(static::getRegistryType());
2296 
2297  /** @var OrderStatus $orderClassName */
2298  $orderClassName = $registry->getOrderStatusClassName();
2299  return $orderClassName::isAllowPay($this->getField('STATUS_ID'));
2300  }
2301 
2302  /**
2303  * @param $orderId
2304  */
2305  protected static function deleteExternalEntities($orderId)
2306  {
2307  return;
2308  }
2309 
2310  /**
2311  * @param $orderId
2312  * @return Result
2313  */
2314  protected static function deleteEntitiesNoDemand($orderId)
2315  {
2316  $registry = Registry::getInstance(static::getRegistryType());
2317 
2318  /** @var BasketBase $basketClassName */
2319  $basketClassName = $registry->getBasketClassName();
2320  $r = $basketClassName::deleteNoDemand($orderId);
2321  if (!$r->isSuccess())
2322  {
2323  return $r;
2324  }
2325 
2326  /** @var PropertyValueCollectionBase $propertyValueCollectionClassName */
2327  $propertyValueCollectionClassName = $registry->getPropertyValueCollectionClassName();
2328  $r = $propertyValueCollectionClassName::deleteNoDemand($orderId);
2329  if (!$r->isSuccess())
2330  {
2331  return $r;
2332  }
2333 
2334  /** @var OrderDiscountBase $orderDiscountClassName */
2335  $orderDiscountClassName = $registry->getOrderDiscountClassName();
2336  $orderDiscountClassName::deleteByOrder($orderId);
2337 
2338  return new Result();
2339  }
2340 
2341  /**
2342  * Return discount object
2343  *
2344  * @return Discount
2345  */
2346  public function getDiscount()
2347  {
2348  if ($this->discount === null)
2349  {
2350  $this->discount = $this->loadDiscount();
2351  }
2352 
2353  return $this->discount;
2354  }
2355 
2356  /**
2357  * @return Tax
2358  * @throws Main\ArgumentException
2359  * @throws Main\NotImplementedException
2360  */
2361  protected function loadTax()
2362  {
2363  $registry = Registry::getInstance(static::getRegistryType());
2364 
2365  /** @var Tax $taxClassName */
2366  $taxClassName = $registry->getTaxClassName();
2367  return $taxClassName::load($this);
2368  }
2369 
2370  /**
2371  * @return DiscountBase
2372  * @throws Main\ArgumentException
2373  * @throws Main\NotImplementedException
2374  */
2375  protected function loadDiscount()
2376  {
2377  $registry = Registry::getInstance(static::getRegistryType());
2378 
2379  /** @var Discount $discountClassName */
2380  $discountClassName = $registry->getDiscountClassName();
2381  return $discountClassName::buildFromOrder($this);
2382  }
2383 
2384  /**
2385  * @return Result
2386  */
2387  private function refreshOrderPrice()
2388  {
2389  return $this->setField("PRICE", $this->calculatePrice());
2390  }
2391 
2392  /**
2393  * @return float
2394  */
2395  protected function calculatePrice()
2396  {
2397  $basket = $this->getBasket();
2398  $taxPrice = !$this->isUsedVat() ? $this->getField('TAX_PRICE') : 0;
2399 
2400  return $basket->getPrice() + $taxPrice;
2401  }
2402 
2403  /**
2404  * @return Result
2405  */
2406  protected function onBeforeSave()
2407  {
2408  return new Result();
2409  }
2410 
2411  /**
2412  * @param bool $hasMeaningfulField
2413  * @return Result
2414  * @throws Main\ArgumentNullException
2415  * @throws Main\ObjectNotFoundException
2416  */
2417  public function doFinalAction($hasMeaningfulField = false)
2418  {
2419  $result = new Result();
2420 
2421  $orderInternalId = $this->getInternalId();
2422 
2423  $r = Internals\ActionEntity::runActions($orderInternalId);
2424  if (!$r->isSuccess())
2425  {
2426  $result->addErrors($r->getErrors());
2427  }
2428 
2429  if (!$hasMeaningfulField)
2430  {
2431  $this->clearStartField();
2432  return $result;
2433  }
2434 
2435 
2436  if ($r->hasWarnings())
2437  {
2438  $result->addWarnings($r->getWarnings());
2439  }
2440 
2441  $currentIsMathActionOnly = $this->isMathActionOnly();
2442 
2443  $basket = $this->getBasket();
2444  if ($basket)
2445  {
2446  $this->setMathActionOnly(true);
2447 
2448  $eventManager = Main\EventManager::getInstance();
2449  $eventsList = $eventManager->findEventHandlers('sale', 'OnBeforeSaleOrderFinalAction');
2450  if (!empty($eventsList))
2451  {
2452  $event = new Main\Event('sale', 'OnBeforeSaleOrderFinalAction', array(
2453  'ENTITY' => $this,
2454  'HAS_MEANINGFUL_FIELD' => $hasMeaningfulField,
2455  'BASKET' => $basket,
2456  ));
2457  $event->send();
2458 
2459  if ($event->getResults())
2460  {
2461  /** @var Main\EventResult $eventResult */
2462  foreach($event->getResults() as $eventResult)
2463  {
2464  if($eventResult->getType() == Main\EventResult::ERROR)
2465  {
2466  $errorMsg = new ResultError(
2467  Main\Localization\Loc::getMessage(
2468  'SALE_EVENT_ON_BEFORE_SALEORDER_FINAL_ACTION_ERROR'
2469  ),
2470  'SALE_EVENT_ON_BEFORE_SALEORDER_FINAL_ACTION_ERROR'
2471  );
2472 
2473  $eventResultData = $eventResult->getParameters();
2474  if ($eventResultData)
2475  {
2476  if (isset($eventResultData) && $eventResultData instanceof ResultError)
2477  {
2478  /** @var ResultError $errorMsg */
2479  $errorMsg = $eventResultData;
2480  }
2481  }
2482 
2483  $result->addError($errorMsg);
2484  }
2485  }
2486  }
2487  }
2488 
2489  if (!$result->isSuccess())
2490  {
2491  return $result;
2492  }
2493 
2494  // discount
2495  $discount = $this->getDiscount();
2496  $r = $discount->calculate();
2497  if (!$r->isSuccess())
2498  {
2499 // $this->clearStartField();
2500 // $result->addErrors($r->getErrors());
2501 // return $result;
2502  }
2503 
2504  if ($r->isSuccess() && ($discountData = $r->getData()) && !empty($discountData) && is_array($discountData))
2505  {
2506  /** @var Result $r */
2507  $r = $this->applyDiscount($discountData);
2508  if (!$r->isSuccess())
2509  {
2510  $result->addErrors($r->getErrors());
2511  return $result;
2512  }
2513  }
2514 
2515  /** @var Tax $tax */
2516  $tax = $this->getTax();
2517  /** @var Result $r */
2518  $r = $tax->refreshData();
2519  if (!$r->isSuccess())
2520  {
2521  $result->addErrors($r->getErrors());
2522  return $result;
2523  }
2524 
2525  $taxResult = $r->getData();
2526 
2527  $taxChanged = false;
2528  if (isset($taxResult['TAX_PRICE']) && floatval($taxResult['TAX_PRICE']) >= 0)
2529  {
2530  if (!$this->isUsedVat())
2531  {
2532  $taxChanged = $this->getField('TAX_PRICE') !== $taxResult['TAX_PRICE'];
2533  if ($taxChanged)
2534  {
2535  $this->setField('TAX_PRICE', $taxResult['TAX_PRICE']);
2536  $this->refreshOrderPrice();
2537  }
2538  }
2539 
2540  }
2541 
2542  if (array_key_exists('VAT_SUM', $taxResult))
2543  {
2544  if ($this->isUsedVat())
2545  {
2546  $this->setField('VAT_SUM', $taxResult['VAT_SUM']);
2547  }
2548  }
2549 
2550  if ($taxChanged || $this->isUsedVat())
2551  {
2552  $taxValue = $this->isUsedVat()? $this->getVatSum() : $this->getField('TAX_PRICE');
2553  if (floatval($taxValue) != floatval($this->getField('TAX_VALUE')))
2554  {
2555  $this->setField('TAX_VALUE', floatval($taxValue));
2556  }
2557  }
2558 
2559  }
2560 
2561  if (!$currentIsMathActionOnly)
2562  $this->setMathActionOnly(false);
2563 
2564  $this->clearStartField();
2565 
2566  $eventManager = Main\EventManager::getInstance();
2567  if ($eventsList = $eventManager->findEventHandlers('sale', 'OnAfterSaleOrderFinalAction'))
2568  {
2569  $event = new Main\Event(
2570  'sale',
2571  'OnAfterSaleOrderFinalAction',
2572  array('ENTITY' => $this)
2573  );
2574  $event->send();
2575  }
2576 
2577  return $result;
2578  }
2579 
2580  /**
2581  * Apply the result of the discounts to the order.
2582  *
2583  * @internal
2584  *
2585  * @param array $data
2586  * @return Result
2587  * @throws Main\ArgumentNullException
2588  */
2589  public function applyDiscount(array $data)
2590  {
2591  if (!empty($data['BASKET_ITEMS']) && is_array($data['BASKET_ITEMS']))
2592  {
2593  /** @var BasketBase $basket */
2594  $basket = $this->getBasket();
2595  $basketResult = $basket->applyDiscount($data['BASKET_ITEMS']);
2596  if (!$basketResult->isSuccess())
2597  return $basketResult;
2598  unset($basketResult, $basket);
2599 
2600  $this->refreshOrderPrice();
2601  }
2602 
2603  return new Result();
2604  }
2605 
2606  /**
2607  * @param $value
2608  * @return Result
2609  * @throws Main\ArgumentException
2610  */
2611  protected function setReasonMarked($value)
2612  {
2613  $result = new Result();
2614 
2615  if (!empty($value))
2616  {
2617  $orderReasonMarked = $this->getField('REASON_MARKED');
2618  if (is_array($value))
2619  {
2620  $newOrderReasonMarked = '';
2621 
2622  foreach ($value as $err)
2623  {
2624  $newOrderReasonMarked .= (strval($newOrderReasonMarked) != '' ? "\n" : "") . $err;
2625  }
2626  }
2627  else
2628  {
2629  $newOrderReasonMarked = $value;
2630  }
2631 
2632  /** @var Result $r */
2633  $r = $this->setField('REASON_MARKED', $orderReasonMarked. (strval($orderReasonMarked) != '' ? "\n" : ""). $newOrderReasonMarked);
2634  if (!$r->isSuccess())
2635  {
2636  $result->addErrors($r->getErrors());
2637  }
2638  }
2639 
2640  return $result;
2641  }
2642 
2643  /**
2644  * Reset the value of the order and delivery
2645  *
2646  * @internal
2647  *
2648  * @param array $select
2649  * @throws Main\ArgumentOutOfRangeException
2650  */
2651  public function resetData($select = array('PRICE'))
2652  {
2653  if (in_array('PRICE', $select))
2654  {
2655  $this->setFieldNoDemand('PRICE', 0);
2656  }
2657 
2658  if (in_array('PRICE_DELIVERY', $select))
2659  {
2660  $this->setFieldNoDemand('PRICE_DELIVERY', 0);
2661  }
2662  }
2663 
2664  /**
2665  * @param $value
2666  * @param $oldValue
2667  * @return bool
2668  * @throws Main\ArgumentException
2669  * @throws Main\ArgumentNullException
2670  * @throws Main\ArgumentOutOfRangeException
2671  * @throws Main\NotImplementedException
2672  */
2673  protected function isStatusChangedOnPay($value, $oldValue)
2674  {
2675  $registry = Registry::getInstance(static::getRegistryType());
2676 
2677  /** @var OrderStatus $orderStatus */
2678  $orderStatus = $registry->getOrderStatusClassName();
2679 
2680  $allowPayStatus = $orderStatus::getAllowPayStatusList();
2681  $disallowPayStatus = $orderStatus::getDisallowPayStatusList();
2682 
2683  return !empty($disallowPayStatus)
2684  && in_array($oldValue, $disallowPayStatus)
2685  && !empty($allowPayStatus)
2686  && in_array($value, $allowPayStatus);
2687  }
2688 
2689  /**
2690  * Create order clone
2691  *
2692  * @return OrderBase
2693  * @throws Main\ArgumentException
2694  * @throws Main\NotImplementedException
2695  * @throws Main\SystemException
2696  */
2697  public function createClone()
2698  {
2699  $cloneEntity = new \SplObjectStorage();
2700 
2701  /** @var OrderBase $orderClone */
2702  $orderClone = clone $this;
2703  $orderClone->isClone = true;
2704 
2705  /** @var Internals\Fields $fields */
2706  if ($fields = $this->fields)
2707  {
2708  $orderClone->fields = $fields->createClone($cloneEntity);
2709  }
2710 
2711  /** @var Internals\Fields $calculatedFields */
2712  if ($calculatedFields = $this->calculatedFields)
2713  {
2714  $orderClone->calculatedFields = $calculatedFields->createClone($cloneEntity);
2715  }
2716 
2717  if (!$cloneEntity->contains($this))
2718  {
2719  $cloneEntity[$this] = $orderClone;
2720  }
2721 
2722  $this->cloneEntities($cloneEntity);
2723 
2724  return $orderClone;
2725  }
2726 
2727  /**
2728  * @param \SplObjectStorage $cloneEntity
2729  * @throws Main\ArgumentException
2730  * @throws Main\NotImplementedException
2731  * @throws Main\SystemException
2732  */
2733  protected function cloneEntities(\SplObjectStorage $cloneEntity)
2734  {
2735  if (!$cloneEntity->contains($this))
2736  {
2737  throw new Main\SystemException();
2738  }
2739 
2740  $orderClone = $cloneEntity[$this];
2741 
2742  /** @var BasketBase $basket */
2743  if ($basket = $this->getBasket())
2744  {
2745  $orderClone->basketCollection = $basket->createClone($cloneEntity);
2746  }
2747 
2748  /** @var PropertyValueCollectionBase $propertyCollection */
2750  {
2751  $orderClone->propertyCollection = $propertyCollection->createClone($cloneEntity);
2752  }
2753 
2754  if ($tax = $this->getTax())
2755  {
2756  $orderClone->tax = $tax->createClone($cloneEntity);
2757  }
2758 
2759  if ($discount = $this->getDiscount())
2760  {
2761  $orderClone->discount = $discount->createClone($cloneEntity);
2762  }
2763  }
2764 
2765  /**
2766  * @param array $data
2767  * @throws Main\NotImplementedException
2768  * @return Main\Entity\AddResult
2769  */
2770  abstract protected function addInternal(array $data);
2771 
2772  /**
2773  * @param $primary
2774  * @param array $data
2775  * @throws Main\NotImplementedException
2776  * @return Main\Entity\UpdateResult
2777  */
2778  protected static function updateInternal($primary, array $data)
2779  {
2780  throw new Main\NotImplementedException();
2781  }
2782 
2783  /**
2784  * @param $primary
2785  * @throws Main\NotImplementedException
2786  * @return Main\Entity\DeleteResult
2787  */
2788  protected static function deleteInternal($primary)
2789  {
2790  throw new Main\NotImplementedException();
2791  }
2792 
2793  /**
2794  * Return user field id
2795  *
2796  * @return null
2797  */
2798  public static function getUfId()
2799  {
2800  return null;
2801  }
2802 
2803  /**
2804  * @deprecated Use \Bitrix\Sale\OrderBase::getAvailableFields instead
2805  *
2806  * @returns array
2807  */
2808  public static function getSettableFields()
2809  {
2810  return static::getAvailableFields();
2811  }
2812 
2813  /**
2814  * @internal
2815  *
2816  * @return string
2817  */
2818  public static function getEntityEventName()
2819  {
2820  return 'SaleOrder';
2821  }
2822 
2823  public function toArray() : array
2824  {
2825  $result = parent::toArray();
2826 
2827  $result['BASKET_ITEMS'] = $this->getBasket()->toArray();
2828  $result['PROPERTIES'] = $this->getPropertyCollection()->toArray();
2829 
2830  return $result;
2831  }
2832 }
static getBaseCurrency()
Return base currency.
Exception is thrown when "empty" value is passed to a function that does not accept it as a valid arg...
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.
Exception is thrown when operation is not supported.
Base class for fatal exceptions.
refreshData($select=array(), BasketItemBase $refreshItem=null)
setOrder(OrderBase $order)
Attach to the essence of the object of the order basket.
Definition: basketbase.php:195
const EVENT_ON_ORDER_STATUS_CHANGE_SEND_MAIL
const EVENT_ON_ORDER_STATUS_ALLOW_PAY_CHANGE
const EVENT_ON_BEFORE_ORDER_STATUS_CHANGE
static resetEvents(Order $order=null)
Definition: eventspool.php:32
static addEvent(Order $order, $type, $event)
Definition: eventspool.php:24
static getEvents(Order $order)
Definition: eventspool.php:9
static generateForOrder(Sale\OrderBase $order)
static runActions($code, array $typeList=array())
static getSiteCurrency($siteId)
Returns site currency.
onFieldModify($name, $oldValue, $value)
Definition: orderbase.php:1532
isPaid()
Return TRUE, if order is payed.
Definition: orderbase.php:1913
getUserId()
Return user id.
Definition: orderbase.php:815
static deleteNoDemand($id)
Definition: orderbase.php:2117
static deleteEntitiesNoDemand($orderId)
Definition: orderbase.php:2314
setMathActionOnly($value=false)
Definition: orderbase.php:2103
isStatusChangedOnPay($value, $oldValue)
Definition: orderbase.php:2673
getHash()
Return order hash.
Definition: orderbase.php:1953
static load($id)
Load order object by id.
Definition: orderbase.php:253
createClone()
Create order clone.
Definition: orderbase.php:2697
static getRegistryEntity()
Definition: orderbase.php:187
setBasket(BasketBase $basket)
Append basket to order and refresh it.
Definition: orderbase.php:378
getVatSum()
Return order vat sum.
Definition: orderbase.php:867
onOrderModify($name, $oldValue, $value)
Definition: orderbase.php:1717
applyDiscount(array $data)
Apply the result of the discounts to the order.
Definition: orderbase.php:2589
static getUfId()
Return user field id.
Definition: orderbase.php:2798
const SALE_ORDER_CALC_TYPE_NEW
Definition: orderbase.php:64
getTax()
Get the entity of taxes.
Definition: orderbase.php:1811
static loadByFilter(array $parameters)
Return object order list satisfying filter.
Definition: orderbase.php:282
checkValueBeforeSet($name, $value)
Definition: orderbase.php:492
getPrice()
Return order price.
Definition: orderbase.php:743
resetVat()
Clear VAT info.
Definition: orderbase.php:891
isChanged()
Return TRUE if order is changed.
Definition: orderbase.php:1848
getSiteId()
Return site id.
Definition: orderbase.php:825
onBasketModify($action, BasketItemBase $basketItem, $name=null, $oldValue=null, $value=null)
Modify basket.
Definition: orderbase.php:1735
static getMeaningfulFields()
Definition: orderbase.php:165
static deleteExternalEntities($orderId)
Definition: orderbase.php:2305
static getCalculatedFields()
Return virtual field names.
Definition: orderbase.php:133
static create($siteId, $userId=null, $currency=null)
Create \Bitrix\Sale\OrderBase object.
Definition: orderbase.php:203
isMathActionOnly()
Return TRUE if calculations are based on current values.
Definition: orderbase.php:2049
getCurrency()
Return currency.
Definition: orderbase.php:805
refreshData()
Full order refresh.
Definition: orderbase.php:660
static getList(array $parameters=array())
Get order information.
Definition: orderbase.php:2017
doFinalAction($hasMeaningfulField=false)
Definition: orderbase.php:2417
static updateInternal($primary, array $data)
Definition: orderbase.php:2778
isUsedVat()
Return TRUE if VAT is used.
Definition: orderbase.php:835
initField($name, $value)
Definition: orderbase.php:588
isStartField($isMeaningfulField=false)
Definition: orderbase.php:2077
setVatSum($price)
Set VAT sum.
Definition: orderbase.php:1486
static loadFromDb(array $parameters)
Definition: orderbase.php:366
getDiscountPrice()
Return discount price.
Definition: orderbase.php:795
const SALE_ORDER_CALC_TYPE_CHANGE
Definition: orderbase.php:65
calculateVat()
Calculate VAT.
Definition: orderbase.php:923
isDeducted()
Return TRUE, if order is deducted.
Definition: orderbase.php:1933
resetData($select=array('PRICE'))
Reset the value of the order and delivery.
Definition: orderbase.php:2651
getPersonTypeId()
Return person type id of order.
Definition: orderbase.php:721
isExternal()
Return TRUE if order is external.
Definition: orderbase.php:984
static getEntityEventName()
Definition: orderbase.php:2818
static getSettableFields()
Definition: orderbase.php:2808
static getAvailableFields()
Return field names that can set in \Bitrix\Sale\OrderBase::setField.
Definition: orderbase.php:111
const SALE_ORDER_CALC_TYPE_REFRESH
Definition: orderbase.php:66
setVatDelivery($price)
Set VAT delivery sum.
Definition: orderbase.php:1496
isCanceled()
Return TRUE, if order is canceled.
Definition: orderbase.php:1943
__construct(array $fields=array())
OrderBase constructor.
Definition: orderbase.php:73
getInternalId()
Return internal index of order.
Definition: orderbase.php:94
clearStartField()
Reset order flags: \Bitrix\Sale\OrderBase::$isStartField, \Bitrix\Sale\OrderBase::$isMeaningfulField.
Definition: orderbase.php:2067
getTaxLocation()
Return tax location.
Definition: orderbase.php:2027
getBasket()
Return order basket.
Definition: orderbase.php:422
verify()
Verify object to correctness.
Definition: orderbase.php:1971
addInternal(array $data)
static isExists($id)
Definition: orderbase.php:2275
setPersonTypeId($personTypeId)
Set person type id of order.
Definition: orderbase.php:733
setFieldNoDemand($name, $value)
Definition: orderbase.php:526
isClone()
Return TRUE, if this order is cloned.
Definition: orderbase.php:1903
static deleteEntities(OrderBase $order)
Definition: orderbase.php:2247
static deleteInternal($primary)
Definition: orderbase.php:2788
loadBasket()
Load basket appended to order.
Definition: orderbase.php:439
getCalculateType()
Return value: OrderBase::SALE_ORDER_CALC_TYPE_REFRESH, OrderBase::SALE_ORDER_CALC_TYPE_CHANGE,...
Definition: orderbase.php:1516
getSumPaid()
Return paid sum.
Definition: orderbase.php:753
isShipped()
Return TRUE if order is deducted.
Definition: orderbase.php:974
resetTax()
Reset the value of taxes.
Definition: orderbase.php:1837
onPropertyValueCollectionModify($action, PropertyValueBase $property, $name=null, $oldValue=null, $value=null)
Definition: orderbase.php:646
cloneEntities(\SplObjectStorage $cloneEntity)
Definition: orderbase.php:2733
setField($name, $value)
Set value with call events on field modify.
Definition: orderbase.php:463
isAllowDelivery()
Return TRUE, if order is allowed delivery.
Definition: orderbase.php:1923
getDiscount()
Return discount object.
Definition: orderbase.php:2346
appendBasket(BasketBase $basket)
Append basket to order.
Definition: orderbase.php:404
getDateInsert()
Return date order insert.
Definition: orderbase.php:1506
completeSaving($needUpdateDateInsert)
Definition: orderbase.php:1191
getField($name)
Return field value.
Definition: orderbase.php:568
setAccountNumber()
Set account number.
Definition: orderbase.php:1470
static loadByAccountNumber($value)
Load object order by account number.
Definition: orderbase.php:344
isMarked()
Return TRUE if order has problems.
Definition: orderbase.php:882
getVatRate()
Return order vat rate.
Definition: orderbase.php:851
static roundPrecision($value)
Definition: pricemaths.php:17
__construct(Base $connector)
Constructor.
Definition: resultview.php:40