1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
order.php
См. документацию.
1<?php
2
9
10Loc::loadMessages(__FILE__);
11
12$GLOBALS["SALE_ORDER"] = array();
13
15{
29 public static function DoCalculateOrder($siteId, $userId, $arShoppingCart, $personTypeId, $arOrderPropsValues,
30 $deliveryId, $paySystemId, $arOptions, &$arErrors, &$arWarnings)
31 {
32 if(!is_array($arErrors))
33 {
34 $arErrors = array();
35 }
36
37 if(!is_array($arOptions))
38 {
39 $arOptions = array();
40 }
41
42 $siteId = trim($siteId);
43 if (empty($siteId))
44 {
45 $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGO_CALC_PARAM_ERROR'));
46 return null;
47 }
48
49 $userId = intval($userId);
50
51 if (!is_array($arShoppingCart) || (count($arShoppingCart) <= 0))
52 {
53 $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGO_SHOPPING_CART_EMPTY'));
54 return null;
55 }
56
57 $arOrder = static::makeOrderArray($siteId, $userId, $arShoppingCart, $arOptions);
58
59 // init defaults
60 $arOrder["TAX_PRICE"] ??= 0.0;
61 $arOrder["DELIVERY_PRICE"] ??= 0.0;
62 $arOrder["DISCOUNT_PRICE"] ??= 0.0;
63
64 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderShoppingCart", true) as $arEvent)
65 ExecuteModuleEventEx($arEvent, array(&$arOrder));
66
67 CSalePersonType::DoProcessOrder($arOrder, $personTypeId, $arErrors, $arOptions);
68 if (count($arErrors) > 0)
69 return null;
70
71 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderPersonType", true) as $arEvent)
72 ExecuteModuleEventEx($arEvent, array(&$arOrder));
73
74 CSaleOrderProps::DoProcessOrder($arOrder, $arOrderPropsValues, $arErrors, $arWarnings, $paySystemId, $deliveryId, $arOptions);
75 if (count($arErrors) > 0)
76 return null;
77
78 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderProps", true) as $arEvent)
79 ExecuteModuleEventEx($arEvent, array(&$arOrder));
80
81 CSaleDelivery::DoProcessOrder($arOrder, $deliveryId, $arErrors);
82 if (count($arErrors) > 0)
83 return null;
84
85 $arOrder["PRICE_DELIVERY"] = $arOrder["DELIVERY_PRICE"];
86
87 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderDelivery", true) as $arEvent)
88 ExecuteModuleEventEx($arEvent, array(&$arOrder));
89
90 CSalePaySystem::DoProcessOrder($arOrder, $paySystemId, $arErrors);
91 if (count($arErrors) > 0)
92 return null;
93
94 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderPaySystem", true) as $arEvent)
95 ExecuteModuleEventEx($arEvent, array(&$arOrder));
96
97 if (!array_key_exists('CART_FIX', $arOptions) || 'Y' != $arOptions['CART_FIX'])
98 {
99 CSaleDiscount::DoProcessOrder($arOrder, $arOptions, $arErrors);
100 if (count($arErrors) > 0)
101 return null;
102
103 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderDiscount", true) as $arEvent)
104 ExecuteModuleEventEx($arEvent, array(&$arOrder));
105
106 if (isset($arOrder['ORDER_PRICE']))
107 {
108 $roundOrderFields = static::getRoundFields();
109 foreach ($arOrder as $fieldName => $fieldValue)
110 {
111 if (in_array($fieldName, $roundOrderFields))
112 {
113 $arOrder[$fieldName] = PriceMaths::roundPrecision($arOrder[ $fieldName ]);
114 }
115 }
116 }
117
118 if (!empty($arOrder['BASKET_ITEMS']) && is_array($arOrder['BASKET_ITEMS']))
119 {
120 $arOrder['ORDER_PRICE'] = 0;
121 $roundBasketFields = CSaleBasket::getRoundFields();
122 foreach ($arOrder['BASKET_ITEMS'] as &$basketItem)
123 {
124 foreach($basketItem as $fieldName => $fieldValue)
125 {
126 if (in_array($fieldName, $roundBasketFields))
127 {
128 if (isset($basketItem[$fieldName]))
129 {
130 $basketItem[$fieldName] = PriceMaths::roundPrecision($basketItem[ $fieldName ]);
131 }
132 }
133 }
134 if (CSaleBasketHelper::isSetItem($basketItem))
135 continue;
136
137 $arOrder['ORDER_PRICE'] += CSaleBasketHelper::getFinalPrice($basketItem);
138 }
139 }
140
141 }
142
143 CSaleTax::DoProcessOrderBasket($arOrder, $arOptions, $arErrors);
144 if (count($arErrors) > 0)
145 return null;
146
147 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderShoppingCartTax", true) as $arEvent)
148 ExecuteModuleEventEx($arEvent, array(&$arOrder));
149
150 CSaleTax::DoProcessOrderDelivery($arOrder, $arOptions, $arErrors);
151 if (count($arErrors) > 0)
152 return null;
153
154 foreach(GetModuleEvents("sale", "OnSaleCalculateOrderDeliveryTax", true) as $arEvent)
155 ExecuteModuleEventEx($arEvent, array(&$arOrder));
156
157 $arOrder["PRICE"] = $arOrder["ORDER_PRICE"] + $arOrder["DELIVERY_PRICE"] + $arOrder["TAX_PRICE"] - $arOrder["DISCOUNT_PRICE"];
158 $arOrder["TAX_VALUE"] = ($arOrder["USE_VAT"] ? $arOrder["VAT_SUM"] : $arOrder["TAX_PRICE"]);
159
160 foreach(GetModuleEvents("sale", "OnSaleCalculateOrder", true) as $arEvent)
161 ExecuteModuleEventEx($arEvent, array(&$arOrder));
162
163 $arOrder["PRICE"] = \Bitrix\Sale\PriceMaths::roundPrecision($arOrder["PRICE"]);
164 $arOrder["TAX_VALUE"] = \Bitrix\Sale\PriceMaths::roundPrecision($arOrder["TAX_VALUE"]);
165
166 return $arOrder;
167 }
168
177 public static function makeOrderArray($siteId, $userId = null, array $shoppingCart = [], array $options = [])
178 {
179 // calculate weight for set parent
180 $parentWeight = array();
181 foreach ($shoppingCart as $item)
182 {
184 $parentWeight[$item["SET_PARENT_ID"]]["WEIGHT"] += $item["WEIGHT"] * $item["QUANTITY"];
185 }
186
187 foreach ($shoppingCart as &$item)
188 {
189 if (CSaleBasketHelper::isSetParent($item) && isset($parentWeight[$item["SET_PARENT_ID"]]))
190 $item["WEIGHT"] = $parentWeight[$item["SET_PARENT_ID"]]["WEIGHT"];
191 }
192 unset($item);
193
194 $currency = isset($options['CURRENCY']) && is_string($options['CURRENCY']) ? $options['CURRENCY'] : '';
195 if($currency === '')
196 {
198 }
199
200 $arOrder = array(
201 "ORDER_PRICE" => 0,
202 "ORDER_WEIGHT" => 0,
203 "CURRENCY" => $currency,
204 "WEIGHT_UNIT" => htmlspecialcharsbx(COption::GetOptionString('sale', 'weight_unit', false, $siteId)),
205 "WEIGHT_KOEF" => htmlspecialcharsbx(COption::GetOptionString('sale', 'weight_koef', 1, $siteId)),
206 "BASKET_ITEMS" => $shoppingCart,
207 "SITE_ID" => $siteId,
208 "LID" => $siteId,
209 "USER_ID" => $userId,
210 "USE_VAT" => false,
211 "VAT_RATE" => 0,
212 "VAT_SUM" => 0,
213 "DELIVERY_ID" => false,
214 );
215
216 if (isset($options["DELIVERY_EXTRA_SERVICES"]))
217 {
218 $arOrder["DELIVERY_EXTRA_SERVICES"] = $options["DELIVERY_EXTRA_SERVICES"];
219 }
220
221 $orderPrices = CSaleOrder::CalculateOrderPrices($shoppingCart);
222 if (is_array($orderPrices))
223 {
224 $arOrder['ORDER_PRICE'] = $orderPrices['ORDER_PRICE'];
225 $arOrder['ORDER_WEIGHT'] = $orderPrices['ORDER_WEIGHT'];
226 $arOrder['VAT_RATE'] = $orderPrices['VAT_RATE'];
227 $arOrder['VAT_SUM'] = $orderPrices['VAT_SUM'];
228 $arOrder["USE_VAT"] = ($orderPrices['USE_VAT'] == "Y");
229 }
230
231 return $arOrder;
232 }
233
239 public static function CalculateOrderPrices($arBasketItems)
240 {
241 if (!isset($arBasketItems) || (isset($arBasketItems) && sizeof($arBasketItems) <= 0))
242 return false;
243
245 "ORDER_PRICE" => 0,
246 "ORDER_WEIGHT" => 0,
247 "VAT_RATE" => 0,
248 "VAT_SUM" => 0,
249 "USE_VAT" => 'N',
250 "BASKET_ITEMS" => $arBasketItems,
251 );
252
253 foreach ($arResult['BASKET_ITEMS'] as &$arItem)
254 {
255 if (!CSaleBasketHelper::isSetItem($arItem))
256 {
257 if (array_key_exists('CUSTOM_PRICE', $arItem) && $arItem['CUSTOM_PRICE'] == 'Y')
258 {
259 $defaultPrice = (float)($arItem['DEFAULT_PRICE'] ?? 0.0);
260 $arItem['DISCOUNT_PRICE'] = $defaultPrice - $arItem['PRICE'];
261
262 if ($arItem['DISCOUNT_PRICE'] < 0)
263 {
264 $arItem['DISCOUNT_PRICE'] = 0;
265 }
266
267 if ($defaultPrice > 0)
268 {
269 $arItem['DISCOUNT_PRICE_PERCENT'] = $arItem['DISCOUNT_PRICE'] * 100 / $defaultPrice;
270 }
271 else
272 {
273 $arItem['DISCOUNT_PRICE_PERCENT'] = 0;
274 }
275
276 $arItem["DISCOUNT_PRICE_PERCENT_FORMATED"] = roundEx($arItem["DISCOUNT_PRICE_PERCENT"], SALE_VALUE_PRECISION)."%";
277 }
278
279 if (isset($arItem['CURRENCY']) && $arItem['CURRENCY'] <> '' )
280 $arItem["PRICE_FORMATED"] = SaleFormatCurrency($arItem["PRICE"], $arItem["CURRENCY"]);
281
282 $arResult['ORDER_PRICE'] += CSaleBasketHelper::getFinalPrice($arItem);
283 $arResult['ORDER_WEIGHT'] += $arItem["WEIGHT"] * $arItem["QUANTITY"];
284
285 if ($arItem["VAT_RATE"] > 0)
286 {
287 $arResult['USE_VAT'] = 'Y';
288
289 if ($arItem["VAT_RATE"] > $arResult['VAT_RATE'])
290 $arResult['VAT_RATE'] = $arItem["VAT_RATE"];
291
292 $v = CSaleBasketHelper::getVat($arItem);
293
294 $arItem["VAT_VALUE"] = $arItem["QUANTITY"] > 0
295 ? \Bitrix\Sale\PriceMaths::roundPrecision($v / $arItem["QUANTITY"])
296 : 0.0;
297
298 $arResult["VAT_SUM"] += $v;
299
300 }
301 }
302 }
303
304 $arResult['ORDER_PRICE'] = \Bitrix\Sale\PriceMaths::roundPrecision($arResult['ORDER_PRICE']);
306 unset($arItem);
307
308 return $arResult;
309 }
310
311 // $direct == true => ID => CODE
312 // $direct == false => CODE => ID
313 public static function TranslateLocationPropertyValues($personTypeId, &$orderProps, $direct = true)
314 {
316 {
317 // location ID to CODE
318 $dbOrderProps = CSaleOrderProps::GetList(
319 array("SORT" => "ASC"),
320 array(
321 'PERSON_TYPE_ID' => $personTypeId
322 ),
323 false,
324 false,
325 array("ID", "NAME", "TYPE", "IS_LOCATION", "IS_LOCATION4TAX", "IS_PROFILE_NAME", "IS_PAYER", "IS_EMAIL", "REQUIED", "SORT", "IS_ZIP", "CODE", "MULTIPLE")
326 );
327 while($item = $dbOrderProps->fetch())
328 {
329 if($item['TYPE'] == 'LOCATION' && mb_strlen($orderProps[$item['ID']]))
330 {
331 $source = $orderProps[$item['ID']];
333
334 $orderProps[$item['ID']] = $replace;
335 }
336 }
337 }
338 }
339
344 public static function DoSaveOrder(&$arOrder, $arAdditionalFields, $orderId, &$arErrors, $arCoupons = array(), $arStoreBarcodeOrderFormData = array(), $bSaveBarcodes = false)
345 {
346 global $APPLICATION;
347
348 $orderId = (int)$orderId;
349 $isNew = ($orderId <= 0);
350
351 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
352
354 "ID" => $arOrder["ID"],
355 "LID" => $arOrder["SITE_ID"],
356 "PERSON_TYPE_ID" => $arOrder["PERSON_TYPE_ID"],
357 "PRICE" => $arOrder["PRICE"],
358 "CURRENCY" => $arOrder["CURRENCY"],
359 "USER_ID" => $arOrder["USER_ID"],
360 "PAY_SYSTEM_ID" => $arOrder["PAY_SYSTEM_ID"],
361 "PRICE_DELIVERY" => $arOrder["DELIVERY_PRICE"],
362 "DELIVERY_ID" => ($arOrder["DELIVERY_ID"] <> '' ? $arOrder["DELIVERY_ID"] : false),
363 "DISCOUNT_VALUE" => $arOrder["DISCOUNT_PRICE"],
364 "TAX_VALUE" => $arOrder["TAX_VALUE"],
365 "TRACKING_NUMBER" => $arOrder["TRACKING_NUMBER"]
366 );
367
368 if ($arOrder["DELIVERY_PRICE"] == $arOrder["PRICE_DELIVERY"]
369 && isset($arOrder['PRICE_DELIVERY_DIFF']) && floatval($arOrder['PRICE_DELIVERY_DIFF']) > 0)
370 {
371 $arFields["DELIVERY_PRICE"] = $arOrder['PRICE_DELIVERY_DIFF'] + $arOrder["PRICE_DELIVERY"];
372 }
373
374 if ($orderId <= 0)
375 {
376 $arFields["PAYED"] = "N";
377 $arFields["CANCELED"] = "N";
378 $arFields["STATUS_ID"] = "N";
379 }
380 $arFields = array_merge($arFields, $arAdditionalFields);
381
382 if(!$arOrder['LOCATION_IN_CODES']) // it comes from places like crm_invoice`s Add() and tells us if we need to convert location props from ID to CODE
383 static::TranslateLocationPropertyValues($arOrder["PERSON_TYPE_ID"], $arOrder["ORDER_PROP"]);
384 unset($arOrder['LOCATION_IN_CODES']);
385
386
387 if ($isOrderConverted != 'N')
388 {
389 $orderFields = array_merge($arOrder, $arFields, $arAdditionalFields);
390 if (isset($orderFields['CUSTOM_DISCOUNT_PRICE']) && $orderFields['CUSTOM_DISCOUNT_PRICE'] === true)
391 Sale\Compatible\DiscountCompatibility::reInit(Sale\Compatible\DiscountCompatibility::MODE_DISABLED);
392
393 if (!empty($arStoreBarcodeOrderFormData))
394 {
395 $orderFields['BARCODE_LIST'] = $arStoreBarcodeOrderFormData;
396 }
397
398 $orderFields['BARCODE_SAVE'] = $bSaveBarcodes;
399
400 if ($orderId > 0)
401 $orderFields['ID'] = $orderId;
402
404 $r = Sale\Compatible\OrderCompatibility::modifyOrder(Sale\Compatible\OrderCompatibility::ORDER_COMPAT_ACTION_SAVE, $orderFields);
405 if ($r->isSuccess())
406 {
407 $orderId = $r->getId();
408 }
409 else
410 {
411 foreach ($r->getErrorMessages() as $error)
412 {
413 $arErrors[] = $error;
414 $APPLICATION->ThrowException($error);
415 }
416 return false;
417 }
418 }
419 else
420 {
421
422 if ($orderId > 0)
423 {
425 }
426 else
427 {
428 if (COption::GetOptionString("sale", "product_reserve_condition", "O") == "O")
429 $arFields["RESERVED"] = "Y";
430
432 }
433
434 $orderId = (int)$orderId;
435 if ($orderId <= 0)
436 {
437 if ($ex = $APPLICATION->GetException())
438 $arErrors[] = $ex->GetString();
439 else
440 $arErrors[] = Loc::getMessage("SOA_ERROR_ORDER");
441 }
442
443 if (!empty($arErrors))
444 return null;
445
446 CSaleBasket::DoSaveOrderBasket($orderId, $arOrder["SITE_ID"], $arOrder["USER_ID"], $arOrder["BASKET_ITEMS"], $arErrors, $arCoupons, $arStoreBarcodeOrderFormData, $bSaveBarcodes);
447
448 CSaleTax::DoSaveOrderTax($orderId, $arOrder["TAX_LIST"]);
449 CSaleOrderProps::DoSaveOrderProps($orderId, $arOrder["PERSON_TYPE_ID"], $arOrder["ORDER_PROP"], $arErrors);
450 Sale\DiscountCouponsManager::finalApply();
451 Sale\DiscountCouponsManager::saveApplied();
452
453 foreach(GetModuleEvents("sale", "OnOrderSave", true) as $arEvent)
454 ExecuteModuleEventEx($arEvent, array($orderId, $arFields, $arOrder, $isNew));
455
456 }
457
458 return $orderId;
459 }
460
461 //*************** USER PERMISSIONS *********************/
468 public static function CanUserViewOrder($ID, $arUserGroups = false, $userID = 0)
469 {
470 $ID = intval($ID);
471 $userID = intval($userID);
472
473 $permList = self::checkUserPermissionOrderList(array($ID), 'view', $arUserGroups, $userID);
474 return (isset($permList[$ID]) && $permList[$ID] === true);
475 }
476
483 public static function CanUserUpdateOrder($ID, $arUserGroups = false, $siteID = false)
484 {
485 $ID = intval($ID);
486
487 static $cacheGroupAccess = array();
488 $userRights = CMain::GetUserRight("sale", $arUserGroups, "Y", "Y");
489
490 if ($userRights >= "W")
491 return True;
492
493 if ($userRights == "U")
494 {
495 if ($ID > 0)
496 {
497 $permList = self::checkUserPermissionOrderList(array($ID), 'update', $arUserGroups);
498 return (isset($permList[$ID]) && $permList[$ID] === true);
499 }
500 else // order not created yet
501 {
502 if ($siteID)
503 {
504 $hashGroupAccess = md5($siteID. "|" . join(', ', $arUserGroups));
505 if (array_key_exists($hashGroupAccess, $cacheGroupAccess))
506 {
507 $num = $cacheGroupAccess[$hashGroupAccess];
508 }
509 else
510 {
512 array(),
513 array(
514 "SITE_ID" => $siteID,
515 "GROUP_ID" => $arUserGroups
516 ),
517 array()
518 );
519
520 $cacheGroupAccess[$hashGroupAccess] = $num;
521 }
522
523 if (intval($num) > 0)
524 return True;
525 }
526 }
527 }
528
529 return False;
530 }
531
538 public static function CanUserCancelOrder($ID, $arUserGroups = false, $userID = 0)
539 {
540 $ID = intval($ID);
541 $userID = intval($userID);
542
543 $permList = self::checkUserPermissionOrderList(array($ID), 'cancel', $arUserGroups, $userID);
544 return (isset($permList[$ID]) && $permList[$ID] === true);
545 }
546
553 public static function CanUserMarkOrder($ID, $arUserGroups = false, $userID = 0)
554 {
555 $ID = intval($ID);
556 $userID = intval($userID);
557
558 $permList = self::checkUserPermissionOrderList(array($ID), 'mark', $arUserGroups, $userID);
559 return (isset($permList[$ID]) && $permList[$ID] === true);
560 }
561
568 public static function CanUserChangeOrderFlag($ID, $flag, $arUserGroups = false)
569 {
570 $ID = intval($ID);
571 $flag = trim($flag);
572
573 $userRights = CMain::GetUserRight("sale", $arUserGroups, "Y", "Y");
574 if ($userRights >= "W")
575 return True;
576
577 if ($userRights == "U")
578 {
579 $arOrder = CSaleOrder::GetByID($ID);
580 if ($arOrder)
581 {
583 array(),
584 array(
585 "SITE_ID" => $arOrder["LID"],
586 "GROUP_ID" => $arUserGroups
587 ),
588 array()
589 );
590
591 if (intval($num) > 0)
592 {
593 if ($flag == "P" || $flag == "PERM_PAYMENT")
594 $fieldName = "PERM_PAYMENT";
595 elseif ($flag == "PERM_DEDUCTION")
596 $fieldName = "PERM_DEDUCTION";
597 else
598 $fieldName = "PERM_DELIVERY";
599
600 $dbStatusPerms = CSaleStatus::GetPermissionsList(
601 array(),
602 array(
603 "STATUS_ID" => $arOrder["STATUS_ID"],
604 "GROUP_ID" => $arUserGroups
605 ),
606 array("MAX" => $fieldName)
607 );
608 if ($arStatusPerms = $dbStatusPerms->Fetch())
609 if ($arStatusPerms[$fieldName] == "Y")
610 return True;
611 }
612 }
613 }
614
615 return False;
616 }
617
624 public static function CanUserChangeOrderStatus($ID, $statusID, $arUserGroups = false)
625 {
626 $ID = intval($ID);
627 $statusID = Trim($statusID);
628
629 $userRights = CMain::GetUserRight("sale", $arUserGroups, "Y", "Y");
630 if ($userRights >= "W")
631 return True;
632
633 if ($userRights == "U")
634 {
635 $arOrder = CSaleOrder::GetByID($ID);
636 if ($arOrder)
637 {
639 array(),
640 array(
641 "SITE_ID" => $arOrder["LID"],
642 "GROUP_ID" => $arUserGroups
643 ),
644 array()
645 );
646
647 if (intval($num) > 0)
648 {
649 $dbStatusPerms = CSaleStatus::GetPermissionsList(
650 array(),
651 array(
652 "STATUS_ID" => $arOrder["STATUS_ID"],
653 "GROUP_ID" => $arUserGroups
654 ),
655 array("MAX" => "PERM_STATUS_FROM")
656 );
657 if ($arStatusPerms = $dbStatusPerms->Fetch())
658 {
659 if ($arStatusPerms["PERM_STATUS_FROM"] == "Y")
660 {
661 $dbStatusPerms = CSaleStatus::GetPermissionsList(
662 array(),
663 array(
664 "STATUS_ID" => $statusID,
665 "GROUP_ID" => $arUserGroups
666 ),
667 array("MAX" => "PERM_STATUS")
668 );
669 if ($arStatusPerms = $dbStatusPerms->Fetch())
670 if ($arStatusPerms["PERM_STATUS"] == "Y")
671 return True;
672 }
673 }
674 }
675 }
676 }
677
678 return False;
679 }
680
687 public static function CanUserDeleteOrder($ID, $arUserGroups = false, $userID = 0)
688 {
689 $ID = intval($ID);
690 $userID = intval($userID);
691
692 $permList = self::checkUserPermissionOrderList(array($ID), 'delete', $arUserGroups, $userID);
693 return (isset($permList[$ID]) && $permList[$ID] === true);
694 }
695
696 //*************** ADD, UPDATE, DELETE *********************/
697 public static function CheckFields($ACTION, &$arFields, $ID = 0)
698 {
700
701 if (is_set($arFields, "SITE_ID") && $arFields["SITE_ID"] <> '')
702 $arFields["LID"] = $arFields["SITE_ID"];
703
704 if ((is_set($arFields, "LID") || $ACTION=="ADD") && $arFields["LID"] == '')
705 {
706 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EMPTY_SITE"), "EMPTY_SITE_ID");
707 return false;
708 }
709 if ((is_set($arFields, "PERSON_TYPE_ID") || $ACTION=="ADD") && intval($arFields["PERSON_TYPE_ID"])<=0)
710 {
711 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EMPTY_PERS_TYPE"), "EMPTY_PERSON_TYPE_ID");
712 return false;
713 }
714 if ((is_set($arFields, "USER_ID") || $ACTION=="ADD") && intval($arFields["USER_ID"])<=0)
715 {
716 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EMPTY_USER_ID"), "EMPTY_USER_ID");
717 return false;
718 }
719
720 if (is_set($arFields, "PAYED") && $arFields["PAYED"]!="Y")
721 $arFields["PAYED"]="N";
722 if (is_set($arFields, "CANCELED") && $arFields["CANCELED"]!="Y")
723 $arFields["CANCELED"]="N";
724 if (is_set($arFields, "STATUS_ID") && $arFields["STATUS_ID"] == '')
725 $arFields["STATUS_ID"]="N";
726 if (is_set($arFields, "ALLOW_DELIVERY") && $arFields["ALLOW_DELIVERY"]!="Y")
727 $arFields["ALLOW_DELIVERY"]="N";
728 if (is_set($arFields, "EXTERNAL_ORDER") && $arFields["EXTERNAL_ORDER"]!="Y")
729 $arFields["EXTERNAL_ORDER"]="N";
730
731 if (is_set($arFields, "PRICE") || $ACTION=="ADD")
732 {
733 $arFields["PRICE"] = str_replace(",", ".", $arFields["PRICE"]);
734 $arFields["PRICE"] = DoubleVal($arFields["PRICE"]);
735 }
736 if (is_set($arFields, "PRICE_DELIVERY") || $ACTION=="ADD")
737 {
738 $arFields["PRICE_DELIVERY"] = str_replace(",", ".", $arFields["PRICE_DELIVERY"]);
739 $arFields["PRICE_DELIVERY"] = DoubleVal($arFields["PRICE_DELIVERY"]);
740 }
741 if (is_set($arFields, "SUM_PAID") || $ACTION=="ADD")
742 {
743 $arFields["SUM_PAID"] = str_replace(",", ".", $arFields["SUM_PAID"]);
744 $arFields["SUM_PAID"] = DoubleVal($arFields["SUM_PAID"]);
745 }
746 if (is_set($arFields, "DISCOUNT_VALUE") || $ACTION=="ADD")
747 {
748 $arFields["DISCOUNT_VALUE"] = str_replace(",", ".", $arFields["DISCOUNT_VALUE"]);
749 $arFields["DISCOUNT_VALUE"] = DoubleVal($arFields["DISCOUNT_VALUE"]);
750 }
751 if (is_set($arFields, "TAX_VALUE") || $ACTION=="ADD")
752 {
753 $arFields["TAX_VALUE"] = str_replace(",", ".", $arFields["TAX_VALUE"]);
754 $arFields["TAX_VALUE"] = DoubleVal($arFields["TAX_VALUE"]);
755 }
756
757 if(!is_set($arFields, "LOCKED_BY") && (!is_set($arFields, "UPDATED_1C") || (is_set($arFields, "UPDATED_1C") && $arFields["UPDATED_1C"] != "Y")))
758 {
759 $arFields["UPDATED_1C"] = "N";
760 $arFields["~VERSION"] = "VERSION+0+1";
761 }
762
763 if ((is_set($arFields, "CURRENCY") || $ACTION=="ADD") && $arFields["CURRENCY"] == '')
764 {
765 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EMPTY_CURRENCY"), "EMPTY_CURRENCY");
766 return false;
767 }
768
769 if (is_set($arFields, "CURRENCY"))
770 {
771 if (!($arCurrency = CCurrency::GetByID($arFields["CURRENCY"])))
772 {
773 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["CURRENCY"], Loc::getMessage("SKGO_WRONG_CURRENCY")), "ERROR_NO_CURRENCY");
774 return false;
775 }
776 }
777
778 if (is_set($arFields, "LID"))
779 {
780 $dbSite = CSite::GetByID($arFields["LID"]);
781 if (!$dbSite->Fetch())
782 {
783 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["LID"], Loc::getMessage("SKGO_WRONG_SITE")), "ERROR_NO_SITE");
784 return false;
785 }
786 }
787
788 if (is_set($arFields, "USER_ID"))
789 {
790 $dbUser = CUser::GetByID($arFields["USER_ID"]);
791 if (!$dbUser->Fetch())
792 {
793 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["USER_ID"], Loc::getMessage("SKGO_WRONG_USER")), "ERROR_NO_USER_ID");
794 return false;
795 }
796 }
797
798 if (is_set($arFields, "PERSON_TYPE_ID"))
799 {
800 if (!($arPersonType = CSalePersonType::GetByID($arFields["PERSON_TYPE_ID"])))
801 {
802 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["PERSON_TYPE_ID"], Loc::getMessage("SKGO_WRONG_PERSON_TYPE")), "ERROR_NO_PERSON_TYPE");
803 return false;
804 }
805 }
806
807 if (is_set($arFields, "PAY_SYSTEM_ID") && intval($arFields["PAY_SYSTEM_ID"]) > 0)
808 {
809 if (!($arPaySystem = CSalePaySystem::GetByID(intval($arFields["PAY_SYSTEM_ID"]))))
810 {
811 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["PAY_SYSTEM_ID"], Loc::getMessage("SKGO_WRONG_PS")), "ERROR_NO_PAY_SYSTEM");
812 return false;
813 }
814 }
815
816 if (is_set($arFields, "DELIVERY_ID") && intval($arFields["DELIVERY_ID"]) > 0)
817 {
818 if (!($delivery = \Bitrix\Sale\Delivery\Services\Table::getById($arFields["DELIVERY_ID"])))
819 {
820 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["DELIVERY_ID"], Loc::getMessage("SKGO_WRONG_DELIVERY")), "ERROR_NO_DELIVERY");
821 return false;
822 }
823 }
824
825 if (is_set($arFields, "STATUS_ID"))
826 {
827 if (!($arStatus = CSaleStatus::GetByID($arFields["STATUS_ID"])))
828 {
829 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["STATUS_ID"], Loc::getMessage("SKGO_WRONG_STATUS")), "ERROR_NO_STATUS_ID");
830 return false;
831 }
832 }
833
834 if (is_set($arFields, "ACCOUNT_NUMBER") && $ACTION=="UPDATE")
835 {
836 if ($arFields["ACCOUNT_NUMBER"] == '')
837 {
838 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EMPTY_ACCOUNT_NUMBER"), "EMPTY_ACCOUNT_NUMBER");
839 return false;
840 }
841 else
842 {
843 $dbres = $DB->Query("SELECT ID, ACCOUNT_NUMBER FROM b_sale_order WHERE ACCOUNT_NUMBER = '".$DB->ForSql($arFields["ACCOUNT_NUMBER"])."'", true);
844 if ($arRes = $dbres->GetNext())
845 {
846 if (is_array($arRes) && $arRes["ID"] != $ID)
847 {
848 $APPLICATION->ThrowException(Loc::getMessage("SKGO_EXISTING_ACCOUNT_NUMBER"), "EXISTING_ACCOUNT_NUMBER");
849 return false;
850 }
851 }
852 }
853 }
854
855 if($ACTION == "ADD")
856 $arFields["VERSION"] = 1;
857
858 if (!$USER_FIELD_MANAGER->CheckFields("ORDER", $ID, $arFields))
859 {
860 return false;
861 }
862
863 return True;
864 }
865
866 public static function _Delete($ID)
867 {
868 global $DB, $USER_FIELD_MANAGER;
869
870 $ID = intval($ID);
871 $bSuccess = True;
872
873 foreach(GetModuleEvents("sale", "OnBeforeOrderDelete", true) as $arEvent)
874 if (ExecuteModuleEventEx($arEvent, Array($ID))===false)
875 return false;
876
877 $DB->StartTransaction();
878
879 if ($bSuccess)
880 {
881 $dbBasket = CSaleBasket::GetList(array(), array("ORDER_ID" => $ID));
882 while ($arBasket = $dbBasket->Fetch())
883 {
884 if (CSaleBasketHelper::isSetItem($arBasket)) // set items are deleted when parent is deleted
885 continue;
886
887 $bSuccess = CSaleBasket::Delete($arBasket["ID"]);
888 if (!$bSuccess)
889 break;
890 }
891 }
892
893 if ($bSuccess)
894 {
895 $dbRecurring = CSaleRecurring::GetList(array(), array("ORDER_ID" => $ID));
896 while ($arRecurring = $dbRecurring->Fetch())
897 {
898 $bSuccess = CSaleRecurring::Delete($arRecurring["ID"]);
899 if (!$bSuccess)
900 break;
901 }
902 }
903
904 if ($bSuccess)
906
907 if ($bSuccess)
908 $bSuccess = CSaleOrderTax::DeleteEx($ID);
909
910 if($bSuccess)
912
913 if ($bSuccess)
914 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
915
916 if ($bSuccess)
917 $bSuccess = $DB->Query("DELETE FROM b_sale_order WHERE ID = ".$ID."", true);
918
919 if ($bSuccess)
920 $USER_FIELD_MANAGER->Delete("ORDER", $ID);
921
922 if ($bSuccess)
923 $DB->Commit();
924 else
925 $DB->Rollback();
926
927 foreach(GetModuleEvents("sale", "OnOrderDelete", true) as $arEvent)
928 ExecuteModuleEventEx($arEvent, Array($ID, $bSuccess));
929
930
931 return $bSuccess;
932 }
933
934 public static function Delete($ID)
935 {
936 global $APPLICATION;
937 $ID = (int)$ID;
938 if ($ID <= 0)
939 return false;
940
941 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
942
943 $arOrder = CSaleOrder::GetByID($ID);
944 if ($arOrder)
945 {
946
947 if ($isOrderConverted != 'N')
948 {
949 $errorMessage = "";
950
952 $r = \Bitrix\Sale\Compatible\OrderCompatibility::delete($ID);
953
954 $orderDeleted = (bool)$r->isSuccess();
955
956 if (!$r->isSuccess())
957 {
958 foreach($r->getErrorMessages() as $error)
959 {
960 $errorMessage .= " ".$error;
961 }
962
963 $APPLICATION->ThrowException(Loc::getMessage("SKGO_DELETE_ERROR", array("#MESSAGE#" => $errorMessage)), "DELETE_ERROR");
964 }
965
966 return $orderDeleted;
967
968 }
969 else
970 {
971 if ($arOrder["CANCELED"] != "Y")
972 CSaleBasket::OrderCanceled($ID, "Y"); //used only for old catalog without reservation and deduction
973
974 if ($arOrder["ALLOW_DELIVERY"] == "Y")
975 CSaleOrder::DeliverOrder($ID, "N");
976
977 if ($arOrder["DEDUCTED"] == "Y")
978 {
980 }
981
982 if ($arOrder["RESERVED"] == "Y")
983 {
984 CSaleOrder::ReserveOrder($ID, "N");
985 }
986
987
988 if ($arOrder["PAYED"] != "Y")
989 {
990 $arOrder["SUM_PAID"] = DoubleVal($arOrder["SUM_PAID"]);
991 if ($arOrder["SUM_PAID"] > 0)
992 {
993 if (!CSaleUserAccount::UpdateAccount($arOrder["USER_ID"], $arOrder["SUM_PAID"], $arOrder["CURRENCY"], "ORDER_CANCEL_PART", $ID))
994 return False;
995 }
996
997 return CSaleOrder::_Delete($ID);
998 }
999 else
1000 {
1001 if (CSaleOrder::PayOrder($ID, "N", True, True))
1002 return CSaleOrder::_Delete($ID);
1003 }
1004 }
1005 }
1006
1007 return false;
1008 }
1009
1010 //*************** COMMON UTILS *********************/
1011 public static function GetFilterOperation($key)
1012 {
1013 $strNegative = "N";
1014 if (mb_substr($key, 0, 1) == "!")
1015 {
1016 $key = mb_substr($key, 1);
1017 $strNegative = "Y";
1018 }
1019
1020 $strOrNull = "N";
1021 if (mb_substr($key, 0, 1) == "+")
1022 {
1023 $key = mb_substr($key, 1);
1024 $strOrNull = "Y";
1025 }
1026
1027 if (mb_substr($key, 0, 2) == ">=")
1028 {
1029 $key = mb_substr($key, 2);
1030 $strOperation = ">=";
1031 }
1032 elseif (mb_substr($key, 0, 1) == ">")
1033 {
1034 $key = mb_substr($key, 1);
1035 $strOperation = ">";
1036 }
1037 elseif (mb_substr($key, 0, 2) == "<=")
1038 {
1039 $key = mb_substr($key, 2);
1040 $strOperation = "<=";
1041 }
1042 elseif (mb_substr($key, 0, 1) == "<")
1043 {
1044 $key = mb_substr($key, 1);
1045 $strOperation = "<";
1046 }
1047 elseif (mb_substr($key, 0, 1) == "@")
1048 {
1049 $key = mb_substr($key, 1);
1050 $strOperation = "IN";
1051 }
1052 elseif (mb_substr($key, 0, 1) == "~")
1053 {
1054 $key = mb_substr($key, 1);
1055 $strOperation = "LIKE";
1056 }
1057 elseif (mb_substr($key, 0, 1) == "%")
1058 {
1059 $key = mb_substr($key, 1);
1060 $strOperation = "QUERY";
1061 }
1062 else
1063 {
1064 $strOperation = "=";
1065 }
1066
1067 return array("FIELD" => $key, "NEGATIVE" => $strNegative, "OPERATION" => $strOperation, "OR_NULL" => $strOrNull);
1068 }
1069
1070 public static function PrepareSql(&$arFields, $arOrder, &$arFilter, $arGroupBy, $arSelectFields, $obUserFieldsSql = false, $callback = false, $arOptions = array())
1071 {
1072 global $DB;
1073
1074 $arGroupByFunct = array("COUNT", "AVG", "MIN", "MAX", "SUM");
1075
1076 $arAlreadyJoined = array();
1077
1078 $strSqlGroupBy = '';
1079 $strSqlFrom = '';
1080 $strSqlSelect = '';
1081 $strSqlWhere = '';
1082
1083 // GROUP BY -->
1084 if (is_array($arGroupBy) && count($arGroupBy) > 0)
1085 {
1086 $arSelectFields = $arGroupBy;
1087 foreach ($arGroupBy as $key => $val)
1088 {
1089 $val = mb_strtoupper($val);
1090 $key = mb_strtoupper($key);
1091 if (array_key_exists($val, $arFields) && !in_array($key, $arGroupByFunct))
1092 {
1093 if ($strSqlGroupBy != '')
1094 $strSqlGroupBy .= ", ";
1095 $strSqlGroupBy .= $arFields[$val]["FIELD"];
1096
1097 if (isset($arFields[$val]["FROM"])
1098 && $arFields[$val]["FROM"] <> ''
1099 && !in_array($arFields[$val]["FROM"], $arAlreadyJoined))
1100 {
1101 if ($strSqlFrom != '')
1102 $strSqlFrom .= " ";
1103 $strSqlFrom .= $arFields[$val]["FROM"];
1104 $arAlreadyJoined[] = $arFields[$val]["FROM"];
1105 }
1106 }
1107 }
1108 }
1109 // <-- GROUP BY
1110
1111 // SELECT -->
1112 $arFieldsKeys = array_keys($arFields);
1113
1114 if (is_array($arGroupBy) && count($arGroupBy)==0)
1115 {
1116 $strSqlSelect = "COUNT(%%_DISTINCT_%% ".$arFields[$arFieldsKeys[0]]["FIELD"].") as CNT ";
1117 }
1118 else
1119 {
1120 if (isset($arSelectFields) && !is_array($arSelectFields) && is_string($arSelectFields) && $arSelectFields <> '' && array_key_exists($arSelectFields, $arFields))
1121 $arSelectFields = array($arSelectFields);
1122
1123 if (!isset($arSelectFields)
1124 || !is_array($arSelectFields)
1125 || count($arSelectFields)<=0
1126 || in_array("*", $arSelectFields))
1127 {
1128 $countFieldKey = count($arFieldsKeys);
1129 for ($i = 0; $i < $countFieldKey; $i++)
1130 {
1131 if (isset($arFields[$arFieldsKeys[$i]]["WHERE_ONLY"])
1132 && $arFields[$arFieldsKeys[$i]]["WHERE_ONLY"] == "Y")
1133 {
1134 continue;
1135 }
1136
1137 if ($strSqlSelect != '')
1138 $strSqlSelect .= ", ";
1139
1140 if ($arFields[$arFieldsKeys[$i]]["TYPE"] == "datetime")
1141 {
1142 if ((mb_strtoupper($DB->type)=="ORACLE" || mb_strtoupper($DB->type)=="MSSQL") && (array_key_exists($arFieldsKeys[$i], $arOrder)))
1143 $strSqlSelect .= $arFields[$arFieldsKeys[$i]]["FIELD"]." as ".$arFieldsKeys[$i]."_X1, ";
1144
1145 $strSqlSelect .= $DB->DateToCharFunction($arFields[$arFieldsKeys[$i]]["FIELD"], "FULL")." as ".$arFieldsKeys[$i];
1146 }
1147 elseif ($arFields[$arFieldsKeys[$i]]["TYPE"] == "date")
1148 {
1149 if ((mb_strtoupper($DB->type)=="ORACLE" || mb_strtoupper($DB->type)=="MSSQL") && (array_key_exists($arFieldsKeys[$i], $arOrder)))
1150 $strSqlSelect .= $arFields[$arFieldsKeys[$i]]["FIELD"]." as ".$arFieldsKeys[$i]."_X1, ";
1151
1152 $strSqlSelect .= $DB->DateToCharFunction($arFields[$arFieldsKeys[$i]]["FIELD"], "SHORT")." as ".$arFieldsKeys[$i];
1153 }
1154 else
1155 $strSqlSelect .= $arFields[$arFieldsKeys[$i]]["FIELD"]." as ".$arFieldsKeys[$i];
1156
1157 if (isset($arFields[$arFieldsKeys[$i]]["FROM"])
1158 && $arFields[$arFieldsKeys[$i]]["FROM"] <> ''
1159 && !in_array($arFields[$arFieldsKeys[$i]]["FROM"], $arAlreadyJoined))
1160 {
1161 if ($strSqlFrom <> '')
1162 $strSqlFrom .= " ";
1163 $strSqlFrom .= $arFields[$arFieldsKeys[$i]]["FROM"];
1164 $arAlreadyJoined[] = $arFields[$arFieldsKeys[$i]]["FROM"];
1165 }
1166 }
1167 }
1168 else
1169 {
1170 foreach ($arSelectFields as $key => $val)
1171 {
1172 $val = mb_strtoupper($val);
1173 $key = mb_strtoupper($key);
1174 if (array_key_exists($val, $arFields))
1175 {
1176 if ($strSqlSelect <> '')
1177 $strSqlSelect .= ", ";
1178
1179 if (in_array($key, $arGroupByFunct))
1180 {
1181 $strSqlSelect .= $key."(".$arFields[$val]["FIELD"].") as ".$val;
1182 }
1183 else
1184 {
1185 if ($arFields[$val]["TYPE"] == "datetime")
1186 {
1187 if ((mb_strtoupper($DB->type)=="ORACLE" || mb_strtoupper($DB->type)=="MSSQL") && (array_key_exists($val, $arOrder)))
1188 $strSqlSelect .= $arFields[$val]["FIELD"]." as ".$val."_X1, ";
1189
1190 $strSqlSelect .= $DB->DateToCharFunction($arFields[$val]["FIELD"], "FULL")." as ".$val;
1191 }
1192 elseif ($arFields[$val]["TYPE"] == "date")
1193 {
1194 if ((mb_strtoupper($DB->type)=="ORACLE" || mb_strtoupper($DB->type)=="MSSQL") && (array_key_exists($val, $arOrder)))
1195 $strSqlSelect .= $arFields[$val]["FIELD"]." as ".$val."_X1, ";
1196
1197 $strSqlSelect .= $DB->DateToCharFunction($arFields[$val]["FIELD"], "SHORT")." as ".$val;
1198 }
1199 else
1200 $strSqlSelect .= $arFields[$val]["FIELD"]." as ".$val;
1201 }
1202
1203 if (isset($arFields[$val]["FROM"])
1204 && $arFields[$val]["FROM"] <> ''
1205 && !in_array($arFields[$val]["FROM"], $arAlreadyJoined))
1206 {
1207 if ($strSqlFrom <> '')
1208 $strSqlFrom .= " ";
1209 $strSqlFrom .= $arFields[$val]["FROM"];
1210 $arAlreadyJoined[] = $arFields[$val]["FROM"];
1211 }
1212 }
1213 }
1214 }
1215
1216 if ($strSqlGroupBy <> '')
1217 {
1218 if ($strSqlSelect <> '')
1219 $strSqlSelect .= ", ";
1220 $strSqlSelect .= "COUNT(%%_DISTINCT_%% ".$arFields[$arFieldsKeys[0]]["FIELD"].") as CNT";
1221 }
1222 else
1223 $strSqlSelect = "%%_DISTINCT_%% ".$strSqlSelect;
1224 }
1225 // <-- SELECT
1226
1227 // WHERE -->
1228 $arSqlSearch = Array();
1229
1230 if (!is_array($arFilter))
1231 $filter_keys = Array();
1232 else
1233 $filter_keys = array_keys($arFilter);
1234
1235 $countFilterKey = count($filter_keys);
1236 for ($i = 0; $i < $countFilterKey; $i++)
1237 {
1238 $vals = $arFilter[$filter_keys[$i]];
1239 if (!is_array($vals))
1240 $vals = array($vals);
1241 else
1242 $vals = array_values($vals);
1243
1244 $key = $filter_keys[$i];
1246 $key = $key_res["FIELD"];
1247 $strNegative = $key_res["NEGATIVE"];
1248 $strOperation = $key_res["OPERATION"];
1249 $strOrNull = $key_res["OR_NULL"];
1250
1251 if (array_key_exists($key, $arFields))
1252 {
1253 $arSqlSearch_tmp = array();
1254 if (count($vals) > 0)
1255 {
1256 if ($strOperation == "IN")
1257 {
1258 if (isset($arFields[$key]["WHERE"]))
1259 {
1260 $arSqlSearch_tmp1 = call_user_func_array(
1261 $arFields[$key]["WHERE"],
1262 array($vals, $key, $strOperation, $strNegative, $arFields[$key]["FIELD"], $arFields, $arFilter)
1263 );
1264 if ($arSqlSearch_tmp1 !== false)
1265 $arSqlSearch_tmp[] = $arSqlSearch_tmp1;
1266 }
1267 else
1268 {
1269 if ($arFields[$key]["TYPE"] == "int")
1270 {
1271 array_walk(
1272 $vals,
1273 function (&$item)
1274 {
1275 $item = (int)$item;
1276 }
1277 );
1278 $vals = array_unique($vals);
1279 $val = implode(",", $vals);
1280
1281 if (count($vals) <= 0)
1282 $arSqlSearch_tmp[] = "(1 = 2)";
1283 else
1284 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." IN (".$val."))";
1285 }
1286 elseif ($arFields[$key]["TYPE"] == "double")
1287 {
1288 array_walk(
1289 $vals,
1290 function (&$item) {
1291 $item = (float)$item;
1292 }
1293 );
1294 $vals = array_unique($vals);
1295 $val = implode(",", $vals);
1296
1297 if (count($vals) <= 0)
1298 $arSqlSearch_tmp[] = "(1 = 2)";
1299 else
1300 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))";
1301 }
1302 elseif ($arFields[$key]["TYPE"] == "string" || $arFields[$key]["TYPE"] == "char")
1303 {
1304 array_walk(
1305 $vals,
1306 function (&$item)
1307 {
1308 $item = "'".$GLOBALS["DB"]->ForSql($item)."'";
1309 }
1310 );
1311 $vals = array_unique($vals);
1312 $val = implode(",", $vals);
1313
1314 if (count($vals) <= 0)
1315 $arSqlSearch_tmp[] = "(1 = 2)";
1316 else
1317 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))";
1318 }
1319 elseif ($arFields[$key]["TYPE"] == "datetime")
1320 {
1321 array_walk(
1322 $vals,
1323 function (&$item)
1324 {
1325 $item = $GLOBALS["DB"]->CharToDateFunction($item, "FULL");
1326 }
1327 );
1328 $vals = array_unique($vals);
1329 $val = implode(",", $vals);
1330
1331 if (count($vals) <= 0)
1332 $arSqlSearch_tmp[] = "1 = 2";
1333 else
1334 $arSqlSearch_tmp[] = ($strNegative=="Y"?" NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))";
1335 }
1336 elseif ($arFields[$key]["TYPE"] == "date")
1337 {
1338 array_walk(
1339 $vals,
1340 function (&$item)
1341 {
1342 $item = $GLOBALS["DB"]->CharToDateFunction($item, "SHORT");
1343 }
1344 );
1345 $vals = array_unique($vals);
1346 $val = implode(",", $vals);
1347
1348 if (count($vals) <= 0)
1349 $arSqlSearch_tmp[] = "1 = 2";
1350 else
1351 $arSqlSearch_tmp[] = ($strNegative=="Y"?" NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))";
1352 }
1353 }
1354 }
1355 else
1356 {
1357 $countVals = count($vals);
1358 for ($j = 0; $j < $countVals; $j++)
1359 {
1360 $val = $vals[$j];
1361
1362 if (isset($arFields[$key]["WHERE"]))
1363 {
1364 $arSqlSearch_tmp1 = call_user_func_array(
1365 $arFields[$key]["WHERE"],
1366 array($val, $key, $strOperation, $strNegative, $arFields[$key]["FIELD"], $arFields, $arFilter)
1367 );
1368 if ($arSqlSearch_tmp1 !== false)
1369 $arSqlSearch_tmp[] = $arSqlSearch_tmp1;
1370 }
1371 else
1372 {
1373 if ($arFields[$key]["TYPE"] == "int")
1374 {
1375 if ((intval($val) == 0) && (mb_strpos($strOperation, "=") !== False))
1376 $arSqlSearch_tmp[] = "(".$arFields[$key]["FIELD"]." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND" : "OR")." ".(($strNegative == "Y") ? "NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." 0)";
1377 else
1378 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$arFields[$key]["FIELD"]." IS NULL OR NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".intval($val)." )";
1379 }
1380 elseif ($arFields[$key]["TYPE"] == "double")
1381 {
1382 $val = str_replace(",", ".", $val);
1383
1384 if ((DoubleVal($val) == 0) && (mb_strpos($strOperation, "=") !== False))
1385 $arSqlSearch_tmp[] = "(".$arFields[$key]["FIELD"]." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND" : "OR")." ".(($strNegative == "Y") ? "NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." 0)";
1386 else
1387 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$arFields[$key]["FIELD"]." IS NULL OR NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".DoubleVal($val)." )";
1388 }
1389 elseif ($arFields[$key]["TYPE"] == "string" || $arFields[$key]["TYPE"] == "char")
1390 {
1391 if ($strOperation == "QUERY")
1392 {
1393 $arSqlSearch_tmp[] = GetFilterQuery($arFields[$key]["FIELD"], $val, "Y");
1394 }
1395 else
1396 {
1397 if (($val == '') && (mb_strpos($strOperation, "=") !== False))
1398 $arSqlSearch_tmp[] = "(".$arFields[$key]["FIELD"]." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND NOT" : "OR")." (".$DB->Length($arFields[$key]["FIELD"])." <= 0) ".(($strNegative == "Y") ? "AND NOT" : "OR")." (".$arFields[$key]["FIELD"]." ".$strOperation." '".$DB->ForSql($val)."' )";
1399 else
1400 $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$arFields[$key]["FIELD"]." IS NULL OR NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." '".$DB->ForSql($val)."' )";
1401 }
1402 }
1403 elseif ($arFields[$key]["TYPE"] == "datetime")
1404 {
1405 if ($val == '')
1406 $arSqlSearch_tmp[] = ($strNegative=="Y"?"NOT":"")."(".$arFields[$key]["FIELD"]." IS NULL)";
1407 else
1408 $arSqlSearch_tmp[] = ($strNegative=="Y"?" ".$arFields[$key]["FIELD"]." IS NULL OR NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".$DB->CharToDateFunction($DB->ForSql($val), "FULL").")";
1409 }
1410 elseif ($arFields[$key]["TYPE"] == "date")
1411 {
1412 if ($val == '')
1413 $arSqlSearch_tmp[] = ($strNegative=="Y"?"NOT":"")."(".$arFields[$key]["FIELD"]." IS NULL)";
1414 else
1415 $arSqlSearch_tmp[] = ($strNegative=="Y"?" ".$arFields[$key]["FIELD"]." IS NULL OR NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".$DB->CharToDateFunction($DB->ForSql($val), "SHORT").")";
1416 }
1417 }
1418 }
1419 }
1420 }
1421
1422 if (isset($arFields[$key]["FROM"])
1423 && $arFields[$key]["FROM"] <> ''
1424 && !in_array($arFields[$key]["FROM"], $arAlreadyJoined))
1425 {
1426 if ($strSqlFrom <> '')
1427 $strSqlFrom .= " ";
1428 $strSqlFrom .= $arFields[$key]["FROM"];
1429 $arAlreadyJoined[] = $arFields[$key]["FROM"];
1430 }
1431
1432 $strSqlSearch_tmp = "";
1433 $countSqlSearch = count($arSqlSearch_tmp);
1434 for ($j = 0; $j < $countSqlSearch; $j++)
1435 {
1436 if ($j > 0)
1437 $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR ");
1438 $strSqlSearch_tmp .= "(".$arSqlSearch_tmp[$j].")";
1439 }
1440 if ($strOrNull == "Y")
1441 {
1442 if ($strSqlSearch_tmp <> '')
1443 $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR ");
1444 $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." IS ".($strNegative=="Y" ? "NOT " : "")."NULL)";
1445
1446 if ($arFields[$key]["TYPE"] == "int" || $arFields[$key]["TYPE"] == "double")
1447 {
1448 if ($strSqlSearch_tmp <> '')
1449 $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR ");
1450 $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." ".($strNegative=="Y" ? "<>" : "=")." 0)";
1451 }
1452 elseif ($arFields[$key]["TYPE"] == "string" || $arFields[$key]["TYPE"] == "char")
1453 {
1454 if ($strSqlSearch_tmp <> '')
1455 $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR ");
1456 $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." ".($strNegative=="Y" ? "<>" : "=")." '')";
1457 }
1458 }
1459
1460 if ($strSqlSearch_tmp != "")
1461 $arSqlSearch[] = "(".$strSqlSearch_tmp.")";
1462 }
1463 }
1464
1465 // custom subquery callback
1466 if (is_callable($callback))
1467 {
1468 $arSqlSearch[] = call_user_func_array($callback, array($arFields));
1469 }
1470
1471 $countSqlSearch = count($arSqlSearch);
1472 for ($i = 0; $i < $countSqlSearch; $i++)
1473 {
1474 if ($strSqlWhere != '')
1475 $strSqlWhere .= " AND ";
1476 $strSqlWhere .= "(".$arSqlSearch[$i].")";
1477 }
1478
1479 // <-- WHERE
1480
1481 // ORDER BY -->
1482 $arSqlOrder = Array();
1483 if (!is_array($arOrder))
1484 $arOrder = array();
1485 foreach ($arOrder as $by => $order)
1486 {
1487 $by = mb_strtoupper($by);
1488 $order = mb_strtoupper($order);
1489
1490 if ($order != "ASC")
1491 $order = "DESC";
1492 else
1493 $order = "ASC";
1494
1495 if (is_array($arGroupBy) && count($arGroupBy) > 0 && in_array($by, $arGroupBy))
1496 {
1497 $arSqlOrder[] = " ".$by." ".$order." ";
1498 }
1499 elseif (array_key_exists($by, $arFields))
1500 {
1501 $arSqlOrder[] = " ".$arFields[$by]["FIELD"]." ".$order." ";
1502
1503 if (isset($arFields[$by]["FROM"])
1504 && $arFields[$by]["FROM"] <> ''
1505 && !in_array($arFields[$by]["FROM"], $arAlreadyJoined))
1506 {
1507 if ($strSqlFrom <> '')
1508 $strSqlFrom .= " ";
1509 $strSqlFrom .= $arFields[$by]["FROM"];
1510 $arAlreadyJoined[] = $arFields[$by]["FROM"];
1511 }
1512 }
1513 elseif ($obUserFieldsSql)
1514 {
1515 $arSqlOrder[] = " ".$obUserFieldsSql->GetOrder($by)." ".$order." ";
1516 }
1517 }
1518
1519 $nullsLast = isset($arOptions['NULLS_LAST']) ? (bool)$arOptions['NULLS_LAST'] : false;
1520 $strSqlOrderBy = "";
1521 DelDuplicateSort($arSqlOrder);
1522 $countSqlOrder = count($arSqlOrder);
1523 for ($i=0; $i < $countSqlOrder; $i++)
1524 {
1525 if ($strSqlOrderBy <> '')
1526 $strSqlOrderBy .= ", ";
1527
1528 $order = (mb_substr($arSqlOrder[$i], -3) == "ASC") ? "ASC" : "DESC";
1529 if (!$nullsLast)
1530 {
1531 if(mb_strtoupper($DB->type)=="ORACLE")
1532 {
1533 if($order === "ASC")
1534 $strSqlOrderBy .= $arSqlOrder[$i]." NULLS FIRST";
1535 else
1536 $strSqlOrderBy .= $arSqlOrder[$i]." NULLS LAST";
1537 }
1538 else
1539 $strSqlOrderBy .= $arSqlOrder[$i];
1540 }
1541 else
1542 {
1543 $field = mb_substr($arSqlOrder[$i], 0, -mb_strlen($order) - 1);
1544 if(mb_strtoupper($DB->type) === "MYSQL")
1545 {
1546 if($order === 'ASC')
1547 $strSqlOrderBy .= '(CASE WHEN ISNULL('.$field.') THEN 1 ELSE 0 END) '.$order.', '.$field." ".$order;
1548 else
1549 $strSqlOrderBy .= $field." ".$order;
1550 }
1551 elseif(mb_strtoupper($DB->type) === "MSSQL")
1552 {
1553 if($order === 'ASC')
1554 $strSqlOrderBy .= '(CASE WHEN '.$field.' IS NULL THEN 1 ELSE 0 END) '.$order.', '.$field." ".$order;
1555 else
1556 $strSqlOrderBy .= $field." ".$order;
1557
1558 }
1559 elseif(mb_strtoupper($DB->type) === "ORACLE")
1560 {
1561 if($order === 'DESC')
1562 $strSqlOrderBy .= $field." ".$order." NULLS LAST";
1563 else
1564 $strSqlOrderBy .= $field." ".$order;
1565 }
1566 }
1567 }
1568 // <-- ORDER BY
1569
1570 return array(
1571 "SELECT" => $strSqlSelect,
1572 "FROM" => $strSqlFrom,
1573 "WHERE" => $strSqlWhere,
1574 "GROUPBY" => $strSqlGroupBy,
1575 "ORDERBY" => $strSqlOrderBy
1576 );
1577 }
1578
1579
1580 //*************** SELECT *********************/
1581 public static function GetByID($ID)
1582 {
1583 global $DB;
1584
1585 if (intval($ID) <= 0)
1586 return false;
1587
1588 if (isset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]) && is_array($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]) && is_set($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID], "ID"))
1589 {
1590 return $GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID];
1591 }
1592 else
1593 {
1594 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
1595
1596 if ($isOrderConverted != 'N')
1597 {
1598 $db_res = \Bitrix\Sale\Compatible\OrderCompatibility::getById($ID);
1599 }
1600 else
1601 {
1602 $strSql =
1603 "SELECT O.*, ".
1604 " ".$DB->DateToCharFunction("O.DATE_STATUS", "FULL")." as DATE_STATUS_FORMAT, ".
1605 " ".$DB->DateToCharFunction("O.DATE_INSERT", "SHORT")." as DATE_INSERT_FORMAT, ".
1606 " ".$DB->DateToCharFunction("O.DATE_UPDATE", "FULL")." as DATE_UPDATE_FORMAT, ".
1607 " ".$DB->DateToCharFunction("O.DATE_LOCK", "FULL")." as DATE_LOCK_FORMAT ".
1608 "FROM b_sale_order O ".
1609 "WHERE O.ID = ".$ID."";
1610
1611 $db_res = $DB->Query($strSql);
1612 }
1613
1614 if ($res = $db_res->Fetch())
1615 {
1616 if ($isOrderConverted != 'N')
1617 {
1618 $dataKeys = array_keys($res);
1619 foreach ($dataKeys as $key)
1620 {
1621
1622 if (!empty($res[$key])
1623 && (($res[$key] instanceof \Bitrix\Main\Type\DateTime)
1624 || ($res[$key] instanceof \Bitrix\Main\Type\Date)))
1625 {
1627 $dateObject = $res[$key];
1628
1629 if ($key == "DATE_INSERT")
1630 {
1631 $res['DATE_INSERT_FORMAT'] = Sale\Compatible\OrderCompatibility::convertDateFieldToFormat($dateObject, FORMAT_DATE);
1632 }
1633 elseif ($key == "DATE_STATUS")
1634 {
1635 $res['DATE_STATUS_FORMAT'] = Sale\Compatible\OrderCompatibility::convertDateFieldToFormat($dateObject, FORMAT_DATETIME);
1636 }
1637 elseif ($key == "DATE_UPDATE")
1638 {
1639 $res['DATE_UPDATE_FORMAT'] = Sale\Compatible\OrderCompatibility::convertDateFieldToFormat($dateObject, FORMAT_DATETIME);
1640 }
1641 elseif ($key == "DATE_LOCK")
1642 {
1643 $res['DATE_LOCK_FORMAT'] = Sale\Compatible\OrderCompatibility::convertDateFieldToFormat($dateObject, FORMAT_DATETIME);
1644 }
1645
1646 $res[$key] = $dateObject->format('Y-m-d H:i:s');
1647 }
1648 }
1649 $res = \Bitrix\Sale\Compatible\OrderFetchAdapter::convertRowData($res);
1650 }
1651
1652 $GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID] = $res;
1653 return $res;
1654 }
1655 }
1656
1657 return False;
1658 }
1659
1660
1661 //*************** EVENTS *********************/
1662 public static function OnBeforeCurrencyDelete($currency)
1663 {
1664 global $APPLICATION;
1665
1666 $currency = (string)$currency;
1667 if ($currency === '')
1668 return true;
1669
1670 if (Internals\OrderTable::getList(array(
1671 'filter' => array('=CURRENCY' => $currency),
1672 'limit' => 1
1673 ))->fetch())
1674 {
1675 $APPLICATION->ThrowException(Loc::getMessage("SKGO_ERROR_ORDERS_CURRENCY" , array("#CURRENCY#" => $currency)), "ERROR_ORDERS_CURRENCY");
1676 return false;
1677 }
1678
1679 if (Internals\OrderArchiveTable::getList(array(
1680 'select' => array('ID'),
1681 'filter' => array('=CURRENCY' => $currency),
1682 'limit' => 1
1683 ))->fetch())
1684 {
1685 $APPLICATION->ThrowException(Loc::getMessage("SKGO_ERROR_ORDERS_ARCHIVE_CURRENCY", array("#CURRENCY#" => $currency)), "ERROR_ORDERS_ARCHIVE_CURRENCY");
1686 return false;
1687 }
1688
1689 return true;
1690 }
1691
1692 public static function OnBeforeUserDelete($userID)
1693 {
1694 global $APPLICATION;
1695
1696 $userID = intval($userID);
1697 if ($userID <= 0)
1698 {
1699 $APPLICATION->ThrowException("Empty user ID", "EMPTY_USER_ID");
1700 return false;
1701 }
1702
1703 if (Internals\OrderTable::getList(array(
1704 'filter' => array('=USER_ID' => $userID),
1705 'limit' => 1
1706 ))->fetch())
1707 {
1708 $APPLICATION->ThrowException(Loc::getMessage("SKGO_ERROR_ORDERS", array("#USER_ID#" => $userID)), "ERROR_ORDERS");
1709 return false;
1710 }
1711
1712 if (Internals\OrderArchiveTable::getList(array(
1713 'filter' => array('=USER_ID' => $userID),
1714 'limit' => 1
1715 ))->fetch())
1716 {
1717 $APPLICATION->ThrowException(Loc::getMessage("SKGO_ERROR_ORDERS_ARCHIVE", array("#USER_ID#" => $userID)), "ERROR_ORDERS_ARCHIVE");
1718 return false;
1719 }
1720
1721 return true;
1722 }
1723
1724 //*************** ACTIONS *********************/
1725 public static function PayOrder($ID, $val, $bWithdraw = True, $bPay = True, $recurringID = 0, $arAdditionalFields = array())
1726 {
1727 global $DB, $USER, $APPLICATION;
1728
1729 $ID = intval($ID);
1730 $val = (($val != "Y") ? "N" : "Y");
1731 $bWithdraw = ($bWithdraw ? True : False);
1732 $bPay = ($bPay ? True : False);
1733 $recurringID = intval($recurringID);
1734
1735 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
1736
1737
1738 $NO_CHANGE_STATUS = 'N';
1739 if (isset($arAdditionalFields['NOT_CHANGE_STATUS']) && $arAdditionalFields['NOT_CHANGE_STATUS'] === 'Y')
1740 {
1741 $NO_CHANGE_STATUS = "Y";
1742 unset($arAdditionalFields["NOT_CHANGE_STATUS"]);
1743 }
1744
1745 if ($ID <= 0)
1746 {
1747 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID"), "NO_ORDER_ID");
1748 return False;
1749 }
1750
1751 $arOrder = CSaleOrder::GetByID($ID);
1752 if (!$arOrder)
1753 {
1754 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
1755 return False;
1756 }
1757
1758 if ($arOrder["PAYED"] == $val)
1759 {
1760 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_PAY")), "ALREADY_FLAG");
1761 return False;
1762 }
1763
1764 foreach(GetModuleEvents("sale", "OnSaleBeforePayOrder", true) as $arEvent)
1765 if (ExecuteModuleEventEx($arEvent, Array($ID, $val, $bWithdraw, $bPay, $recurringID, $arAdditionalFields))===false)
1766 return false;
1767
1768 if ($isOrderConverted == "N" && $bWithdraw)
1769 {
1770 if ($val == "Y")
1771 {
1772 $needPaySum = DoubleVal($arOrder["PRICE"]) - DoubleVal($arOrder["SUM_PAID"]);
1773
1774 if ($bPay)
1775 if (!CSaleUserAccount::UpdateAccount($arOrder["USER_ID"], $needPaySum, $arOrder["CURRENCY"], "OUT_CHARGE_OFF", $ID))
1776 return False;
1777
1778 if ($needPaySum > 0 && !CSaleUserAccount::Pay($arOrder["USER_ID"], $needPaySum, $arOrder["CURRENCY"], $ID, False))
1779 return False;
1780 }
1781 else
1782 {
1783 if (!CSaleUserAccount::UpdateAccount($arOrder["USER_ID"], $arOrder["PRICE"], $arOrder["CURRENCY"], "ORDER_UNPAY", $ID))
1784 return False;
1785 }
1786 }
1787
1788 $connection = Application::getConnection();
1789 $helper = $connection->getSqlHelper();
1790
1791 $arFields = array(
1792 "PAYED" => $val,
1793 "=DATE_PAYED" => $helper->getCurrentDateTimeFunction(),
1794 "EMP_PAYED_ID" => ((int)$USER->GetID() > 0 ? (int)$USER->GetID() : false),
1795 "SUM_PAID" => 0
1796 );
1797 if (count($arAdditionalFields) > 0)
1798 {
1799 foreach ($arAdditionalFields as $addKey => $addValue)
1800 {
1801 if (!array_key_exists($addKey, $arFields))
1802 $arFields[$addKey] = $addValue;
1803 }
1804 }
1805
1806 if ($isOrderConverted != 'N')
1807 {
1808 $errorMessage = "";
1810 $r = \Bitrix\Sale\Compatible\OrderCompatibility::pay($ID, $arFields, $bWithdraw, $bPay);
1811
1812 if (!$r->isSuccess(true))
1813 {
1814 foreach($r->getErrorMessages() as $error)
1815 {
1816 $errorMessage .= " ".$error;
1817 }
1818
1819 $APPLICATION->ThrowException(Loc::getMessage("SKGB_PAY_ERROR", array("#MESSAGE#" => $errorMessage)), "RESERVATION_ERROR");
1820 return false;
1821 }
1822
1823 $res = true;
1824 }
1825 else
1826 {
1828 foreach(GetModuleEvents("sale", "OnSalePayOrder", true) as $arEvent)
1829 ExecuteModuleEventEx($arEvent, Array($ID, $val));
1830 }
1831
1832 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
1833
1834 if ($val == "Y")
1835 {
1837 $arOrder = CSaleOrder::GetByID($ID);
1839
1840 if ($NO_CHANGE_STATUS != "Y")
1841 {
1842 $orderStatus = COption::GetOptionString("sale", "status_on_paid", "");
1843 if($orderStatus <> '' && $orderStatus != $arOrder["STATUS_ID"])
1844 {
1845 $dbStatus = CSaleStatus::GetList(Array("SORT" => "ASC"), Array("LID" => LANGUAGE_ID));
1846 while ($arStatus = $dbStatus->GetNext())
1847 {
1848 $arStatuses[$arStatus["ID"]] = $arStatus["SORT"];
1849 }
1850
1851 if($arStatuses[$orderStatus] >= $arStatuses[$arOrder["STATUS_ID"]])
1852 CSaleOrder::StatusOrder($ID, $orderStatus);
1853 }
1854 }
1855
1856 $userEMail = "";
1857 $dbOrderProp = CSaleOrderPropsValue::GetList(Array(), Array("ORDER_ID" => $arOrder["ID"], "PROP_IS_EMAIL" => "Y"));
1858 if($arOrderProp = $dbOrderProp->Fetch())
1859 $userEMail = $arOrderProp["VALUE"];
1860
1861 if($userEMail == '')
1862 {
1863 $dbUser = CUser::GetByID($arOrder["USER_ID"]);
1864 if($arUser = $dbUser->Fetch())
1865 $userEMail = $arUser["EMAIL"];
1866 }
1867
1868 if ($isOrderConverted == 'N')
1869 {
1870 $arFields = Array(
1871 "ORDER_ID" => $arOrder["ACCOUNT_NUMBER"],
1872 "ORDER_DATE" => $arOrder["DATE_INSERT_FORMAT"],
1873 "EMAIL" => $userEMail,
1874 "SALE_EMAIL" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER["SERVER_NAME"])
1875 );
1876 $eventName = "SALE_ORDER_PAID";
1877
1878 $bSend = true;
1879 foreach(GetModuleEvents("sale", "OnOrderPaySendEmail", true) as $arEvent)
1880 {
1881 if (ExecuteModuleEventEx($arEvent, Array($ID, &$eventName, &$arFields))===false)
1882 $bSend = false;
1883 }
1884
1885 if($bSend)
1886 {
1887 $event = new CEvent;
1888 $event->Send($eventName, $arOrder["LID"], $arFields, "N");
1889 }
1890 }
1891
1892 CSaleMobileOrderPush::send("ORDER_PAYED", array("ORDER" => $arOrder));
1893
1894 if (CModule::IncludeModule("statistic"))
1895 {
1896 CStatEvent::AddByEvents("eStore", "order_paid", $ID, "", $arOrder["STAT_GID"], $arOrder["PRICE"], $arOrder["CURRENCY"]);
1897 }
1898 }
1899 else
1900 {
1901 if (CModule::IncludeModule("statistic"))
1902 {
1903 CStatEvent::AddByEvents("eStore", "order_chargeback", $ID, "", $arOrder["STAT_GID"], $arOrder["PRICE"], $arOrder["CURRENCY"], "Y");
1904 }
1905 }
1906
1907 if ($isOrderConverted == 'N')
1908 {
1909 //reservation
1910 if (COption::GetOptionString("sale", "product_reserve_condition", "O") == "P" && $arOrder["RESERVED"] != $val)
1911 {
1912 if (!CSaleOrder::ReserveOrder($ID, $val))
1913 return false;
1914 }
1915
1916 if ($val == "Y")
1917 {
1918 $allowDelivery = COption::GetOptionString("sale", "status_on_payed_2_allow_delivery", "");
1919 if($allowDelivery == "Y" && $arOrder["ALLOW_DELIVERY"] == "N")
1920 {
1921 CSaleOrder::DeliverOrder($ID, "Y");
1922 }
1923 }
1924 }
1925
1926 return $res;
1927 }
1928
1929 public static function DeliverOrder($ID, $val, $recurringID = 0, $arAdditionalFields = array())
1930 {
1931 global $DB, $USER, $APPLICATION;
1932
1933 $ID = intval($ID);
1934 $val = (($val != "Y") ? "N" : "Y");
1935 $recurringID = intval($recurringID);
1936
1937 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
1938
1939 $NO_CHANGE_STATUS = "N";
1940 if (isset($arAdditionalFields['NOT_CHANGE_STATUS']) && $arAdditionalFields['NOT_CHANGE_STATUS'] === 'Y')
1941 {
1942 $NO_CHANGE_STATUS = "Y";
1943 unset($arAdditionalFields["NOT_CHANGE_STATUS"]);
1944 }
1945
1946 if ($ID <= 0)
1947 {
1948 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID"), "NO_ORDER_ID");
1949 return False;
1950 }
1951
1952 $arOrder = CSaleOrder::GetByID($ID);
1953 if (!$arOrder)
1954 {
1955 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
1956 return False;
1957 }
1958
1959 if ($arOrder["ALLOW_DELIVERY"] == $val)
1960 {
1961 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_DELIVERY")), "ALREADY_FLAG");
1962 return False;
1963 }
1964
1965 foreach(GetModuleEvents("sale", "OnSaleBeforeDeliveryOrder", true) as $arEvent)
1966 if (ExecuteModuleEventEx($arEvent, Array($ID, $val, $recurringID, $arAdditionalFields))===false)
1967 return false;
1968
1969 if ($isOrderConverted == 'N')
1970 {
1971 $arFields = array(
1972 "ALLOW_DELIVERY" => $val,
1973 "=DATE_ALLOW_DELIVERY" => $DB->GetNowFunction(),
1974 "EMP_ALLOW_DELIVERY_ID" => ( intval($USER->GetID())>0 ? intval($USER->GetID()) : false )
1975 );
1976 if (count($arAdditionalFields) > 0)
1977 {
1978 foreach ($arAdditionalFields as $addKey => $addValue)
1979 {
1980 if (!array_key_exists($addKey, $arFields))
1981 $arFields[$addKey] = $addValue;
1982 }
1983 }
1985 }
1986 else
1987 {
1988 $errorMessage = '';
1989
1991 $r = \Bitrix\Sale\Compatible\OrderCompatibility::allowDelivery($ID, ($val == "Y" ? true : false));
1992 if (!$r->isSuccess(true))
1993 {
1994 foreach($r->getErrorMessages() as $error)
1995 {
1996 $errorMessage .= " ".$error;
1997 }
1998
1999 $APPLICATION->ThrowException(Loc::getMessage("SKGO_DELIVER_ERROR", array("#MESSAGE#" => $errorMessage)), "DELIVER_ERROR");
2000 return false;
2001 }
2002
2003 $res = true;
2004 }
2005
2006 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2007
2008 if ($recurringID <= 0)
2009 {
2010 if (intval($arOrder["RECURRING_ID"]) > 0)
2011 $recurringID = intval($arOrder["RECURRING_ID"]);
2012 }
2013
2014 CSaleBasket::OrderDelivery($ID, (($val=="Y") ? True : False), $recurringID);
2015
2016 if ($isOrderConverted == 'N')
2017 {
2018 foreach(GetModuleEvents("sale", "OnSaleDeliveryOrder", true) as $arEvent)
2019 ExecuteModuleEventEx($arEvent, Array($ID, $val));
2020 }
2021
2022 if ($val == "Y")
2023 {
2025 $arOrder = CSaleOrder::GetByID($ID);
2027
2028 if ($NO_CHANGE_STATUS != "Y")
2029 {
2030 $orderStatus = COption::GetOptionString("sale", "status_on_allow_delivery", "");
2031 if($orderStatus <> '' && $orderStatus != $arOrder["STATUS_ID"])
2032 {
2033 $dbStatus = CSaleStatus::GetList(Array("SORT" => "ASC"), Array("LID" => LANGUAGE_ID), false, false, Array("ID", "SORT"));
2034 while ($arStatus = $dbStatus->GetNext())
2035 {
2036 $arStatuses[$arStatus["ID"]] = $arStatus["SORT"];
2037 }
2038
2039 if($arStatuses[$orderStatus] >= $arStatuses[$arOrder["STATUS_ID"]])
2040 CSaleOrder::StatusOrder($ID, $orderStatus);
2041 }
2042 }
2043
2044 $userEMail = "";
2045 $dbOrderProp = CSaleOrderPropsValue::GetList(Array(), Array("ORDER_ID" => $arOrder["ID"], "PROP_IS_EMAIL" => "Y"));
2046 if($arOrderProp = $dbOrderProp->Fetch())
2047 $userEMail = $arOrderProp["VALUE"];
2048
2049 if($userEMail == '')
2050 {
2051 $dbUser = CUser::GetByID($arOrder["USER_ID"]);
2052 if($arUser = $dbUser->Fetch())
2053 $userEMail = $arUser["EMAIL"];
2054 }
2055
2056 if ($isOrderConverted == 'N')
2057 {
2058 $eventName = "SALE_ORDER_DELIVERY";
2059 $arFields = Array(
2060 "ORDER_ID" => $arOrder["ACCOUNT_NUMBER"],
2061 "ORDER_DATE" => $arOrder["DATE_INSERT_FORMAT"],
2062 "EMAIL" => $userEMail,
2063 "SALE_EMAIL" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER["SERVER_NAME"])
2064 );
2065
2066 $bSend = true;
2067 foreach(GetModuleEvents("sale", "OnOrderDeliverSendEmail", true) as $arEvent)
2068 if (ExecuteModuleEventEx($arEvent, Array($ID, &$eventName, &$arFields))===false)
2069 $bSend = false;
2070
2071 if($bSend)
2072 {
2073 $event = new CEvent;
2074 $event->Send($eventName, $arOrder["LID"], $arFields, "N");
2075 }
2076 }
2077
2078 CSaleMobileOrderPush::send("ORDER_DELIVERY_ALLOWED", array("ORDER" => $arOrder));
2079 }
2080
2081 //reservation
2082 if (COption::GetOptionString("sale", "product_reserve_condition", "O") == "D" && $arOrder["RESERVED"] != $val)
2083 {
2084 if (!CSaleOrder::ReserveOrder($ID, $val))
2085 return false;
2086 }
2087
2088 //proceed to deduction
2089 if ($val == "Y")
2090 {
2091 $allowDeduction = COption::GetOptionString("sale", "allow_deduction_on_delivery", "");
2092 if($allowDeduction == "Y" && $arOrder["DEDUCTED"] == "N")
2093 {
2095 }
2096 }
2097
2098 return $res;
2099 }
2100
2101 public static function DeductOrder($ID, $val, $description = "", $bAutoDeduction = true, $arStoreBarcodeOrderFormData = array(), $recurringID = 0)
2102 {
2103 global $DB, $USER, $APPLICATION;
2104
2105 $ID = intval($ID);
2106 $val = (($val != "Y") ? "N" : "Y");
2107 $description = Trim($description);
2108 $recurringID = intval($recurringID);
2109
2110 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
2111
2112 if ($ID <= 0)
2113 {
2114 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID"), "NO_ORDER_ID");
2115 return false;
2116 }
2117
2118 $arOrder = CSaleOrder::GetByID($ID);
2119 if (!$arOrder)
2120 {
2121 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
2122 return false;
2123 }
2124
2125 if ($arOrder["DEDUCTED"] == $val)
2126 {
2127 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_DEDUCTION")), "ALREADY_FLAG");
2128 return false;
2129 }
2130
2131 foreach(GetModuleEvents("sale", "OnSaleBeforeDeductOrder", true) as $arEvent)
2132 if (ExecuteModuleEventEx($arEvent, Array($ID, $val, $description, $bAutoDeduction, $arStoreBarcodeOrderFormData, $recurringID))===false)
2133 return false;
2134
2135 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2136
2137 if ($recurringID <= 0)
2138 {
2139 if (intval($arOrder["RECURRING_ID"]) > 0)
2140 $recurringID = intval($arOrder["RECURRING_ID"]);
2141 }
2142
2143 $arDeductResult = CSaleBasket::OrderDeduction($ID, (($val == "N") ? true : false), $recurringID, $bAutoDeduction, $arStoreBarcodeOrderFormData);
2144
2145 if (array_key_exists("ERROR", $arDeductResult))
2146 {
2147 if ($isOrderConverted == 'N')
2148 {
2149 CSaleOrder::SetMark($ID, Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"])));
2150 }
2151
2152 $APPLICATION->ThrowException(Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"])), "DEDUCTION_ERROR");
2153 return false;
2154 }
2155 else
2156 {
2157 if ($arOrder["MARKED"] == "Y")
2158 {
2160 }
2161 }
2162
2163 if ($isOrderConverted != 'N')
2164 {
2165 if ($arDeductResult["RESULT"])
2166 {
2167 if($val == "Y")
2168 CSaleMobileOrderPush::send("ORDER_DEDUCTED", array("ORDER" => $arOrder));
2169
2170 return true;
2171 }
2172 }
2173 else
2174 {
2175
2176 if ($arDeductResult["RESULT"])
2177 {
2178 if ($val == "Y")
2179 {
2180 $arFields = array(
2181 "DEDUCTED" => "Y",
2182 "EMP_DEDUCTED_ID" => ( intval($USER->GetID())>0 ? intval($USER->GetID()) : false ),
2183 "=DATE_DEDUCTED" => $DB->GetNowFunction()
2184 );
2185 }
2186 else
2187 {
2188 $arFields = array(
2189 "DEDUCTED" => "N",
2190 "EMP_DEDUCTED_ID" => ( intval($USER->GetID())>0 ? intval($USER->GetID()) : false ),
2191 "=DATE_DEDUCTED" => $DB->GetNowFunction()
2192 );
2193
2194 if ($description <> '')
2195 $arFields["REASON_UNDO_DEDUCTED"] = $description;
2196 }
2198
2199 if($val == "Y" && $res)
2200 CSaleMobileOrderPush::send("ORDER_DEDUCTED", array("ORDER" => $arOrder));
2201 }
2202 else
2203 $res = false;
2204
2205 foreach(GetModuleEvents("sale", "OnSaleDeductOrder", true) as $arEvent)
2206 ExecuteModuleEventEx($arEvent, Array($ID, $val));
2207
2208 if ($res)
2209 return $res;
2210 else
2211 return false;
2212
2213 }
2214
2215
2216 }
2217
2218 public static function ReserveOrder($ID, $val)
2219 {
2220 global $APPLICATION;
2221
2222 $ID = intval($ID);
2223 $val = (($val != "Y") ? "N" : "Y");
2224 $errorMessage = "";
2225
2226 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
2227
2228 if ($ID <= 0)
2229 {
2230 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID"), "NO_ORDER_ID");
2231 return false;
2232 }
2233
2234 $arOrder = CSaleOrder::GetByID($ID);
2235 if (!$arOrder)
2236 {
2237 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
2238 return false;
2239 }
2240
2241 if ($arOrder["RESERVED"] == $val)
2242 {
2243 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_RESERVATION")), "ALREADY_FLAG");
2244 return false;
2245 }
2246
2247 foreach(GetModuleEvents("sale", "OnSaleBeforeReserveOrder", true) as $arEvent)
2248 if (ExecuteModuleEventEx($arEvent, Array($ID, $val))===false)
2249 return false;
2250
2251 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2252
2253 if ($isOrderConverted != 'N')
2254 {
2256 $r = \Bitrix\Sale\Compatible\OrderCompatibility::reserve($ID, $val);
2257
2258 if (!$r->isSuccess(true))
2259 {
2260 foreach($r->getErrorMessages() as $error)
2261 {
2262 $errorMessage .= " ".$error;
2263 }
2264
2265 $APPLICATION->ThrowException(Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $errorMessage)), "RESERVATION_ERROR");
2266
2267 return false;
2268 }
2269
2270 $res = true;
2271 }
2272 else
2273 {
2274 $res = CSaleOrder::Update($ID, array("RESERVED" => $val), false);
2275
2276 $arRes = CSaleBasket::OrderReservation($ID, (($val == "N") ? true : false));
2277 if (array_key_exists("ERROR", $arRes))
2278 {
2279 foreach ($arRes["ERROR"] as $arError)
2280 {
2281 $errorMessage .= " ".$arError["MESSAGE"];
2282 }
2283
2284 CSaleOrder::SetMark($ID, Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $errorMessage)));
2285 $APPLICATION->ThrowException(Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $errorMessage)), "RESERVATION_ERROR");
2286 return false;
2287 }
2288 else
2289 {
2290 if ($arOrder["MARKED"] == "Y")
2291 {
2293 }
2294 }
2295 }
2296
2297 foreach(GetModuleEvents("sale", "OnSaleReserveOrder", true) as $arEvent)
2298 ExecuteModuleEventEx($arEvent, Array($ID, $val));
2299
2300 return $res;
2301 }
2302
2303 public static function CancelOrder($ID, $val, $description = "")
2304 {
2305 global $DB, $USER, $APPLICATION;
2306
2307 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
2308
2309 $ID = intval($ID);
2310 $val = (($val != "Y") ? "N" : "Y");
2311 $description = Trim($description);
2312
2313 if ($ID <= 0)
2314 {
2315 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID1"), "NO_ORDER_ID");
2316 return false;
2317 }
2318
2319 $arOrder = CSaleOrder::GetByID($ID);
2320 if (!$arOrder)
2321 {
2322 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
2323 return false;
2324 }
2325
2326 if ($arOrder["CANCELED"] == $val)
2327 {
2328 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_CANCEL")), "ALREADY_FLAG");
2329 return false;
2330 }
2331
2332 if ($isOrderConverted != 'N')
2333 {
2334 $r = \Bitrix\Sale\Compatible\OrderCompatibility::cancel($ID, $val, $description);
2335 if ($r->isSuccess(true))
2336 {
2337 $res = true;
2338 }
2339 else
2340 {
2341 $errorMessage = "";
2342 foreach($r->getErrorMessages() as $error)
2343 {
2344 $errorMessage .= " ".$error;
2345 }
2346
2347 $APPLICATION->ThrowException(Loc::getMessage("SKGO_CANCEL_ERROR", array("#MESSAGE#" => $errorMessage)), "CANCEL_ERROR");
2348 return false;
2349 }
2350 }
2351 else
2352 {
2353
2354 foreach(GetModuleEvents("sale", "OnSaleBeforeCancelOrder", true) as $arEvent)
2355 if (ExecuteModuleEventEx($arEvent, Array($ID, $val))===false)
2356 return false;
2357
2358 if ($val == "Y")
2359 {
2360 if ($arOrder["DEDUCTED"] == "Y")
2361 {
2362 if (!CSaleOrder::DeductOrder($ID, "N"))
2363 return false;
2364 }
2365
2366 if ($arOrder["RESERVED"] == "Y")
2367 {
2368 if (!CSaleOrder::ReserveOrder($ID, "N"))
2369 return false;
2370 }
2371
2372 if ($arOrder["PAYED"] == "Y")
2373 {
2374 if (!CSaleOrder::PayOrder($ID, "N", True, True))
2375 return False;
2376 }
2377 else
2378 {
2379 $arOrder["SUM_PAID"] = DoubleVal($arOrder["SUM_PAID"]);
2380 if ($arOrder["SUM_PAID"] > 0)
2381 {
2382 if (!CSaleUserAccount::UpdateAccount($arOrder["USER_ID"], $arOrder["SUM_PAID"], $arOrder["CURRENCY"], "ORDER_CANCEL_PART", $ID))
2383 return False;
2384 CSaleOrder::Update($arOrder["ID"], array("SUM_PAID" => 0));
2385 }
2386 }
2387
2388 if ($arOrder["ALLOW_DELIVERY"] == "Y")
2389 {
2390 if (!CSaleOrder::DeliverOrder($ID, "N"))
2391 return False;
2392 }
2393 }
2394 else //if undo cancel
2395 {
2396 if (COption::GetOptionString("sale", "product_reserve_condition", "O") == "O" && $arOrder["RESERVED"] != "Y")
2397 {
2398 if (!CSaleOrder::ReserveOrder($ID, "Y"))
2399 return false;
2400 }
2401 }
2402
2403 $arFields = array(
2404 "CANCELED" => $val,
2405 "=DATE_CANCELED" => $DB->GetNowFunction(),
2406 "REASON_CANCELED" => ( $description <> '' ? $description : false ),
2407 "EMP_CANCELED_ID" => ( intval($USER->GetID())>0 ? intval($USER->GetID()) : false )
2408 );
2410 }
2411
2412 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2413
2414 if ($isOrderConverted == 'N')
2415 {
2416 //this method is used only for catalogs without reservation and deduction support
2417 CSaleBasket::OrderCanceled($ID, (($val=="Y") ? True : False));
2418
2419 foreach(GetModuleEvents("sale", "OnSaleCancelOrder", true) as $arEvent)
2420 ExecuteModuleEventEx($arEvent, Array($ID, $val, $description));
2421 }
2422
2423 if ($val == "Y")
2424 {
2425 CTimeZone::Disable();
2426 $arOrder = CSaleOrder::GetByID($ID);
2427 CTimeZone::Enable();
2428
2429 $userEmail = "";
2430 $dbOrderProp = CSaleOrderPropsValue::GetList(Array(), Array("ORDER_ID" => $ID, "PROP_IS_EMAIL" => "Y"));
2431 if($arOrderProp = $dbOrderProp->Fetch())
2432 $userEmail = $arOrderProp["VALUE"];
2433 if($userEmail == '')
2434 {
2435 $dbUser = CUser::GetByID($arOrder["USER_ID"]);
2436 if($arUser = $dbUser->Fetch())
2437 $userEmail = $arUser["EMAIL"];
2438 }
2439
2440 if (CModule::IncludeModule("statistic"))
2441 {
2442 CStatEvent::AddByEvents("eStore", "order_cancel", $ID, "", $arOrder["STAT_GID"]);
2443 }
2444 }
2445
2446 return $res;
2447 }
2448
2449 public static function StatusOrder($ID, $val)
2450 {
2451 global $DB, $USER, $APPLICATION;
2452
2453 $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y');
2454
2455 $ID = intval($ID);
2456 $val = trim($val);
2457
2458 if ($ID <= 0)
2459 {
2460 $APPLICATION->ThrowException(Loc::getMessage("SKGO_NO_ORDER_ID1"), "NO_ORDER_ID");
2461 return false;
2462 }
2463
2464 $arOrder = CSaleOrder::GetByID($ID);
2465 if (!$arOrder)
2466 {
2467 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_NO_ORDER")), "NO_ORDER");
2468 return false;
2469 }
2470
2471 if ($arOrder["STATUS_ID"] == $val)
2472 {
2473 $APPLICATION->ThrowException(str_replace("#ID#", $ID, Loc::getMessage("SKGO_DUB_STATUS")), "ALREADY_FLAG");
2474 return false;
2475 }
2476
2477 $arFields = array(
2478 "STATUS_ID" => $val,
2479 "=DATE_STATUS" => $DB->GetNowFunction(),
2480 "EMP_STATUS_ID" => ((isset($USER) && $USER instanceof \CUser) && intval($USER->GetID())>0 ? intval($USER->GetID()) : false )
2481 );
2483
2484 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2485
2486 return $res;
2487 }
2488
2489 public static function CommentsOrder($ID, $val)
2490 {
2491 $ID = intval($ID);
2492 $val = Trim($val);
2493
2494 $arFields = array(
2495 "COMMENTS" => ( $val <> '' ? $val : false )
2496 );
2498
2499 unset($GLOBALS["SALE_ORDER"]["SALE_ORDER_CACHE_".$ID]);
2500
2501 return $res;
2502 }
2503
2504 public static function Lock($ID)
2505 {
2506 global $DB;
2507
2508 $ID = intval($ID);
2509 if ($ID <= 0)
2510 return False;
2511
2512 $arFields = array(
2513 "DATE_LOCK" => new \Bitrix\Main\Type\DateTime(),
2514 "LOCKED_BY" => $GLOBALS["USER"]->GetID()
2515 );
2516
2517 return Sale\Internals\OrderTable::update($ID, $arFields)->isSuccess();
2518 }
2519
2520 public static function UnLock($ID)
2521 {
2522 $ID = intval($ID);
2523 if ($ID <= 0)
2524 return False;
2525
2526 $arOrder = CSaleOrder::GetByID($ID);
2527 if (!$arOrder)
2528 return False;
2529
2530 $userRights = CMain::GetUserRight("sale", $GLOBALS["USER"]->GetUserGroupArray(), "Y", "Y");
2531
2532 if (($userRights >= "W") || ($arOrder["LOCKED_BY"] == $GLOBALS["USER"]->GetID()))
2533 {
2534 $arFields = array(
2535 "DATE_LOCK" => false,
2536 "LOCKED_BY" => false
2537 );
2538
2539 return Sale\Internals\OrderTable::update($ID, $arFields)->isSuccess();
2540 }
2541
2542 return False;
2543 }
2544
2545 public static function IsLocked($ID, &$lockedBY, &$dateLock)
2546 {
2547 $ID = (int)$ID;
2548
2549 return static::GetLockStatus($ID, $lockedBY, $dateLock) === 'red';
2550 }
2551
2552 public static function GetLockStatus($ID, &$lockedBY, &$dateLock)
2553 {
2554 $ID = (int)$ID;
2555 if ($ID <= 0)
2556 {
2557 return 'green';
2558 }
2559
2560 $order = Sale\Internals\OrderTable::getRow([
2561 'select' => [
2562 'LOCKED_BY',
2563 'LOCK_STATUS',
2564 'DATE_LOCK',
2565 ],
2566 'filter' => [
2567 '=ID' => $ID,
2568 ],
2569 ]);
2570
2571 if ($order === null)
2572 {
2573 return 'green';
2574 }
2575
2576 $lockedBY = $order['LOCKED_BY'];
2577 $dateLock = $order['DATE_LOCK'] instanceof Main\Type\DateTime ? $order['DATE_LOCK']->toString() : $order['DATE_LOCK'];
2578
2579 return $order['LOCK_STATUS'];
2580 }
2581
2582 public static function RemindPayment()
2583 {
2584 $reminder = COption::GetOptionString("sale", "pay_reminder", "");
2585 $arReminder = unserialize($reminder, ['allowed_classes' => false]);
2586
2587 if(!empty($arReminder))
2588 {
2589 $arSites = Array();
2590 $minDay = time();
2591 foreach($arReminder as $key => $val)
2592 {
2593 $use = $val["use"] ?? null;
2594 $frequency = (float)($val["frequency"] ?? 0.0);
2595
2596 if ($use === "Y" && $frequency > 0)
2597 {
2598 $arSites[] = $key;
2599 $days = Array();
2600
2601 for($i=0; $i <= floor($val["period"] / $frequency); $i++)
2602 {
2603 $day = AddToTimeStamp(Array("DD" => -($val["after"] + $val["period"] - $frequency*$i)));
2604 if($day < time())
2605 {
2606 if($minDay > $day)
2607 $minDay = $day;
2608
2609 $day = ConvertTimeStamp($day);
2610
2611 $days[] = $day;
2612 }
2613 }
2614 $arReminder[$key]["days"] = $days;
2615 }
2616 }
2617
2618 if(!empty($arSites))
2619 {
2620 $bTmpUser = False;
2621 if (!isset($GLOBALS["USER"]) || !is_object($GLOBALS["USER"]))
2622 {
2623 $bTmpUser = True;
2624 $GLOBALS["USER"] = new CUser;
2625 }
2626
2627 $arFilter = Array(
2628 "LID" => $arSites,
2629 "PAYED" => "N",
2630 "CANCELED" => "N",
2631 "ALLOW_DELIVERY" => "N",
2632 ">=DATE_INSERT" => ConvertTimeStamp($minDay),
2633 );
2634
2635 $dbOrder = CSaleOrder::GetList(Array("ID" => "DESC"), $arFilter, false, false, Array("ID", "DATE_INSERT", "PAYED", "USER_ID", "LID", "PRICE", "CURRENCY", "ACCOUNT_NUMBER"));
2636 while($arOrder = $dbOrder -> GetNext())
2637 {
2638 $date_insert = ConvertDateTime($arOrder["DATE_INSERT"], CSite::GetDateFormat("SHORT"));
2639
2640 if(in_array($date_insert, $arReminder[$arOrder["LID"]]["days"]))
2641 {
2642
2643 $strOrderList = "";
2644 $dbBasketTmp = CSaleBasket::GetList(
2645 array("NAME" => "ASC"),
2646 array("ORDER_ID" => $arOrder["ID"]),
2647 false,
2648 false,
2649 array("ID", "NAME", "QUANTITY")
2650 );
2651 while ($arBasketTmp = $dbBasketTmp->Fetch())
2652 {
2653 $strOrderList .= $arBasketTmp["NAME"]." (".$arBasketTmp["QUANTITY"].")";
2654 $strOrderList .= "\n";
2655 }
2656
2657 $payerEMail = "";
2658 $dbOrderProp = CSaleOrderPropsValue::GetList(Array(), Array("ORDER_ID" => $arOrder["ID"], "PROP_IS_EMAIL" => "Y"));
2659 if($arOrderProp = $dbOrderProp->Fetch())
2660 $payerEMail = $arOrderProp["VALUE"];
2661
2662 $payerName = "";
2663 $dbUser = CUser::GetByID($arOrder["USER_ID"]);
2664 if ($arUser = $dbUser->Fetch())
2665 {
2666 if ($payerName == '')
2667 $payerName = $arUser["NAME"].(($arUser["NAME"] == '' || $arUser["LAST_NAME"] == '') ? "" : " ").$arUser["LAST_NAME"];
2668 if ($payerEMail == '')
2669 $payerEMail = $arUser["EMAIL"];
2670 }
2671
2672 $publicLink = '';
2673
2674 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
2675
2677 $orderClass = $registry->getOrderClassName();
2678
2679 $order = $orderClass::load($arOrder['ID']);
2680 if (Sale\Helpers\Order::isAllowGuestView($order))
2681 {
2682 $publicLink = Sale\Helpers\Order::getPublicLink($order);
2683 }
2684
2685 $arFields = Array(
2686 "ORDER_ID" => $arOrder["ACCOUNT_NUMBER"],
2687 "ORDER_DATE" => $date_insert,
2688 "ORDER_USER" => $payerName,
2689 "PRICE" => SaleFormatCurrency($arOrder["PRICE"], $arOrder["CURRENCY"]),
2690 "BCC" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER["SERVER_NAME"]),
2691 "EMAIL" => $payerEMail,
2692 "ORDER_LIST" => $strOrderList,
2693 "SALE_EMAIL" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER['SERVER_NAME']),
2694 "ORDER_PUBLIC_URL" => $publicLink
2695 );
2696
2697 $eventName = "SALE_ORDER_REMIND_PAYMENT";
2698
2699 $bSend = true;
2700 foreach(GetModuleEvents("sale", "OnOrderRemindSendEmail", true) as $arEvent)
2701 if (ExecuteModuleEventEx($arEvent, Array($arOrder["ID"], &$eventName, &$arFields))===false)
2702 $bSend = false;
2703
2704 if($bSend)
2705 {
2706 $event = new CEvent;
2707 $event->Send($eventName, $arOrder["LID"], $arFields, "Y");
2708 }
2709 }
2710 }
2711
2712 if ($bTmpUser)
2713 {
2714 unset($GLOBALS["USER"]);
2715 }
2716
2717 }
2718 }
2719 return "CSaleOrder::RemindPayment();";
2720 }
2721
2734 public static function GetNextAccountNumber($orderID, $templateType, $param)
2735 {
2736 global $DB;
2737 $value = false;
2738
2739 switch ($templateType)
2740 {
2741 case 'NUMBER':
2742
2743 $param = intval($param);
2744 $maxLastID = 0;
2745
2746 $strSql = "SELECT ID, ACCOUNT_NUMBER FROM b_sale_order WHERE ACCOUNT_NUMBER IS NOT NULL ORDER BY ID DESC LIMIT 1";
2747
2748 $dbres = $DB->Query($strSql, true);
2749 if ($arRes = $dbres->GetNext())
2750 {
2751 if (mb_strlen($arRes["ACCOUNT_NUMBER"]) === mb_strlen(intval($arRes["ACCOUNT_NUMBER"])))
2752 $maxLastID = intval($arRes["ACCOUNT_NUMBER"]);
2753 }
2754
2755 $value = ($maxLastID >= $param) ? $maxLastID + 1 : $param;
2756 break;
2757
2758 case 'PREFIX':
2759
2760 $value = $param.$orderID;
2761 break;
2762
2763 case 'RANDOM':
2764
2765 $rand = randString(intval($param), array("ABCDEFGHIJKLNMOPQRSTUVWXYZ", "0123456789"));
2766 $dbres = $DB->Query("SELECT ID, ACCOUNT_NUMBER FROM b_sale_order WHERE ACCOUNT_NUMBER = '".$rand."'", true);
2767 $value = ($arRes = $dbres->GetNext()) ? false : $rand;
2768 break;
2769
2770 case 'USER':
2771
2772 $dbres = $DB->Query("SELECT USER_ID FROM b_sale_order WHERE ID = '".$orderID."'", true);
2773
2774 if ($arRes = $dbres->GetNext())
2775 {
2776 $userID = $arRes["USER_ID"];
2777
2778 $strSql = "SELECT MAX(CAST(SUBSTRING(ACCOUNT_NUMBER, LENGTH('".$userID."_') + 1) as UNSIGNED)) as NUM_ID FROM b_sale_order WHERE ACCOUNT_NUMBER LIKE '".$userID."\_%'";
2779 $dbres = $DB->Query($strSql, true);
2780 if ($arRes = $dbres->GetNext())
2781 {
2782 $numID = (intval($arRes["NUM_ID"]) > 0) ? $arRes["NUM_ID"] + 1 : 1;
2783 $value = $userID."_".$numID;
2784 }
2785 else
2786 $value = $userID."_1";
2787 }
2788 else
2789 $value = false;
2790
2791 break;
2792
2793 case 'DATE':
2794
2795 switch ($param)
2796 {
2797 // date in the site format but without delimeters
2798 case 'day':
2799 $date = date($DB->DateFormatToPHP(CSite::GetDateFormat("SHORT")), mktime(0, 0, 0, date("m"), date("d"), date("Y")));
2800 $date = preg_replace("/[^0-9]/", "", $date);
2801 break;
2802 case 'month':
2803 $date = date($DB->DateFormatToPHP(str_replace("DD", "", CSite::GetDateFormat("SHORT"))), mktime(0, 0, 0, date("m"), date("d"), date("Y")));
2804 $date = preg_replace("/[^0-9]/", "", $date);
2805 break;
2806 case 'year':
2807 $date = date('Y');
2808 break;
2809 }
2810
2811 $strSql = "SELECT MAX(CAST(SUBSTRING(ACCOUNT_NUMBER, LENGTH('".$date." / ') + 1) as UNSIGNED)) as NUM_ID FROM b_sale_order WHERE ACCOUNT_NUMBER LIKE '".$date." / %'";
2812 $dbres = $DB->Query($strSql, true);
2813 if ($arRes = $dbres->GetNext())
2814 {
2815 $numID = (intval($arRes["NUM_ID"]) > 0) ? $arRes["NUM_ID"] + 1 : 1;
2816 $value = $date." / ".$numID;
2817 }
2818 else
2819 $value = $date." / 1";
2820
2821 break;
2822 }
2823
2824 return $value;
2825 }
2826
2827 public static function __SaleOrderCount($arFilter, $strCurrency = '')
2828 {
2829 $mxResult = false;
2830 if (is_array($arFilter) && !empty($arFilter))
2831 {
2832 $dblPrice = 0;
2833 $strCurrency = strval($strCurrency);
2834 $mxLastOrderDate = '';
2835 $intMaxTimestamp = 0;
2836 $rsSaleOrders = CSaleOrder::GetList(
2837 array(),
2838 $arFilter,
2839 false,
2840 false,
2841 array('ID','PRICE','CURRENCY','DATE_INSERT')
2842 );
2843 while ($arSaleOrder = $rsSaleOrders->Fetch())
2844 {
2845 $intTimeStamp = MakeTimeStamp($arSaleOrder['DATE_INSERT']);
2846 if ($intMaxTimestamp < $intTimeStamp)
2847 {
2848 $intMaxTimestamp = $intTimeStamp;
2849 $mxLastOrderDate = $arSaleOrder['DATE_INSERT'];
2850 }
2851 if (empty($strCurrency))
2852 {
2853 $dblPrice += $arSaleOrder['PRICE'];
2854 $strCurrency = $arSaleOrder['CURRENCY'];
2855 }
2856 else
2857 {
2858 $dblPrice += (
2859 $strCurrency != $arSaleOrder['CURRENCY']
2860 ? CCurrencyRates::ConvertCurrency($arSaleOrder['PRICE'], $arSaleOrder['CURRENCY'], $strCurrency)
2861 : $arSaleOrder['PRICE']
2862 );
2863 }
2864 unset($intTimeStamp);
2865 }
2866 unset($arSaleOrder, $rsSaleOrders);
2867
2868 $archiveData = Sale\Archive\Manager::getList(
2869 array(
2870 'filter' => $arFilter,
2871 'select' => array('DATE_INSERT', 'PRICE', 'CURRENCY')
2872 )
2873 );
2874
2875 while($archiveOrder = $archiveData->fetch())
2876 {
2877 $intTimeStamp = MakeTimeStamp($archiveOrder['DATE_INSERT']);
2878 if ($intMaxTimestamp < $intTimeStamp)
2879 {
2880 $intMaxTimestamp = $intTimeStamp;
2881 $mxLastOrderDate = $archiveOrder['DATE_INSERT'];
2882 }
2883 if (empty($strCurrency))
2884 {
2885 $dblPrice += $archiveOrder['PRICE'];
2886 $strCurrency = $archiveOrder['CURRENCY'];
2887 }
2888
2889 $dblPrice += (
2890 $strCurrency != $archiveOrder['CURRENCY']
2891 ? CCurrencyRates::ConvertCurrency($archiveOrder['PRICE'], $archiveOrder['CURRENCY'], $strCurrency)
2892 : $archiveOrder['PRICE']
2893 );
2894 }
2895
2896 $mxResult = array(
2897 'PRICE' => $dblPrice,
2898 'CURRENCY' => $strCurrency,
2899 'LAST_ORDER_DATE' => $mxLastOrderDate,
2900 'TIMESTAMP' => $intMaxTimestamp,
2901 );
2902 }
2903 return $mxResult;
2904 }
2905
2917 public static function GetHistoryList($arOrder = array("ID"=>"DESC"), $arFilter = array(), $arGroupBy = false, $arNavStartParams = false, $arSelectFields = array())
2918 {
2919 global $DB;
2920
2921 if (array_key_exists("H_DATE_INSERT_FROM", $arFilter))
2922 {
2923 $val = $arFilter["H_DATE_INSERT_FROM"];
2924 unset($arFilter["H_DATE_INSERT_FROM"]);
2925 $arFilter[">=H_DATE_INSERT"] = $val;
2926 }
2927 if (array_key_exists("H_DATE_INSERT_TO", $arFilter))
2928 {
2929 $val = $arFilter["H_DATE_INSERT_TO"];
2930 unset($arFilter["H_DATE_INSERT_TO"]);
2931 $arFilter["<=H_DATE_INSERT"] = $val;
2932 }
2933
2934 if (!$arSelectFields || count($arSelectFields) <= 0 || in_array("*", $arSelectFields))
2935 {
2936 $arSelectFields = array(
2937 "ID",
2938 "H_USER_ID",
2939 "H_DATE_INSERT",
2940 "H_ORDER_ID",
2941 "H_CURRENCY",
2942 "PERSON_TYPE_ID",
2943 "PAYED",
2944 "DATE_PAYED",
2945 "EMP_PAYED_ID",
2946 "CANCELED",
2947 "DATE_CANCELED",
2948 "REASON_CANCELED",
2949 "MARKED",
2950 "DATE_MARKED",
2951 "REASON_MARKED",
2952 "DEDUCTED",
2953 "DATE_DEDUCTED",
2954 "REASON_UNDO_DEDUCTED",
2955 "RESERVED",
2956 "STATUS_ID",
2957 "DATE_STATUS",
2958 "PRICE_DELIVERY",
2959 "ALLOW_DELIVERY",
2960 "DATE_ALLOW_DELIVERY",
2961 "PRICE",
2962 "CURRENCY",
2963 "DISCOUNT_VALUE",
2964 "USER_ID",
2965 "PAY_SYSTEM_ID",
2966 "DELIVERY_ID",
2967 "PS_STATUS",
2968 "PS_STATUS_CODE",
2969 "PS_STATUS_DESCRIPTION",
2970 "PS_STATUS_MESSAGE",
2971 "PS_SUM",
2972 "PS_CURRENCY",
2973 "PS_RESPONSE_DATE",
2974 "TAX_VALUE",
2975 "STAT_GID",
2976 "SUM_PAID",
2977 "PAY_VOUCHER_NUM",
2978 "PAY_VOUCHER_DATE",
2979 "AFFILIATE_ID",
2980 "DELIVERY_DOC_NUM",
2981 "DELIVERY_DOC_DATE"
2982 );
2983 }
2984
2985 $arFields = array(
2986 "ID" => array("FIELD" => "V.ID", "TYPE" => "int"),
2987 "H_ORDER_ID" => array("FIELD" => "V.H_ORDER_ID", "TYPE" => "int"),
2988 "H_USER_ID" => array("FIELD" => "V.H_USER_ID", "TYPE" => "int"),
2989 "H_DATE_INSERT" => array("FIELD" => "V.H_DATE_INSERT", "TYPE" => "datetime"),
2990 "H_CURRENCY" => array("FIELD" => "V.H_CURRENCY", "TYPE" => "string"),
2991 "PERSON_TYPE_ID" => array("FIELD" => "V.PERSON_TYPE_ID", "TYPE" => "int"),
2992 "PAYED" => array("FIELD" => "V.PAYED", "TYPE" => "char"),
2993 "DATE_PAYED" => array("FIELD" => "V.DATE_PAYED", "TYPE" => "datetime"),
2994 "EMP_PAYED_ID" => array("FIELD" => "V.EMP_PAYED_ID", "TYPE" => "int"),
2995 "CANCELED" => array("FIELD" => "V.CANCELED", "TYPE" => "char"),
2996 "DATE_CANCELED" => array("FIELD" => "V.DATE_CANCELED", "TYPE" => "datetime"),
2997 "REASON_CANCELED" => array("FIELD" => "V.REASON_CANCELED", "TYPE" => "string"),
2998 "MARKED" => array("FIELD" => "V.MARKED", "TYPE" => "char"),
2999 "DATE_MARKED" => array("FIELD" => "V.DATE_MARKED", "TYPE" => "datetime"),
3000 "REASON_MARKED" => array("FIELD" => "V.REASON_MARKED", "TYPE" => "string"),
3001 "DEDUCTED" => array("FIELD" => "V.DEDUCTED", "TYPE" => "char"),
3002 "DATE_DEDUCTED" => array("FIELD" => "V.DATE_DEDUCTED", "TYPE" => "datetime"),
3003 "REASON_DEDUCTED" => array("FIELD" => "V.REASON_UNDO_DEDUCTED", "TYPE" => "string"),
3004 "RESERVED" => array("FIELD" => "V.RESERVED", "TYPE" => "char"),
3005 "STATUS_ID" => array("FIELD" => "V.STATUS_ID", "TYPE" => "char"),
3006 "DATE_STATUS" => array("FIELD" => "V.DATE_STATUS", "TYPE" => "datetime"),
3007 "PAY_VOUCHER_NUM" => array("FIELD" => "V.PAY_VOUCHER_NUM", "TYPE" => "string"),
3008 "PAY_VOUCHER_DATE" => array("FIELD" => "V.PAY_VOUCHER_DATE", "TYPE" => "date"),
3009 "PRICE_DELIVERY" => array("FIELD" => "V.PRICE_DELIVERY", "TYPE" => "double"),
3010 "ALLOW_DELIVERY" => array("FIELD" => "V.ALLOW_DELIVERY", "TYPE" => "char"),
3011 "DATE_ALLOW_DELIVERY" => array("FIELD" => "V.DATE_ALLOW_DELIVERY", "TYPE" => "datetime"),
3012 "PRICE" => array("FIELD" => "V.PRICE", "TYPE" => "double"),
3013 "CURRENCY" => array("FIELD" => "V.CURRENCY", "TYPE" => "string"),
3014 "DISCOUNT_VALUE" => array("FIELD" => "V.DISCOUNT_VALUE", "TYPE" => "double"),
3015 "SUM_PAID" => array("FIELD" => "V.SUM_PAID", "TYPE" => "double"),
3016 "USER_ID" => array("FIELD" => "V.USER_ID", "TYPE" => "int"),
3017 "PAY_SYSTEM_ID" => array("FIELD" => "V.PAY_SYSTEM_ID", "TYPE" => "int"),
3018 "DELIVERY_ID" => array("FIELD" => "V.DELIVERY_ID", "TYPE" => "string"),
3019 "PS_STATUS" => array("FIELD" => "V.PS_STATUS", "TYPE" => "char"),
3020 "PS_STATUS_CODE" => array("FIELD" => "V.PS_STATUS_CODE", "TYPE" => "string"),
3021 "PS_STATUS_DESCRIPTION" => array("FIELD" => "V.PS_STATUS_DESCRIPTION", "TYPE" => "string"),
3022 "PS_STATUS_MESSAGE" => array("FIELD" => "V.PS_STATUS_MESSAGE", "TYPE" => "string"),
3023 "PS_SUM" => array("FIELD" => "V.PS_SUM", "TYPE" => "double"),
3024 "PS_CURRENCY" => array("FIELD" => "V.PS_CURRENCY", "TYPE" => "string"),
3025 "PS_RESPONSE_DATE" => array("FIELD" => "V.PS_RESPONSE_DATE", "TYPE" => "datetime"),
3026 "TAX_VALUE" => array("FIELD" => "V.TAX_VALUE", "TYPE" => "double"),
3027 "AFFILIATE_ID" => array("FIELD" => "V.AFFILIATE_ID", "TYPE" => "int"),
3028 "DELIVERY_DOC_NUM" => array("FIELD" => "V.DELIVERY_DOC_NUM", "TYPE" => "string"),
3029 "DELIVERY_DOC_DATE" => array("FIELD" => "V.DELIVERY_DOC_DATE", "TYPE" => "date"),
3030 );
3031
3032 $arSqls = CSaleOrder::PrepareSql($arFields, $arOrder, $arFilter, $arGroupBy, $arSelectFields);
3033
3034 $arSqls["SELECT"] = str_replace("%%_DISTINCT_%%", "", $arSqls["SELECT"]);
3035 $strSql = "SELECT ".$arSqls["SELECT"]." FROM b_sale_order_history V ";
3036
3037 if ($arSqls["WHERE"] <> '')
3038 $strSql .= "WHERE ".$arSqls["WHERE"]." ";
3039 if ($arSqls["GROUPBY"] <> '')
3040 $strSql .= "GROUP BY ".$arSqls["GROUPBY"]." ";
3041 if ($arSqls["ORDERBY"] <> '')
3042 $strSql .= "ORDER BY ".$arSqls["ORDERBY"]." ";
3043
3044 if (is_array($arGroupBy) && count($arGroupBy) == 0)
3045 {
3046 $dbRes = $DB->Query($strSql);
3047 if ($arRes = $dbRes->Fetch())
3048 return $arRes["CNT"];
3049 else
3050 return false;
3051 }
3052
3053 if (is_array($arNavStartParams) && intval($arNavStartParams["nTopCount"]) <= 0 )
3054 {
3055 $strSql_tmp = "SELECT COUNT('x') as CNT FROM b_sale_order_history V ";
3056 if ($arSqls["WHERE"] <> '')
3057 $strSql_tmp .= "WHERE ".$arSqls["WHERE"]." ";
3058 if ($arSqls["GROUPBY"] <> '')
3059 $strSql_tmp .= "GROUP BY ".$arSqls["GROUPBY"]." ";
3060
3061 $dbRes = $DB->Query($strSql_tmp);
3062 $cnt = 0;
3063 if ($arSqls["GROUPBY"] == '')
3064 {
3065 if ($arRes = $dbRes->Fetch())
3066 $cnt = $arRes["CNT"];
3067 }
3068 else
3069 {
3070 $cnt = $dbRes->SelectedRowsCount();
3071 }
3072 $dbRes = new CDBResult();
3073
3074 $dbRes->NavQuery($strSql, $cnt, $arNavStartParams);
3075 }
3076 else
3077 {
3078 if (isset($arNavStartParams["nTopCount"]))
3079 {
3080 $strSql = $DB->TopSql($strSql, $arNavStartParams["nTopCount"]);
3081 }
3082
3083 $dbRes = $DB->Query($strSql);
3084 }
3085
3086 return $dbRes;
3087 }
3088
3089 public static function SetMark($ID, $comment = "", $userID = 0)
3090 {
3091 global $DB;
3092
3093 $ID = intval($ID);
3094 if ($ID < 0)
3095 return false;
3096
3097 $userID = intval($userID);
3098
3099 $arFields = array(
3100 "MARKED" => "Y",
3101 "REASON_MARKED" => $comment,
3102 "EMP_MARKED_ID" => $userID,
3103 "=DATE_MARKED" => $DB->GetNowFunction()
3104 );
3105
3106 CSaleMobileOrderPush::send("ORDER_MARKED", array("ORDER_ID" => $ID));
3107
3109 }
3110
3111 public static function UnsetMark($ID, $userID = 0)
3112 {
3113 global $DB;
3114
3115 $ID = intval($ID);
3116 if ($ID < 0)
3117 return false;
3118
3119 $userID = intval($userID);
3120
3121 $arFields = array(
3122 "MARKED" => "N",
3123 "REASON_MARKED" => "",
3124 "EMP_MARKED_ID" => $userID,
3125 "=DATE_MARKED" => $DB->GetNowFunction()
3126 );
3127
3129 }
3130
3139 public static function SetAccountNumber($ID)
3140 {
3142 $r = static::setAccountNumberById($ID);
3143 return $r->isSuccess();
3144 }
3145
3153 public static function setAccountNumberById($id)
3154 {
3155 $result = new Sale\Result();
3156
3157 $id = intval($id);
3158 if ($id <= 0)
3159 {
3160 $result->addError(
3161 new Sale\ResultError(
3162 Loc::getMessage('SALE_ORDER_GENERATE_ACCOUNT_NUMBER_ORDER_NUMBER_WRONG_ID'),
3163 'SALE_ORDER_GENERATE_ACCOUNT_NUMBER_ORDER_NUMBER_WRONG_ID'
3164 )
3165 );
3166
3167 return $result;
3168 }
3169 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3170
3172 $orderClass = $registry->getOrderClassName();
3173
3174 $order = $orderClass::load($id);
3175 if (!$order)
3176 {
3177 $result->addError(
3178 new \Bitrix\Main\Error(
3179 Bitrix\Main\Localization\Loc::getMessage('ERROR')
3180 )
3181 );
3182
3183 return $result;
3184 }
3185
3186 $accountNumber = Internals\AccountNumberGenerator::generateForOrder($order);
3187
3188 $r = Internals\OrderTable::update($id, ['ACCOUNT_NUMBER' => $accountNumber]);
3189 if (!$r->isSuccess())
3190 {
3191 $result->addErrors($r->getErrors());
3192 }
3193
3194 return $result;
3195 }
3196
3203 public static function ClearProductReservedQuantity()
3204 {
3205 \Bitrix\Sale\Helpers\ReservedProductCleaner::bind(60);
3206 return "CSaleOrder::ClearProductReservedQuantity();";
3207 }
3208
3221 protected static function ProcessCompleteOrdersParam($values, $key, $op, $opNegative, $field, $fields, $filter)
3222 {
3223 if($op != '=' && $op != 'IN')
3224 return false;
3225
3226 global $DB;
3227
3228 if(is_array($values) && !empty($values))
3229 {
3230 foreach($values as $k => $value)
3231 $values[$k] = "'".$DB->ForSql($value)."'";
3232
3233 $values = '('.implode(',', $values).')';
3234 }
3235 elseif(!empty($values))
3236 $values = "'".$DB->ForSql($values)."'";
3237 else
3238 return false;
3239
3240 if($opNegative == 'Y')
3241 return "( (NOT (".$fields["STATUS_ID"]["FIELD"]." ".$op." ".$values.")) AND (".$fields["CANCELED"]["FIELD"]." = 'N'))";
3242 else
3243 return "((".$fields["STATUS_ID"]["FIELD"]." ".$op." ".$values.") OR (".$fields["CANCELED"]["FIELD"]." = 'Y'))";
3244 }
3245
3246 // returns reference of all properties of TYPE = LOCATION
3247 public static function getLocationPropertyInfo()
3248 {
3249 static $info;
3250
3251 if($info === null)
3252 {
3253 $info = array();
3255 {
3256 $res = CSaleOrderProps::GetList(array(), array('TYPE' => 'LOCATION'), false, false, array('ID', 'CODE'));
3257 while($item = $res->fetch())
3258 {
3259 $info['ID'][$item['ID']] = $item['CODE'];
3260 $info['CODE'][$item['CODE']] = $item['ID'];
3261 }
3262 }
3263 }
3264
3265 return $info;
3266 }
3267
3272 public static function getRoundFields()
3273 {
3274 return array(
3275 'ORDER_PRICE',
3276 'DISCOUNT_PRICE',
3277 'VAT_RATE',
3278 'VAT_SUM',
3279 );
3280 }
3281
3292 public static function checkUserPermissionOrderList(array $list, $perm, $userGroups = false, $userId = false)
3293 {
3294 $output = array();
3295
3296 $userRights = CMain::GetUserRight("sale", $userGroups, "Y", "Y");
3297 foreach ($list as $orderId)
3298 {
3299 $output[$orderId] = ($userRights >= "W") ? true: false;
3300 }
3301
3302 if ($userRights >= "W")
3303 return $output;
3304
3305 $orderList = array();
3306 $siteList = array();
3307 $statusList = array();
3308 $accessSiteList = array();
3309 $statusPermissionList = array();
3310 $statusIndexList = array();
3311
3312 $cacheAccessSite = array();
3313 $cacheStatusGroupOperation = array();
3314
3315 $selectOrder = array('ID', 'LID', 'STATUS_ID');
3316
3317 if ($userId > 0)
3318 {
3319 $selectOrder[] = 'USER_ID';
3320 }
3321
3322 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3323
3325 $orderClass = $registry->getOrderClassName();
3326
3327 $res = $orderClass::getList([
3328 'filter' => [
3329 '=ID' => $list,
3330 ],
3331 'select' => $selectOrder,
3332 ]);
3333 while($orderData = $res->fetch())
3334 {
3335 if (!in_array($orderData['LID'], array_keys($siteList)))
3336 {
3337 $siteList[$orderData['LID']][] = $orderData['ID'];
3338 }
3339
3340 if ($userId > 0 && $orderData['USER_ID'] == $userId)
3341 {
3342 $output[$orderData['ID']] = true;
3343 continue;
3344 }
3345
3346 $orderList[$orderData['ID']] = $orderData;
3347 }
3348
3349 if ($userRights == "U" && !empty($orderList))
3350 {
3351 $hashAccessSite = md5(join(',', array_keys($siteList))."|". join(', ', $userGroups));
3352
3353 if (array_key_exists($hashAccessSite, $cacheAccessSite))
3354 {
3355 $accessSiteList = $cacheAccessSite[$hashAccessSite];
3356 }
3357 else
3358 {
3359 $accessSiteRes = CSaleGroupAccessToSite::GetList(
3360 array(),
3361 array(
3362 "@SITE_ID" => array_keys($siteList),
3363 "GROUP_ID" => $userGroups
3364 ),
3365 false,
3366 false,
3367 array('SITE_ID')
3368 );
3369 while($accessSiteData = $accessSiteRes->Fetch())
3370 {
3371 $accessSiteList[] = $accessSiteData['SITE_ID'];
3372 }
3373
3374 $cacheAccessSite[$hashAccessSite] = $accessSiteList;
3375 }
3376
3377 foreach ($siteList as $siteId => $orderIdList)
3378 {
3379 if (!in_array($siteId, $accessSiteList))
3380 {
3381 foreach ($siteList[$siteId] as $orderId)
3382 {
3383 if (!empty($orderList[$orderId]))
3384 {
3385 unset($orderList[$orderId]);
3386 }
3387 }
3388 unset($siteList[$siteId]);
3389 }
3390 }
3391
3392 if (!empty($orderList))
3393 {
3394 foreach ($orderList as $orderId => $orderData)
3395 {
3396 if (!in_array($orderData['STATUS_ID'], $statusList))
3397 {
3398 $statusList[$orderData['STATUS_ID']] = $orderData['STATUS_ID'];
3399 }
3400
3401 $statusIndexList[$orderData['STATUS_ID']][] = $orderData['ID'];
3402 }
3403
3404 $statusIdList = array_keys($statusList);
3405
3406 if (!empty($statusIdList))
3407 {
3408 foreach ($statusIdList as $statusId)
3409 {
3410 $hashStatusGroupOperation = md5($statusId . "|" . join(',', $userGroups)."|". $perm);
3411 if (array_key_exists($hashStatusGroupOperation, $cacheStatusGroupOperation))
3412 {
3413 $statusPermissionList[$statusId] = $cacheStatusGroupOperation[$hashAccessSite];
3414 }
3415 else
3416 {
3417 if (Sale\OrderStatus::canGroupDoOperations($userGroups, $statusId, array($perm)))
3418 {
3419 $statusPermissionList[$statusId] = true;
3420 $cacheStatusGroupOperation[$hashStatusGroupOperation] = true;
3421 }
3422 }
3423 }
3424 }
3425
3426 foreach ($statusIndexList as $statusId => $orderIdList)
3427 {
3428 if (!array_key_exists($statusId, $statusPermissionList))
3429 {
3430 foreach ($orderIdList as $orderId)
3431 {
3432 if (!empty($orderList[$orderId]))
3433 {
3434 unset($orderList[$orderId]);
3435 }
3436 }
3437 unset($statusList[$statusId]);
3438 }
3439 }
3440 }
3441 }
3442
3443 if (!empty($orderList))
3444 {
3445 $orderIdList = array_keys($orderList);
3446
3447 foreach ($list as $orderId)
3448 {
3449 if (in_array($orderId, $orderIdList))
3450 {
3451 if (isset($output[$orderId]))
3452 {
3453 $output[$orderId] = true;
3454 }
3455 }
3456 }
3457 }
3458
3459 return $output;
3460 }
3461}
$connection
Определения actionsdefinitions.php:38
$arSites
Определения options.php:15
$db_res
Определения options_user_settings.php:8
global $APPLICATION
Определения include.php:80
$arRecurring
Определения options.php:1889
$arResult
Определения generate_coupon.php:16
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static get($moduleId, $name, $default="", $siteId=false)
Определения option.php:30
static getMessage($code, $replace=null, $language=null)
Определения loc.php:30
static getList(array $parameters=array())
Определения manager.php:205
static roundPrecision($value)
Определения pricemaths.php:16
static GetByID($currency)
Определения currency.php:453
static ConvertCurrency($valSum, $curFrom, $curTo, $valDate="")
Определения currency_rate.php:393
static GetOptionString($module_id, $name, $def="", $site=false, $bExactSite=false)
Определения option.php:8
static OrderCanceled($orderID, $bCancel)
Определения basket.php:2293
static DoProcessOrder(&$arOrder, $deliveryCode, &$arErrors)
Определения delivery.php:52
static DoProcessOrder(&$arOrder, $arOptions, &$arErrors)
Определения discount.php:40
static isLocationProMigrated()
Определения location.php:58
static getLocationIDbyCODE($code)
Определения location.php:238
static getLocationCODEbyID($id)
Определения location.php:260
Определения order.php:15
static DoCalculateOrder($siteId, $userId, $arShoppingCart, $personTypeId, $arOrderPropsValues, $deliveryId, $paySystemId, $arOptions, &$arErrors, &$arWarnings)
Определения order.php:29
static GetFilterOperation($key)
Определения order.php:1011
static CancelOrder($ID, $val, $description="")
Определения order.php:2303
static StatusOrder($ID, $val)
Определения order.php:2449
static CanUserViewOrder($ID, $arUserGroups=false, $userID=0)
Определения order.php:468
static Lock($ID)
Определения order.php:2504
static __SaleOrderCount($arFilter, $strCurrency='')
Определения order.php:2827
static GetNextAccountNumber($orderID, $templateType, $param)
Определения order.php:2734
static DeductOrder($ID, $val, $description="", $bAutoDeduction=true, $arStoreBarcodeOrderFormData=array(), $recurringID=0)
Определения order.php:2101
static CanUserUpdateOrder($ID, $arUserGroups=false, $siteID=false)
Определения order.php:483
static OnBeforeCurrencyDelete($currency)
Определения order.php:1662
static PrepareSql(&$arFields, $arOrder, &$arFilter, $arGroupBy, $arSelectFields, $obUserFieldsSql=false, $callback=false, $arOptions=array())
Определения order.php:1070
static CanUserDeleteOrder($ID, $arUserGroups=false, $userID=0)
Определения order.php:687
static ClearProductReservedQuantity()
Определения order.php:3203
static ProcessCompleteOrdersParam($values, $key, $op, $opNegative, $field, $fields, $filter)
Определения order.php:3221
static getRoundFields()
Определения order.php:3272
static CheckFields($ACTION, &$arFields, $ID=0)
Определения order.php:697
static _Delete($ID)
Определения order.php:866
static SetMark($ID, $comment="", $userID=0)
Определения order.php:3089
static CanUserChangeOrderFlag($ID, $flag, $arUserGroups=false)
Определения order.php:568
static UnLock($ID)
Определения order.php:2520
static CanUserChangeOrderStatus($ID, $statusID, $arUserGroups=false)
Определения order.php:624
static CalculateOrderPrices($arBasketItems)
Определения order.php:239
static IsLocked($ID, &$lockedBY, &$dateLock)
Определения order.php:2545
static makeOrderArray($siteId, $userId=null, array $shoppingCart=[], array $options=[])
Определения order.php:177
static UnsetMark($ID, $userID=0)
Определения order.php:3111
static TranslateLocationPropertyValues($personTypeId, &$orderProps, $direct=true)
Определения order.php:313
static GetLockStatus($ID, &$lockedBY, &$dateLock)
Определения order.php:2552
static GetHistoryList($arOrder=array("ID"=>"DESC"), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения order.php:2917
static OnBeforeUserDelete($userID)
Определения order.php:1692
static CanUserCancelOrder($ID, $arUserGroups=false, $userID=0)
Определения order.php:538
static CommentsOrder($ID, $val)
Определения order.php:2489
static CanUserMarkOrder($ID, $arUserGroups=false, $userID=0)
Определения order.php:553
static getLocationPropertyInfo()
Определения order.php:3247
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения order_props_values.php:12
static DeleteByOrder($orderID)
Определения order_props_values.php:369
static DeleteEx($ORDER_ID)
Определения order_tax.php:96
static DoProcessOrder(&$arOrder, $paySystemId, &$arErrors)
Определения pay_system.php:10
static GetByID($id, $personTypeId=0)
Определения pay_system.php:82
static GetByID($ID)
Определения person_type.php:69
static Delete($ID)
Определения recurring.php:97
static DoProcessOrderDelivery(&$arOrder, $arOptions, &$arErrors)
Определения tax.php:163
static DoProcessOrderBasket(&$arOrder, $arOptions, &$arErrors)
Определения tax.php:7
static Pay($userID, $paySum, $payCurrency, $orderID=0, $useCC=true, $paymentId=null)
Определения user.php:305
static UpdateAccount($userID, $sum, $currency, $description="", $orderID=0, $notes="", $paymentId=null)
Определения user.php:589
static DeleteByOrder($OrderID)
Определения user_transact.php:65
static AddByEvents($EVENT1, $EVENT2, $EVENT3, $DATE_ENTER, $PARAM, $MONEY="", $CURRENCY="", $CHARGEBACK="N")
Определения statevent.php:334
static GetByID($ID)
Определения user.php:3820
static getVat(array $basketItemData)
Определения basket_helper.php:199
static isSetParent($arItem)
Определения basket_helper.php:49
static isSetItem($arItem)
Определения basket_helper.php:26
static getFinalPrice(array $basketItemData)
Определения basket_helper.php:251
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения basket.php:33
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения settings.php:7
static GetLangCurrency($siteId)
Определения settings.php:52
static send($eventId, $arParams)
Определения mobile_order.php:1088
static Add($arFields)
Определения order.php:10
static Update($ID, $arFields, $bDateUpdate=true)
Определения order.php:140
static GetList($arOrder=array("ID"=>"DESC"), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array(), $arOptions=array())
Определения order.php:339
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения order_props.php:410
static DoSaveOrderProps($orderId, $personTypeId, $arOrderProps, &$arErrors, $paysystemId=0, $deliveryId="")
Определения order_props.php:296
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения recurring.php:47
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения status.php:72
static GetPermissionsList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения status.php:127
static GetByID($statusId, $languageId=LANGUAGE_ID, $type=null)
Определения status.php:23
static Disable()
Определения time.php:31
static Enable()
Определения time.php:36
Определения user.php:6037
$options
Определения commerceml2.php:49
$arFields
Определения dblapprove.php:5
$orderId
Определения payment.php:5
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
GetFilterQuery($field, $val, $procent="Y", $ex_sep=array(), $clob="N", $div_fields="Y", $clob_upper="N")
Определения filter_tools.php:383
$perm
Определения options.php:169
global $USER_FIELD_MANAGER
Определения attempt.php:6
$result
Определения get_property_values.php:14
if($ajaxMode) $ID
Определения get_user.php:27
if(Loader::includeModule( 'bitrix24')) elseif(Loader::includeModule('intranet') &&CIntranetUtils::getPortalZone() !=='ru') $description
Определения .description.php:24
$filter
Определения iblock_catalog_list.php:54
while($arParentIBlockProperty=$dbParentIBlockProperty->Fetch()) $errorMessage
$output
Определения options.php:436
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
global $DB
Определения cron_frame.php:29
$siteID
Определения cron_frame.php:12
global $USER
Определения csv_new_run.php:40
$ACTION
Определения csv_new_setup.php:27
const FORMAT_DATETIME
Определения include.php:64
const FORMAT_DATE
Определения include.php:63
$arOptions
Определения structure.php:223
$siteId
Определения ajax.php:8
if($NS['step']==6) if( $NS[ 'step']==7) if(COption::GetOptionInt('main', 'disk_space', 0) > 0) $info
Определения backup.php:924
ConvertDateTime($datetime, $to_format=false, $from_site=false, $bSearchInSitesOnly=false)
Определения tools.php:724
roundEx($value, $prec=0)
Определения tools.php:4635
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
DelDuplicateSort(&$arSort)
Определения tools.php:2055
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
ConvertTimeStamp($timestamp=false, $type="SHORT", $site=false, $bSearchInSitesOnly=false)
Определения tools.php:733
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
is_set($a, $k=false)
Определения tools.php:2133
AddToTimeStamp($arrAdd, $stmp=false)
Определения tools.php:687
randString($pass_len=10, $pass_chars=false)
Определения tools.php:2154
MakeTimeStamp($datetime, $format=false)
Определения tools.php:538
Определения collection.php:2
$GLOBALS['____1690880296']
Определения license.php:1
trait Error
Определения error.php:11
$order
Определения payment.php:8
$event
Определения prolog_after.php:141
$direct
Определения prolog_auth_admin.php:26
return false
Определения prolog_main_admin.php:185
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
if(CSalePaySystemAction::GetParamValue("DATE_PAY_BEFORE", false)) $dbBasket
Определения html.php:162
$comment
Определения template.php:15
$currency
Определения template.php:266
SaleFormatCurrency($fSum, $strCurrency, $OnlyValue=false, $withoutFormat=false)
Определения include.php:142
const SALE_VALUE_PRECISION
Определения include.php:46
$arStatuses
Определения options.php:1642
if(CBXFeatures::IsFeatureEnabled('SaleAccounts')) $arReminder
Определения options.php:2414
$siteList
Определения options.php:47
$val
Определения options.php:1793
if( $guestStatuses !=='') if(!is_array($guestStatuses)) $statusList
Определения options.php:2065
$reminder
Определения options.php:2415
$orderID
Определения result.php:9
if(CSalePaySystemAction::GetParamValue("ORDER_SUBJECT", false)) if(CSalePaySystemAction::GetParamValue("DATE_PAY_BEFORE", false)) if(CSalePaySystemAction::GetParamValue("BUYER_NAME", false)) $arBasketItems
Определения html.php:241
$arRes
Определения options.php:104
$error
Определения subscription_card_product.php:20
$k
Определения template_pdf.php:567
$GLOBALS['_____370096793']
Определения update_client.php:1
$arFilter
Определения user_search.php:106
$dbRes
Определения yandex_detail.php:168
$fields
Определения yandex_run.php:501