1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
basket.php
См. документацию.
1<?php
2
10
12{
13 public const TYPE_SET = 1;
14
15 protected static array $currencySiteList = [];
16 protected static array $currencyList = [];
17
24 public static function GetProductProvider($arBasketItem)
25 {
26 if (!is_array($arBasketItem)
27 || empty($arBasketItem)
28 || !isset($arBasketItem["MODULE"])
29 || !isset($arBasketItem["PRODUCT_PROVIDER_CLASS"])
30 || ($arBasketItem["PRODUCT_PROVIDER_CLASS"] == '')
31 )
32 return false;
33
34 $productProviderClass = $arBasketItem["PRODUCT_PROVIDER_CLASS"];
35
36 if (CModule::IncludeModule($arBasketItem["MODULE"])
37 && class_exists($productProviderClass)
38 && ((array_key_exists("IBXSaleProductProvider", class_implements($productProviderClass))))
39 )
40 {
41 return $productProviderClass;
42 }
43
44 $providerClass = Sale\Internals\Catalog\Provider::getProviderEntity($arBasketItem["PRODUCT_PROVIDER_CLASS"]);
45 if ($providerClass instanceof Sale\SaleProviderBase)
46 {
47 return '\Bitrix\Catalog\Product\CatalogProviderCompatibility';
48 }
49
50 return false;
51 }
52
59 public static function ClearProductSubscribe($LID)
60 {
62
63 return "CSaleBasket::ClearProductSubscribe('".$LID."');";
64 }
65
73 public static function ProductSubscribe($ID, $MODULE)
74 {
75 $ID = (int)$ID;
76 $MODULE = trim($MODULE);
77
78 if ($ID <= 0 || $MODULE == '')
79 return false;
80
82 $subscribeProd = COption::GetOptionString("sale", "subscribe_prod", "");
83 if ($subscribeProd != '')
84 $arSubscribeProd = unserialize($subscribeProd, ['allowed_classes' => false]);
85
86 $rsItemsBasket = CSaleBasket::GetList(
87 array("USER_ID" => "DESC", "LID" => "ASC"),
88 array(
89 "PRODUCT_ID" => $ID,
90 "SUBSCRIBE" => "Y",
91 "CAN_BUY" => "N",
92 "ORDER_ID" => "NULL",
93 ">USER_ID" => "0",
94 "MODULE" => $MODULE
95 ),
96 false,
97 false,
98 array(
99 'ID',
100 'FUSER_ID',
101 'USER_ID',
102 'MODULE', 'PRODUCT_ID', 'CURRENCY', 'DATE_INSERT', 'QUANTITY', 'LID', 'DELAY', 'CALLBACK_FUNC', 'SUBSCRIBE', 'PRODUCT_PROVIDER_CLASS')
103 );
104 while ($arItemsBasket = $rsItemsBasket->Fetch())
105 {
106 $LID = $arItemsBasket["LID"];
107
108 if (isset($arSubscribeProd[$LID]) && $arSubscribeProd[$LID]["use"] == "Y")
109 {
110 $sendEmailList = array();
111 $USER_ID = $arItemsBasket['USER_ID'];
112 $arMailProp = array();
113 $arPayerProp = array();
114
115 // load user profiles
116 $arUserProfiles = CSaleOrderUserProps::DoLoadProfiles($USER_ID);
117 if (!empty($arUserProfiles))
118 {
119 // select person type
120 $dbPersonType = CSalePersonType::GetList(array("SORT" => "ASC"), array("LID" => $LID), false, false, array('ID'));
121 while ($arPersonType = $dbPersonType->Fetch())
122 {
123 // select ID props is mail
124 $dbProperties = CSaleOrderProps::GetList(
125 array(),
126 array("PERSON_TYPE_ID" => $arPersonType["ID"], "IS_EMAIL" => "Y", "ACTIVE" => "Y"),
127 false,
128 false,
129 array('ID', 'PERSON_TYPE_ID')
130 );
131 while ($arProperties = $dbProperties->Fetch())
132 $arMailProp[$arProperties["PERSON_TYPE_ID"]] = $arProperties["ID"];
133
134 // select ID props is name
135 $dbProperties = CSaleOrderProps::GetList(
136 array(),
137 array("PERSON_TYPE_ID" => $arPersonType["ID"], "IS_PAYER" => "Y", "ACTIVE" => "Y"),
138 false,
139 false,
140 array('ID', 'PERSON_TYPE_ID')
141 );
142 while ($arProperties = $dbProperties->Fetch())
143 $arPayerProp[$arProperties["PERSON_TYPE_ID"]] = $arProperties["ID"];
144 }//end while
145 }
146
147 $rsUser = CUser::GetByID($USER_ID);
148 $arUser = $rsUser->Fetch();
149 $userName = $arUser["LAST_NAME"];
150 if ($userName != '')
151 $userName .= " ";
152 $userName .= $arUser["NAME"];
153
154 // select of user name to be sent
155 $arUserSendName = array();
156 if (!empty($arUserProfiles) && !empty($arPayerProp))
157 {
158 foreach($arPayerProp as $personType => $namePropID)
159 {
160 if (isset($arUserProfiles[$personType]))
161 {
162 foreach($arUserProfiles[$personType] as $profiles)
163 {
164 if (isset($profiles["VALUES"][$namePropID]) && $profiles["VALUES"][$namePropID] != '')
165 {
166 $arUserSendName[$personType] = trim($profiles["VALUES"][$namePropID]);
167 break;
168 }
169 else
170 {
171 $arUserSendName[$personType] = $userName;
172 }
173 }
174 }
175 else
176 {
177 $arUserSendName[$personType] = $userName;
178 }
179 }
180 }
181 else
182 {
183 $arUserSendName[] = $userName;
184 }
185
186 // select of e-mail to be sent
187 $arUserSendMail = array();
188 if (!empty($arUserProfiles) && !empty($arMailProp))
189 {
190 foreach($arMailProp as $personType => $mailPropID)
191 {
192 if (isset($arUserProfiles[$personType]))
193 {
194 foreach($arUserProfiles[$personType] as $profiles)
195 {
196 if (isset($profiles["VALUES"][$mailPropID]) && $profiles["VALUES"][$mailPropID] != '')
197 {
198 $arUserSendMail[$personType] = trim($profiles["VALUES"][$mailPropID]);
199 break;
200 }
201 else
202 {
203 $arUserSendMail[$personType] = $arUser["EMAIL"];
204 }
205 }
206 }
207 else
208 {
209 $arUserSendMail[$personType] = $arUser["EMAIL"];
210 }
211 }
212 }
213 else
214 {
215 $arUserSendMail[] = $arUser["EMAIL"];
216 }
217
219 if ($productProvider = CSaleBasket::GetProductProvider($arItemsBasket))
220 {
221 $arCallback = $productProvider::GetProductData(array(
222 "PRODUCT_ID" => $ID,
223 "QUANTITY" => 1,
224 "RENEWAL" => "N",
225 "USER_ID" => $USER_ID,
226 "SITE_ID" => $LID,
227 "BASKET_ID" => $arItemsBasket["ID"],
228 ));
229 }
230 elseif (isset($arItemsBasket["CALLBACK_FUNC"]) && !empty($arItemsBasket["CALLBACK_FUNC"]))
231 {
233 trim($arItemsBasket["CALLBACK_FUNC"]),
234 $MODULE,
235 $ID,
236 1,
237 "N",
238 $USER_ID,
239 $LID
240 );
241 }
242
243 if (!empty($arCallback))
244 {
245 $arCallback["QUANTITY"] = 1;
246 $arCallback["DELAY"] = "N";
247 $arCallback["SUBSCRIBE"] = "N";
248 CSaleBasket::Update($arItemsBasket["ID"], $arCallback);
249 }
250
251 //send mail
252 if (!empty($arUserSendMail) && !empty($arCallback))
253 {
254 $eventName = "SALE_SUBSCRIBE_PRODUCT";
255 $event = new CEvent;
256
257 foreach ($arUserSendMail as $personType => $mail)
258 {
259 $checkMail = mb_strtolower($mail);
260 if (isset($sendEmailList[$checkMail]))
261 continue;
262 $sendName = $userName;
263 if (isset($arUserSendName[$personType]) && $arUserSendName[$personType] != '')
264 $sendName = $arUserSendName[$personType];
265
267 "EMAIL" => $mail,
268 "USER_NAME" => $sendName,
269 "NAME" => $arCallback["NAME"],
270 "PAGE_URL" => CHTTP::URN2URI($arCallback["DETAIL_PAGE_URL"]),
271 "SALE_EMAIL" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER["SERVER_NAME"]),
272 );
273
274 $event->Send($eventName, $LID, $arFields, "N");
275 $sendEmailList[$checkMail] = true;
276 }
277 }
278 }// end if bSend
279 }// end while $arItemsBasket
280
281 return true;
282 }
283
284 public static function DoGetUserShoppingCart($siteId, $userId, $shoppingCart, &$arErrors, $arCoupons = array(), $orderId = 0, $enableCustomCurrency = false)
285 {
286 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
287
288 $siteId = trim($siteId);
289 if (empty($siteId))
290 {
291 $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_PARAM_SITE_ERROR'));
292 return null;
293 }
294
295 $userId = intval($userId);
296
297 if (!is_array($shoppingCart))
298 {
299 if (intval($shoppingCart)."|" != $shoppingCart."|")
300 {
301 $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_PARAM_SK_ERROR'));
302 return null;
303 }
304 $shoppingCart = intval($shoppingCart);
305
306 $dbShoppingCartItems = CSaleBasket::GetList(
307 array("NAME" => "ASC"),
308 array(
309 "FUSER_ID" => $shoppingCart,
310 "LID" => $siteId,
311 "ORDER_ID" => "NULL",
312 "DELAY" => "N",
313 ),
314 false,
315 false,
316 array(
317 "ID", "LID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "QUANTITY", "DELAY",
318 "CAN_BUY", "PRICE", "WEIGHT", "NAME", "CURRENCY", "CATALOG_XML_ID",
319 "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS",
320 "RESERVED", "DEDUCTED", "RESERVE_QUANTITY", "DIMENSIONS", "TYPE", "SET_PARENT_ID"
321 )
322 );
323 $arTmp = array();
324 while ($arShoppingCartItem = $dbShoppingCartItems->Fetch())
325 $arTmp[] = $arShoppingCartItem;
326
327 $shoppingCart = $arTmp;
328 }
329
330 $arOldShoppingCart = array();
331 if ($orderId != 0) // for existing basket we need old data to calculate quantity delta for availability checking
332 {
334 array("NAME" => "ASC"),
335 array(
336 "LID" => $siteId,
337 "ORDER_ID" => $orderId,
338 "DELAY" => "N",
339 ),
340 false,
341 false,
342 array(
343 "ID", "LID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "PRODUCT_PRICE_ID", "PRICE",
344 "QUANTITY", "DELAY", "CAN_BUY", "PRICE", "WEIGHT", "NAME", "CURRENCY",
345 "CATALOG_XML_ID", "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS",
346 "RESERVED", "DEDUCTED", "BARCODE_MULTI", "DIMENSIONS", "TYPE", "SET_PARENT_ID"
347 )
348 );
349 while ($arOldShoppingCartItem = $dbs->Fetch())
350 $arOldShoppingCart[$arOldShoppingCartItem["ID"]] = $arOldShoppingCartItem;
351 }
352
353 if (CSaleHelper::IsAssociativeArray($shoppingCart))
354 $shoppingCart = array($shoppingCart);
355
356 if (!empty($arCoupons))
357 {
358 if (!is_array($arCoupons))
359 $arCoupons = array($arCoupons);
360 foreach(GetModuleEvents("sale", "OnSetCouponList", true) as $arEvent)
361 ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array()));
362 foreach ($arCoupons as &$coupon)
363 $couponResult = DiscountCouponsManager::add($coupon);
364 unset($coupon, $couponResult);
365 }
366
367 if(!is_bool($enableCustomCurrency))
368 {
369 $enableCustomCurrency = false;
370 }
371
372 $arResult = array();
373 $emptyID = 1;
374
375 foreach ($shoppingCart as $itemIndex => $arShoppingCartItem)
376 {
377 if ((array_key_exists("CALLBACK_FUNC", $arShoppingCartItem) && !empty($arShoppingCartItem["CALLBACK_FUNC"]))
378 || (array_key_exists("PRODUCT_PROVIDER_CLASS", $arShoppingCartItem) && !empty($arShoppingCartItem["PRODUCT_PROVIDER_CLASS"])))
379 {
380 // get quantity difference to check its availability
381
382 if ($orderId != 0)
383 $quantity = $arShoppingCartItem["QUANTITY"] - $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["QUANTITY"];
384 else
385 $quantity = $arShoppingCartItem["QUANTITY"];
386
387 $customPrice = (isset($arShoppingCartItem['CUSTOM_PRICE']) && $arShoppingCartItem['CUSTOM_PRICE'] == 'Y');
388 $existBasketID = (isset($arShoppingCartItem['ID']) && (int)$arShoppingCartItem['ID'] > 0);
390 if ($productProvider = CSaleBasket::GetProductProvider($arShoppingCartItem))
391 {
392 if ($existBasketID)
393 {
394 $basketID = $arShoppingCartItem['ID'];
395 }
396 elseif (isset($arShoppingCartItem["ID_TMP"]))
397 {
398 $basketID = $arShoppingCartItem["ID_TMP"];
399 }
400 else
401 {
402 $basketID = 'tmp_'.$emptyID;
403 $emptyID++;
404 }
405 $providerParams = array(
406 "PRODUCT_ID" => $arShoppingCartItem["PRODUCT_ID"],
407 "QUANTITY" => ($quantity > 0) ? $quantity : $arShoppingCartItem["QUANTITY"],
408 "RENEWAL" => "N",
409 "USER_ID" => $userId,
410 "SITE_ID" => $siteId,
411 "BASKET_ID" => $basketID,
412 "CHECK_QUANTITY" => ($quantity > 0) ? "Y" : "N",
413 "CHECK_COUPONS" => ('Y' == $arShoppingCartItem['CAN_BUY'] && (!array_key_exists('DELAY', $arShoppingCartItem) || 'Y' != $arShoppingCartItem['DELAY']) ? 'Y' : 'N'),
414 "CHECK_PRICE" => ($customPrice ? "N" : "Y")
415 );
416 if (isset($arShoppingCartItem['NOTES']))
417 $providerParams['NOTES'] = $arShoppingCartItem['NOTES'];
418 $arFieldsTmp = $productProvider::GetProductData($providerParams);
419 unset($providerParams);
420 }
421 else
422 {
424 $arShoppingCartItem["CALLBACK_FUNC"],
425 $arShoppingCartItem["MODULE"],
426 $arShoppingCartItem["PRODUCT_ID"],
427 $quantity,
428 "N",
429 $userId,
430 $siteId
431 );
432 if (!empty($arFieldsTmp) && is_array($arFieldsTmp))
433 {
434 if ($customPrice)
435 unset($arFieldsTmp['PRICE'], $arFieldsTmp['CURRENCY']);
436 }
437 }
438
439 if (!empty($arFieldsTmp) && is_array($arFieldsTmp))
440 {
441 $arFieldsTmp["CAN_BUY"] = "Y";
442 $arFieldsTmp["SUBSCRIBE"] = "N";
443 $arFieldsTmp['TYPE'] = (int)$arShoppingCartItem['TYPE'];
444 $arFieldsTmp['SET_PARENT_ID'] = $arShoppingCartItem['SET_PARENT_ID'];
445 $arFieldsTmp['LID'] = $siteId;
446 }
447 else
448 {
449 $arFieldsTmp = array("CAN_BUY" => "N");
450 }
451
452 if ($isOrderConverted != 'N')
453 {
454 if (!Sale\Compatible\DiscountCompatibility::isInited())
455 Sale\Compatible\DiscountCompatibility::init();
456 $basketCode = (Sale\Compatible\DiscountCompatibility::usedByClient() ? $arShoppingCartItem['ID'] : $itemIndex);
457 Sale\Compatible\DiscountCompatibility::setBasketItemData($basketCode, $arFieldsTmp);
458 }
459
460 if ($existBasketID)
461 {
462 $arFieldsTmp["IGNORE_CALLBACK_FUNC"] = "Y";
463
464 CSaleBasket::Update($arShoppingCartItem["ID"], $arFieldsTmp);
465
466 $dbTmp = CSaleBasket::GetList(
467 array(),
468 array("ID" => $arShoppingCartItem["ID"]),
469 false,
470 false,
471 array(
472 "ID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "QUANTITY", "DELAY", "CAN_BUY", "PRICE", "TYPE", "SET_PARENT_ID",
473 "WEIGHT", "NAME", "CURRENCY", "CATALOG_XML_ID", "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS", "DIMENSIONS"
474 )
475 );
476 $arTmp = $dbTmp->Fetch();
477
478 foreach ($arTmp as $key => $val)
479 $arShoppingCartItem[$key] = $val;
480 }
481 else
482 {
483 foreach ($arFieldsTmp as $key => $val)
484 {
485 // update returned quantity for the product if quantity difference is available
486 if ($orderId != 0 && $key == "QUANTITY" && $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["RESERVED"] == "Y" && $quantity > 0)
487 {
488 $arShoppingCartItem[$key] = $val + $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["QUANTITY"];
489 }
490 else
491 {
492 $arShoppingCartItem[$key] = $val;
493 }
494 }
495 }
496 }
497
498 if ($arShoppingCartItem["CAN_BUY"] == "Y")
499 {
500 if(!$enableCustomCurrency)
501 {
502 $baseLangCurrency = CSaleLang::GetLangCurrency($siteId);
503 if ($baseLangCurrency != $arShoppingCartItem["CURRENCY"])
504 {
505 $arShoppingCartItem["PRICE"] = CCurrencyRates::ConvertCurrency($arShoppingCartItem["PRICE"], $arShoppingCartItem["CURRENCY"], $baseLangCurrency);
506 if (is_set($arShoppingCartItem, "DISCOUNT_PRICE"))
507 $arShoppingCartItem["DISCOUNT_PRICE"] = CCurrencyRates::ConvertCurrency($arShoppingCartItem["DISCOUNT_PRICE"], $arShoppingCartItem["CURRENCY"], $baseLangCurrency);
508 $arShoppingCartItem["CURRENCY"] = $baseLangCurrency;
509 }
510 }
511
512 $arShoppingCartItem["PRICE"] = \Bitrix\Sale\PriceMaths::roundPrecision($arShoppingCartItem["PRICE"]);
513
514 $arShoppingCartItem["QUANTITY"] = floatval($arShoppingCartItem["QUANTITY"]);
515 $arShoppingCartItem["WEIGHT"] = floatval($arShoppingCartItem["WEIGHT"]);
516 $arShoppingCartItem["DIMENSIONS"] = unserialize($arShoppingCartItem["DIMENSIONS"], ['allowed_classes' => false]);
517 $arShoppingCartItem["VAT_RATE"] = floatval($arShoppingCartItem["VAT_RATE"]);
518 $arShoppingCartItem["DISCOUNT_PRICE"] = roundEx($arShoppingCartItem["DISCOUNT_PRICE"], SALE_VALUE_PRECISION);
519
520 if ($arShoppingCartItem["VAT_RATE"] > 0)
521 $arShoppingCartItem["VAT_VALUE"] = \Bitrix\Sale\PriceMaths::roundPrecision(($arShoppingCartItem["PRICE"] / ($arShoppingCartItem["VAT_RATE"] + 1)) * $arShoppingCartItem["VAT_RATE"]);
522 //$arShoppingCartItem["VAT_VALUE"] = roundEx((($arShoppingCartItem["PRICE"] / ($arShoppingCartItem["VAT_RATE"] + 1)) * $arShoppingCartItem["VAT_RATE"]), SALE_VALUE_PRECISION);
523
524 if ($arShoppingCartItem["DISCOUNT_PRICE"] > 0)
525 $arShoppingCartItem["DISCOUNT_PRICE_PERCENT"] = $arShoppingCartItem["DISCOUNT_PRICE"] * 100 / ($arShoppingCartItem["DISCOUNT_PRICE"] + $arShoppingCartItem["PRICE"]);
526 $arResult[$itemIndex] = $arShoppingCartItem;
527 }
528 }
529 if (isset($arShoppingCartItem))
530 unset($arShoppingCartItem);
531
532 if (!empty($arCoupons) && is_array($arCoupons))
533 {
534 foreach(GetModuleEvents("sale", "OnClearCouponList", true) as $arEvent)
535 ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array()));
536 }
537
538 return $arResult;
539 }
540
559 public static function DoChangeProductQuantity($arBasketItem, $deltaQuantity, $isOrderReserved = false, $isOrderDeducted = false, $arStoreBarcodeOrderFormData = array(), $arAdditionalParams = array())
560 {
561 global $APPLICATION;
562
563 if (!array_key_exists("CHECK_QUANTITY", $arAdditionalParams) || $arAdditionalParams["CHECK_QUANTITY"] != "N")
564 $arAdditionalParams["CHECK_QUANTITY"] = "Y";
565
566 if (defined("SALE_DEBUG") && SALE_DEBUG)
567 {
569 "DoChangeProductQuantity - Started",
570 array(
571 "arBasketItem" => $arBasketItem,
572 "deltaQuantity" => $deltaQuantity,
573 "isOrderReserved" => intval($isOrderReserved),
574 "isOrderDeducted" => intval($isOrderDeducted),
575 "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData,
576 "checkQuantity" => $arAdditionalParams["CHECK_QUANTITY"]
577 ),
578 "DCPQ1"
579 );
580 }
581
583 if ($productProvider = CSaleBasket::GetProductProvider($arBasketItem))
584 {
585 $productProvider::OrderProduct(
586 array(
587 "PRODUCT_ID" => $arBasketItem["PRODUCT_ID"],
588 "QUANTITY" => ($deltaQuantity <= 0 ? $arBasketItem['QUANTITY'] : $deltaQuantity),
589 "RENEWAL" => "N",
590 "USER_ID" => $arAdditionalParams["USER_ID"],
591 "SITE_ID" => $arAdditionalParams["SITE_ID"],
592 "CHECK_QUANTITY" => $arAdditionalParams["CHECK_QUANTITY"],
593 "BASKET_ID" => $arBasketItem['ID']
594 )
595 );
596 if ($deltaQuantity == 0 && $arAdditionalParams["CHECK_QUANTITY"] == 'N')
597 return true;
598
599 if ($isOrderDeducted) // we need to reserve and deduct product
600 {
601 $quantityPreviouslyLeftToReserve = ($arBasketItem["RESERVED"] == "Y") ? floatval($arBasketItem["RESERVE_QUANTITY"]) : 0;
602
603 if (defined("SALE_DEBUG") && SALE_DEBUG)
604 {
606 "Call ::ReserveBasketProduct",
607 array(
608 "arBasketItemID" => $arBasketItem["ID"],
609 "deltaQuantity" => $deltaQuantity,
610 "quantityPreviouslyLeftToReserve" => $quantityPreviouslyLeftToReserve,
611 "isOrderDeducted" => $isOrderDeducted
612 ),
613 "DCPQ2"
614 );
615 }
616
617 $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve, $isOrderDeducted);
618 if (array_key_exists("ERROR", $arRes))
619 {
620 CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"])));
621 return false;
622 }
623
624 if (defined("SALE_DEBUG") && SALE_DEBUG)
625 {
627 "Call ::DeductBasketProduct",
628 array(
629 "arBasketItemID" => $arBasketItem["ID"],
630 "deltaQuantity" => $deltaQuantity,
631 "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData
632 ),
633 "DCPQ3"
634 );
635 }
636
637 $arDeductResult = CSaleBasket::DeductBasketProduct($arBasketItem["ID"], $deltaQuantity, $arStoreBarcodeOrderFormData);
638 if (array_key_exists("ERROR", $arDeductResult))
639 {
640 CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"])));
641 $APPLICATION->ThrowException(Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"])), "DEDUCTION_ERROR");
642 return false;
643 }
644 }
645 else if ($isOrderReserved && !$isOrderDeducted) // we need to reserve product
646 {
647 if ($arBasketItem["RESERVED"] == "Y")
648 {
649 $quantityPreviouslyLeftToReserve = floatval($arBasketItem["RESERVE_QUANTITY"]);
650
651 if (defined("SALE_DEBUG") && SALE_DEBUG)
652 {
654 "Call ::ReserveBasketProduct",
655 array(
656 "arBasketItemID" => $arBasketItem["ID"],
657 "deltaQuantity" => $deltaQuantity,
658 "quantityPreviouslyLeftToReserve" => $quantityPreviouslyLeftToReserve
659 ),
660 "DCPQ4"
661 );
662 }
663
664 $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve);
665 if (array_key_exists("ERROR", $arRes))
666 {
667 CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"])));
668 return false;
669 }
670 }
671 else
672 {
673 if (defined("SALE_DEBUG") && SALE_DEBUG)
674 {
676 "Call ::ReserveBasketProduct",
677 array(
678 "arBasketItemID" => $arBasketItem["ID"],
679 "deltaQuantity" => $deltaQuantity
680 ),
681 "DCPQ5"
682 );
683 }
684
685 $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity);
686 if (array_key_exists("ERROR", $arRes))
687 {
688 CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"])));
689 return false;
690 }
691 }
692 }
693 else // order not reserved, not deducted
694 {
695 if (defined("SALE_DEBUG") && SALE_DEBUG)
696 {
698 "Call ::ReserveBasketProduct",
699 array(
700 "arBasketItemID" => $arBasketItem["ID"],
701 "deltaQuantity" => $deltaQuantity
702 ),
703 "DCPQ6"
704 );
705 }
706
707 if ($arBasketItem["RESERVED"] == "Y") // we undo product reservation
708 {
709 $quantityPreviouslyLeftToReserve = floatval($arBasketItem["RESERVE_QUANTITY"]);
710
711 $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve);
712 if (array_key_exists("ERROR", $arRes))
713 {
714 CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"])));
715 return false;
716 }
717 }
718 }
719 }
720 else // provider is not used. old logic without reservation
721 {
722 if ($deltaQuantity < 0)
723 {
725 $arBasketItem["CANCEL_CALLBACK_FUNC"],
726 $arBasketItem["MODULE"],
727 $arBasketItem["PRODUCT_ID"],
728 abs($deltaQuantity),
729 true
730 );
731 }
732 else if ($deltaQuantity > 0)
733 {
735 $arBasketItem["ORDER_CALLBACK_FUNC"],
736 $arBasketItem["MODULE"],
737 $arBasketItem["PRODUCT_ID"],
738 $deltaQuantity,
739 "N",
740 $arAdditionalParams["USER_ID"],
741 $arAdditionalParams["SITE_ID"]
742 );
743 }
744 else if ($deltaQuantity == 0)
745 {
747 $arBasketItem["ORDER_CALLBACK_FUNC"],
748 $arBasketItem["MODULE"],
749 $arBasketItem["PRODUCT_ID"],
750 $arBasketItem['QUANTITY'],
751 "N",
752 $arAdditionalParams["USER_ID"],
753 $arAdditionalParams["SITE_ID"]
754 );
755 }
756 }
757 return true;
758 }
759
774 public static function DoSaveOrderBasket($orderId, $siteId, $userId, &$arShoppingCart, &$arErrors, $arCoupons = array(), $arStoreBarcodeOrderFormData = array(), $bSaveBarcodes = false)
775 {
776 global $USER, $APPLICATION;
777
778 $currentUserID = 0;
779 if (isset($USER) && $USER instanceof CUser)
780 $currentUserID = (int)$USER->GetID();
781
782 if (defined("SALE_DEBUG") && SALE_DEBUG)
783 {
784 CSaleHelper::WriteToLog("DoSaveOrderBasket - Started",
785 array(
786 "orderId" => $orderId,
787 "siteId" => $siteId,
788 "userId" => $userId,
789 "arShoppingCart" => $arShoppingCart,
790 "bSaveBarcodes" => $bSaveBarcodes,
791 "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData
792 ),
793 "DSOB1"
794 );
795 }
796
797 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
798
799 $orderId = (int)$orderId;
800 if ($orderId <= 0)
801 return false;
802
803 if (empty($arShoppingCart) || !is_array($arShoppingCart))
804 {
805 $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_SHOPPING_CART_EMPTY'));
806 return false;
807 }
808
809 $isOrderReserved = false;
810 $isOrderDeducted = false;
811 $dbOrderTmp = CSaleOrder::GetList(
812 array(),
813 array("ID" => $orderId),
814 false,
815 false,
816 array("ID", "RESERVED", "DEDUCTED")
817 );
818 if ($arOrder = $dbOrderTmp->Fetch())
819 {
820 if ($arOrder["RESERVED"] == "Y")
821 $isOrderReserved = true;
822 if ($arOrder["DEDUCTED"] == "Y")
823 $isOrderDeducted = true;
824 }
825
826 $arOldItems = array();
827 $dbItems = CSaleBasket::GetList(
828 array(),
829 array("ORDER_ID" => $orderId),
830 false,
831 false,
832 array(
833 "ID",
834 "QUANTITY",
835 "CANCEL_CALLBACK_FUNC",
836 "MODULE",
837 "PRODUCT_ID",
838 "PRODUCT_PROVIDER_CLASS",
839 "RESERVED",
840 "RESERVE_QUANTITY",
841 "TYPE",
842 "SET_PARENT_ID"
843 )
844 );
845 while ($arItem = $dbItems->Fetch())
846 {
847 $arOldItems[$arItem["ID"]] = array(
848 "QUANTITY" => $arItem["QUANTITY"],
849 "CANCEL_CALLBACK_FUNC" => $arItem["CANCEL_CALLBACK_FUNC"],
850 "PRODUCT_PROVIDER_CLASS" => $arItem["PRODUCT_PROVIDER_CLASS"],
851 "MODULE" => $arItem["MODULE"],
852 "PRODUCT_ID" => $arItem["PRODUCT_ID"],
853 "RESERVED" => $arItem["RESERVED"],
854 "RESERVE_QUANTITY" => $arItem["RESERVE_QUANTITY"],
855 "TYPE" => $arItem["TYPE"],
856 "SET_PARENT_ID" => $arItem["SET_PARENT_ID"]
857 );
858 }
859
860 if (!empty($arCoupons))
861 {
862 if (!is_array($arCoupons))
863 $arCoupons = array($arCoupons);
864 foreach (GetModuleEvents("sale", "OnSetCouponList", true) as $arEvent)
865 ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array()));
866 foreach ($arCoupons as &$coupon)
867 $couponResult = DiscountCouponsManager::add($coupon);
868 unset($coupon, $couponResult);
869 }
870
871 $FUSER_ID = Sale\Fuser::getIdByUserId((int)$userId);
872
873 $arTmpSetParentId = array();
874
875 //TODO: is orders converted?
876 if ($isOrderConverted == 'N')
877 {
878 // re-sort basket data so newly added Set parents come before Set items (used to correctly add Set items to the table)
879 usort($arShoppingCart, array("CSaleBasketHelper", "cmpSetData"));
880
881 foreach ($arShoppingCart as &$arItem)
882 {
883 $arItemKeys = array_keys($arItem);
884
885 foreach ($arItemKeys as $fieldName)
886 {
887 if(array_key_exists("~".$fieldName, $arItem))
888 {
889 if ((is_array($arItem["~".$fieldName]) && !empty($arItem["~".$fieldName]))
890 || (!is_array($arItem["~".$fieldName]) && $arItem["~".$fieldName] <> ''))
891 {
892 $arItem[$fieldName] = $arItem["~".$fieldName];
893 }
894 unset($arItem["~".$fieldName]);
895 }
896 }
897
898 $arItem = array_filter($arItem, array("CSaleBasketHelper", "filterFields"));
899 }
900 unset($arItem);
901
902
903 foreach ($arShoppingCart as $arItem)
904 {
905 if (mb_strpos($arItem["SET_PARENT_ID"], "tmp") !== false)
906 $arTmpSetParentId[$arItem["SET_PARENT_ID"]] = $arItem["SET_PARENT_ID"];
907 }
908 }
909
910 $orderBasketPool = array();
911
912 // iterate over basket data to save it to basket or change quantity (and reserve/deduct accordingly)
913 foreach ($arShoppingCart as &$arItem)
914 {
915
916 foreach ($arItem as $tmpKey => $tmpVal)
917 {
918 if (is_array($tmpVal) && !in_array($tmpKey, array("STORES", "CATALOG", "PROPS")))
919 $arItem[$tmpKey] = serialize($tmpVal);
920 }
921
922 if (defined("SALE_DEBUG") && SALE_DEBUG)
923 CSaleHelper::WriteToLog("DoSaveOrderBasket - Item", array("arItem" => $arItem), "DSOB2");
924
925
926 if (array_key_exists("ID", $arItem) && (int)$arItem["ID"] > 0)
927 {
928 $arItem["ID"] = (int)$arItem["ID"];
929
930 if (defined("SALE_DEBUG") && SALE_DEBUG)
931 CSaleHelper::WriteToLog("DoSaveOrderBasket - Product #".$arItem["ID"]." already in the basket", array(), "DSOB3");
932
933 // product already in the basket, change quantity
934 if (array_key_exists($arItem["ID"], $arOldItems))
935 {
936 //TODO: is order converted?
937 if ($isOrderConverted == 'N')
938 {
939 if (!CSaleBasketHelper::isSetParent($arItem))
940 {
941 $arAdditionalParams = array(
942 "ORDER_ID" => $orderId,
943 "USER_ID" => $userId,
944 "SITE_ID" => $siteId
945 );
946
947 $quantity = $arItem["QUANTITY"] - $arOldItems[$arItem["ID"]]["QUANTITY"];
948
949 $arAdditionalParams["CHECK_QUANTITY"] = ($quantity > 0) ? "Y" : "N";
950
951 if ($quantity != 0)
952 {
953 self::DoChangeProductQuantity(
954 $arItem,
955 $quantity,
956 $isOrderReserved,
957 $isOrderDeducted,
958 $arStoreBarcodeOrderFormData[$arItem["ID"]],
959 $arAdditionalParams
960 );
961 }
962 else
963 {
964 $arAdditionalParams['CHECK_QUANTITY'] = 'N';
965 self::DoChangeProductQuantity(
966 $arItem,
967 $quantity,
968 $isOrderReserved,
969 $isOrderDeducted,
970 $arStoreBarcodeOrderFormData[$arItem["ID"]],
971 $arAdditionalParams
972 );
973 }
974
975 }
976 }
977 unset($arOldItems[$arItem["ID"]]);
978 }
979 else
980 {
981 //TODO: is order converted?
982 if ($isOrderConverted == 'N')
983 {
984 if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem))
985 {
986 self::DoChangeProductQuantity(
987 $arItem,
988 $arItem["QUANTITY"],
989 $isOrderReserved,
990 $isOrderDeducted,
991 $arStoreBarcodeOrderFormData[$arItem["ID"]],
992 array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId)
993 );
994 }
995 }
996 }
997
998 if(intval($arItem["FUSER_ID"]) <= 0)
999 {
1000 $arFuserItems = CSaleUser::GetList(array("USER_ID" => intval($userId)));
1001 $arItem["FUSER_ID"] = $arFuserItems["ID"];
1002 }
1003
1004 if (CSaleBasketHelper::isSetItem($arItem)) // quantity for set items will be changed when parent item is updated
1005 unset($arItem["QUANTITY"]);
1006
1007
1008 //TODO: is order converted?
1009 if ($isOrderConverted != 'N')
1010 {
1011 $fields = array("IGNORE_CALLBACK_FUNC" => "Y") + $arItem;
1012
1013 $orderBasketPool[$arItem["ID"]] = array("ORDER_ID" => $orderId);
1014
1015 foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $event)
1016 {
1017 if (ExecuteModuleEventEx($event, array($arItem["ID"], &$fields)) === false)
1018 {
1019 return false;
1020 }
1021 }
1022
1024 $r = \Bitrix\Sale\Compatible\BasketCompatibility::update($arItem["ID"], $fields);
1025
1026 if (!$r->isSuccess(true))
1027 {
1028 foreach($r->getErrorMessages() as $error)
1029 {
1030 $APPLICATION->ThrowException($error);
1031 }
1032
1033 return false;
1034 }
1035 }
1036 else
1037 {
1038 CSaleBasket::Update($arItem["ID"], array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem);
1039 }
1040
1041 }
1042 else // new product in the basket
1043 {
1044 if (defined("SALE_DEBUG") && SALE_DEBUG)
1045 CSaleHelper::WriteToLog("DoSaveOrderBasket - new product in the basket", array(), "DSOB4");
1046
1047 unset($arItem["ID"]);
1048
1050 if ($productProvider = CSaleBasket::GetProductProvider($arItem)) //if we need to use new logic
1051 {
1052 $oldSetParentId = -1;
1053 if (CSaleBasketHelper::isSetParent($arItem) && array_key_exists($arItem["SET_PARENT_ID"], $arTmpSetParentId))
1054 {
1055 $oldSetParentId = $arItem["SET_PARENT_ID"];
1056 $arItem["MANUAL_SET_ITEMS_INSERTION"] = "Y";
1057 }
1058
1059 if (CSaleBasketHelper::isSetItem($arItem) && array_key_exists($arItem["SET_PARENT_ID"], $arTmpSetParentId))
1060 {
1061 $arItem["SET_PARENT_ID"] = $arTmpSetParentId[$arItem["SET_PARENT_ID"]];
1062 }
1063
1064 $arItem["ID"] = CSaleBasket::Add(array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem);
1065 if($APPLICATION->GetException())
1066 {
1067 return false;
1068 }
1069
1070 if (isset($arItem["MANUAL_SET_ITEMS_INSERTION"]))
1071 $arTmpSetParentId[$oldSetParentId] = $arItem["ID"];
1072
1073 if ($bSaveBarcodes)
1074 {
1075 if ($arItem["BARCODE_MULTI"] == "N") //saving only store quantity info
1076 {
1077 if (is_array($arItem["STORES"]))
1078 {
1079 foreach ($arItem["STORES"] as $arStore)
1080 {
1081 $arStoreBarcodeFields = array(
1082 "BASKET_ID" => $arItem["ID"],
1083 "BARCODE" => "",
1084 "STORE_ID" => $arStore["STORE_ID"],
1085 "QUANTITY" => $arStore["QUANTITY"],
1086 "CREATED_BY" => ($currentUserID > 0 ? $currentUserID : ''),
1087 "MODIFIED_BY" => ($currentUserID > 0 ? $currentUserID : '')
1088 );
1089
1090 CSaleStoreBarcode::Add($arStoreBarcodeFields);
1091 }
1092 }
1093 }
1094 else // BARCODE_MULTI = Y
1095 {
1096 if (!empty($arItem["STORES"]) && is_array($arItem["STORES"]))
1097 {
1098 foreach ($arItem["STORES"] as $arStore)
1099 {
1100 if (isset($arStore["BARCODE"]) && isset($arStore["BARCODE_FOUND"]))
1101 {
1102 foreach ($arStore["BARCODE"] as $barcodeId => $barcodeValue)
1103 {
1104 // save only non-empty and valid barcodes TODO - if errors?
1105 if ($barcodeValue <> '' && $arStore["BARCODE_FOUND"][$barcodeId] == "Y")
1106 {
1107 $arStoreBarcodeFields = array(
1108 "BASKET_ID" => $arItem["ID"],
1109 "BARCODE" => $barcodeValue,
1110 "STORE_ID" => $arStore["STORE_ID"],
1111 "QUANTITY" => 1,
1112 "CREATED_BY" => ($currentUserID > 0 ? $currentUserID : ''),
1113 "MODIFIED_BY" => ($currentUserID > 0 ? $currentUserID : '')
1114 );
1115
1116 CSaleStoreBarcode::Add($arStoreBarcodeFields);
1117 }
1118 }
1119 }
1120 }
1121 }
1122 }
1123 }
1124
1125 if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem))
1126 {
1127 self::DoChangeProductQuantity(
1128 $arItem,
1129 $arItem["QUANTITY"],
1130 $isOrderReserved,
1131 $isOrderDeducted,
1132 $arItem["STORES"],
1133 array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId)
1134 );
1135 }
1136
1137 if ($FUSER_ID > 0)
1138 $arItem["FUSER_ID"] = $FUSER_ID;
1139 }
1140 else
1141 {
1142 if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem))
1143 {
1144 self::DoChangeProductQuantity(
1145 $arItem,
1146 $arItem["QUANTITY"],
1147 $isOrderReserved,
1148 $isOrderDeducted,
1149 $arItem["STORES"],
1150 array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId)
1151 );
1152 }
1153
1154 if ($FUSER_ID > 0)
1155 $arItem["FUSER_ID"] = $FUSER_ID;
1156
1157 $arItem["ID"] = CSaleBasket::Add(array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem);
1158 //$arItem["ID"] = CSaleBasket::Add(array("CALLBACK_FUNC" => false, "ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem);
1159 }
1160 }
1161 }
1162 unset($arItem);
1163
1164 if ($isOrderConverted != 'N' && !empty($orderBasketPool))
1165 {
1167 $r = Sale\Compatible\BasketCompatibility::setBasketFields($orderBasketPool);
1168 if (!$r->isSuccess(true))
1169 {
1170 foreach($r->getErrorMessages() as $error)
1171 {
1172 $APPLICATION->ThrowException($error);
1173 }
1174
1175 return false;
1176 }
1177 }
1178
1179 if (defined("SALE_DEBUG") && SALE_DEBUG)
1180 CSaleHelper::WriteToLog("Items left in the old basket:", array("arOldItems" => $arOldItems), "DSOB5");
1181
1182 // if some items left in the table which are not present in the updated basket, delete them
1183 $arSetParentsIDs = array();
1184 foreach ($arOldItems as $key => $arOldItem)
1185 {
1186 $arOldItem["ID"] = $key;
1187
1188 if (CSaleBasketHelper::isSetParent($arOldItem))
1189 {
1190 $arSetParentsIDs[] = $arOldItem["ID"];
1191 continue;
1192 }
1193 else
1194 {
1195 if ($isOrderConverted == 'N')
1196 {
1197 // the quantity is negative, so the product is canceled
1198 self::DoChangeProductQuantity(
1199 $arOldItem,
1200 -$arOldItem["QUANTITY"],
1201 $isOrderReserved,
1202 $isOrderDeducted,
1203 $arStoreBarcodeOrderFormData[$arOldItem["ID"]],
1204 array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId)
1205 );
1206 }
1207 }
1208
1209 CSaleBasket::Delete($key);
1210 }
1211
1212 foreach ($arSetParentsIDs as $setParentID)
1213 CSaleBasket::Delete($setParentID);
1214
1215 foreach(GetModuleEvents("sale", "OnDoBasketOrder", true) as $arEvent)
1217
1218 return true;
1219 }
1220
1221 //************** ADD, UPDATE, DELETE ********************//
1222 public static function CheckFields($ACTION, &$arFields, $ID = 0)
1223 {
1224 global $APPLICATION;
1225 static $orderList = array();
1226
1227 $ACTION = mb_strtoupper($ACTION);
1228
1229 if (array_key_exists('ID', $arFields))
1230 unset($arFields['ID']);
1231
1232 if ($ACTION != "ADD" && (int)$ID <=0)
1233 {
1234 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_ID_ABSENT'), "ID");
1235 return false;
1236 }
1237
1238 if ('ADD' == $ACTION)
1239 {
1240 if (!array_key_exists('CUSTOM_PRICE', $arFields))
1241 $arFields['CUSTOM_PRICE'] = '';
1242 }
1243
1244 if (array_key_exists('CUSTOM_PRICE', $arFields) && 'Y' != $arFields['CUSTOM_PRICE'])
1245 $arFields['CUSTOM_PRICE'] = 'N';
1246
1247 if (is_set($arFields, "PRODUCT_ID"))
1248 $arFields["PRODUCT_ID"] = intval($arFields["PRODUCT_ID"]);
1249 if ((is_set($arFields, "PRODUCT_ID") || $ACTION=="ADD") && intval($arFields["PRODUCT_ID"])<=0)
1250 {
1251 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_PRODUCT_ID_ABSENT'), "PRODUCT_ID");
1252 return false;
1253 }
1254
1255 if (!array_key_exists('IGNORE_CALLBACK_FUNC', $arFields) || 'Y' != $arFields['IGNORE_CALLBACK_FUNC'])
1256 {
1257 if ((array_key_exists("CALLBACK_FUNC", $arFields) && !empty($arFields["CALLBACK_FUNC"]))
1258 || (array_key_exists("PRODUCT_PROVIDER_CLASS", $arFields) && !empty($arFields["PRODUCT_PROVIDER_CLASS"]))
1259 )
1260 {
1262 if ($productProvider = CSaleBasket::GetProductProvider(array("MODULE" => $arFields["MODULE"], "PRODUCT_PROVIDER_CLASS" => $arFields["PRODUCT_PROVIDER_CLASS"])))
1263 {
1264
1265 if (array_key_exists("IBXSaleProductProvider", class_implements($productProvider)))
1266 {
1267 $providerParams = array(
1268 "PRODUCT_ID" => $arFields["PRODUCT_ID"],
1269 "QUANTITY" => $arFields["QUANTITY"],
1270 "RENEWAL" => $arFields["RENEWAL"],
1271 "USER_ID" => (isset($arFields["USER_ID"]) ? $arFields["USER_ID"] : 0),
1272 "SITE_ID" => (isset($arFields["LID"]) ? $arFields["LID"] : false),
1273 "BASKET_ID" => $ID
1274 );
1275 if (isset($arFields['NOTES']))
1276 $providerParams['NOTES'] = $arFields['NOTES'];
1277 $arPrice = $productProvider::GetProductData($providerParams);
1278 unset($providerParams);
1279 }
1280 elseif (get_parent_class($productProvider) == 'Bitrix\Sale\SaleProviderBase')
1281 {
1282// $productProvider::getCatalogData();
1283// $productProvider::getProviderData();
1284// $productProvider::getProviderData();
1285 }
1286
1287
1288
1289
1290 }
1291 else
1292 {
1294 $arFields["CALLBACK_FUNC"],
1295 $arFields["MODULE"],
1296 $arFields["PRODUCT_ID"],
1297 $arFields["QUANTITY"],
1298 $arFields["RENEWAL"],
1299 $arFields["USER_ID"],
1300 $arFields["LID"]
1301 );
1302 }
1303
1304 if (!empty($arPrice) && is_array($arPrice))
1305 {
1306 if (isset($arPrice['BASE_PRICE']))
1307 $arPrice['BASE_PRICE'] = roundEx($arPrice['BASE_PRICE'], SALE_VALUE_PRECISION);
1308
1309 if (isset($arPrice['DISCOUNT_PRICE']))
1310 $arPrice['DISCOUNT_PRICE'] = roundEx($arPrice['DISCOUNT_PRICE'], SALE_VALUE_PRECISION);
1311
1312 if (isset($arPrice['PRICE']))
1313 $arPrice['PRICE'] = roundEx($arPrice['PRICE'], SALE_VALUE_PRECISION);
1314
1315 $arFields["PRICE"] = $arPrice["PRICE"];
1316 $arFields["CURRENCY"] = $arPrice["CURRENCY"];
1317 $arFields["CAN_BUY"] = "Y";
1318 $arFields["PRODUCT_PRICE_ID"] = $arPrice["PRODUCT_PRICE_ID"];
1319 $arFields["NOTES"] = $arPrice["NOTES"];
1320 if (!isset($arFields["NAME"]))
1321 $arFields["NAME"] = $arPrice["NAME"];
1322 if (isset($arPrice['DISCOUNT_LIST']))
1323 $arFields['DISCOUNT_LIST'] = $arPrice['DISCOUNT_LIST'];
1324 }
1325 else
1326 {
1327 if ($ACTION == 'ADD')
1328 return false;
1329 $arFields["CAN_BUY"] = "N";
1330 }
1331 }
1332 }
1333
1334 if (is_set($arFields, "PRICE") || $ACTION=="ADD")
1335 {
1336 $arFields["PRICE"] = str_replace(",", ".", $arFields["PRICE"]);
1337 $arFields["PRICE"] = floatval($arFields["PRICE"]);
1338 }
1339
1340 if (is_set($arFields, "DISCOUNT_PRICE") || $ACTION=="ADD")
1341 {
1342 $arFields["DISCOUNT_PRICE"] = str_replace(",", ".", $arFields["DISCOUNT_PRICE"]);
1343 $arFields["DISCOUNT_PRICE"] = floatval($arFields["DISCOUNT_PRICE"]);
1344 }
1345
1346 if (is_set($arFields, "VAT_RATE") || $ACTION=="ADD")
1347 {
1348 $arFields["VAT_RATE"] = str_replace(",", ".", $arFields["VAT_RATE"]);
1349 $arFields["VAT_RATE"] = floatval($arFields["VAT_RATE"]);
1350 }
1351
1352 if ((is_set($arFields, "CURRENCY") || $ACTION=="ADD") && $arFields["CURRENCY"] == '')
1353 {
1354 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_CURRENCY_ABSENT'), "CURRENCY");
1355 return false;
1356 }
1357
1358 if ((is_set($arFields, "LID") || $ACTION=="ADD") && $arFields["LID"] == '')
1359 {
1360 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_SITE_ID_ABSENT'), "LID");
1361 return false;
1362 }
1363
1364 if (is_set($arFields, "ORDER_ID"))
1365 {
1366 if (!isset($orderList[$arFields["ORDER_ID"]]))
1367 {
1368 $rsOrders = CSaleOrder::GetList(
1369 array(),
1370 array('ID' => $arFields["ORDER_ID"]),
1371 false,
1372 false,
1373 array('ID')
1374 );
1375 if ($arOrder = $rsOrders->Fetch())
1376 {
1377 $orderList[$arFields["ORDER_ID"]] = true;
1378 }
1379 }
1380 if (!isset($orderList[$arFields["ORDER_ID"]]))
1381 {
1382 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["ORDER_ID"], Loc::getMessage("SKGB_NO_ORDER")), "ORDER_ID");
1383 return false;
1384 }
1385 }
1386
1387 if (is_set($arFields, 'CURRENCY'))
1388 {
1389 $arFields['CURRENCY'] = (string)$arFields['CURRENCY'];
1390 if (empty($arFields['CURRENCY']))
1391 {
1392 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["CURRENCY"], Loc::getMessage("SKGB_NO_CURRENCY")), "CURRENCY");
1393 return false;
1394 }
1395 else
1396 {
1397 if (empty(self::$currencyList))
1398 {
1399 $currencyIterator = Currency\CurrencyTable::getList(array(
1400 'select' => array('CURRENCY'),
1401 ));
1402 while ($currency = $currencyIterator->fetch())
1403 self::$currencyList[$currency['CURRENCY']] = $currency['CURRENCY'];
1404 }
1405 if (!isset(self::$currencyList[$arFields['CURRENCY']]))
1406 {
1407 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["CURRENCY"], Loc::getMessage("SKGB_NO_CURRENCY")), "CURRENCY");
1408 return false;
1409 }
1410 }
1411 }
1412
1413 if (is_set($arFields, "LID"))
1414 {
1415 $dbSite = CSite::GetByID($arFields["LID"]);
1416 if (!$dbSite->Fetch())
1417 {
1418 $APPLICATION->ThrowException(str_replace("#ID#", $arFields["LID"], Loc::getMessage("SKGB_NO_SITE")), "LID");
1419 return false;
1420 }
1421 }
1422
1423 if ($ACTION != 'ADD')
1424 {
1425 $existPrice = array_key_exists('PRICE', $arFields);
1426 $existCurrency = array_key_exists('CURRENCY', $arFields) && (string)$arFields['CURRENCY'] != '';
1427 if (!$existPrice || !$existCurrency)
1428 {
1429 $existSiteId = isset($arFields['LID']) && (string)$arFields['LID'] != '';
1430 if (!$existSiteId)
1431 {
1432 $select = array('ID', 'LID');
1433 if (!$existPrice)
1434 $select[] = 'PRICE';
1435 if (!$existCurrency)
1436 $select[] = 'CURRENCY';
1437 $basketIterator = CSaleBasket::GetList(
1438 array(),
1439 array('ID' => $ID),
1440 false,
1441 false,
1442 $select
1443 );
1444 if ($basket = $basketIterator->Fetch())
1445 {
1446 if (!$existSiteId)
1447 $arFields['LID'] = $basket['LID'];
1448 if (!$existPrice)
1449 $arFields['PRICE'] = $basket['PRICE'];
1450 if (!$existCurrency)
1451 $arFields['CURRENCY'] = $basket['CURRENCY'];
1452 }
1453 unset($basket, $basketIterator, $select);
1454 }
1455 unset($existSiteId);
1456 }
1457 unset($existCurrency, $existPrice);
1458 }
1459
1460 if (!empty($arFields['LID']) && !empty($arFields['CURRENCY']))
1461 {
1462 if (!isset(self::$currencySiteList[$arFields['LID']]))
1463 self::$currencySiteList[$arFields['LID']] = CSaleLang::GetLangCurrency($arFields['LID']);
1464 $siteCurrency = self::$currencySiteList[$arFields['LID']];
1465 if ($siteCurrency != $arFields['CURRENCY'])
1466 {
1467 $arFields["PRICE"] = roundEx(CCurrencyRates::ConvertCurrency($arFields["PRICE"], $arFields["CURRENCY"], $siteCurrency), SALE_VALUE_PRECISION);
1468 if (is_set($arFields, "DISCOUNT_PRICE"))
1469 $arFields["DISCOUNT_PRICE"] = roundEx(CCurrencyRates::ConvertCurrency($arFields["DISCOUNT_PRICE"], $arFields["CURRENCY"], $siteCurrency), SALE_VALUE_PRECISION);
1470 $arFields["CURRENCY"] = $siteCurrency;
1471 }
1472 unset($siteCurrency);
1473 }
1474
1475 // Changed by Sigurd, 2007-08-16
1476 if (is_set($arFields, "QUANTITY"))
1477 $arFields["QUANTITY"] = floatval($arFields["QUANTITY"]);
1478 if ((is_set($arFields, "QUANTITY") || $ACTION=="ADD") && floatval($arFields["QUANTITY"]) <= 0)
1479 $arFields["QUANTITY"] = 1;
1480
1481 if (is_set($arFields, "DELAY") && $arFields["DELAY"]!="Y")
1482 $arFields["DELAY"]="N";
1483 if (is_set($arFields, "CAN_BUY") && $arFields["CAN_BUY"]!="Y")
1484 $arFields["CAN_BUY"]="N";
1485
1486 if ((is_set($arFields, "NAME") || $ACTION=="ADD") && $arFields["NAME"] == '')
1487 {
1488 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_NAME_ABSENT'), "NAME");
1489 return false;
1490 }
1491
1492 if ($ACTION=="ADD" && !is_set($arFields, "FUSER_ID"))
1493 $arFields["FUSER_ID"] = CSaleBasket::GetBasketUserID(false);
1494
1495 if ((is_set($arFields, "FUSER_ID") || $ACTION=="ADD") && intval($arFields["FUSER_ID"])<=0)
1496 {
1497 $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_FUSER_ID_ABSENT'), "FUSER_ID");
1498 return false;
1499 }
1500
1501 if (array_key_exists("TYPE", $arFields))
1502 {
1503 $arFields["TYPE"] = (int)$arFields["TYPE"];
1504 if ($arFields["TYPE"] != CSaleBasket::TYPE_SET)
1505 unset($arFields["TYPE"]);
1506 }
1507
1508 if (array_key_exists('~TYPE', $arFields))
1509 {
1510 unset($arFields['~TYPE']);
1511 }
1512
1513 if (array_key_exists('CATALOG_XML_ID', $arFields))
1514 {
1515 $arFields['CATALOG_XML_ID'] = (string)$arFields['CATALOG_XML_ID'];
1516 if ($arFields['CATALOG_XML_ID'] === '')
1517 {
1518 unset($arFields['CATALOG_XML_ID']);
1519
1520 if (array_key_exists('~CATALOG_XML_ID', $arFields))
1521 {
1522 unset($arFields['~CATALOG_XML_ID']);
1523 }
1524 }
1525 }
1526
1527 if (array_key_exists('PROPS', $arFields))
1528 {
1529 if (empty($arFields['PROPS']) || !is_array($arFields['PROPS']))
1530 {
1531 unset($arFields['PROPS']);
1532 }
1533 else
1534 {
1535 $clearPropList = array();
1536 foreach ($arFields['PROPS'] as $basketProperty)
1537 {
1538 if (empty($basketProperty) || !is_array($basketProperty) || !isset($basketProperty['NAME']))
1539 continue;
1540 $basketProperty['NAME'] = (string)$basketProperty['NAME'];
1541 if ($basketProperty['NAME'] == '')
1542 continue;
1543 $propCode = (isset($basketProperty['CODE']) ? (string)$basketProperty['CODE'] : '');
1544 $propValue = (isset($basketProperty['VALUE']) ? (string)$basketProperty['VALUE'] : '');
1545 $clearProp = array(
1546 'NAME' => $basketProperty['NAME'],
1547 'SORT' => (isset($basketProperty['SORT']) ? (int)$basketProperty['SORT'] : 100)
1548 );
1549 if ($propCode != '')
1550 $clearProp['CODE'] = $propCode;
1551 if ($propValue != '')
1552 $clearProp['VALUE'] = $propValue;
1553 $clearPropList[] = $clearProp;
1554 unset($clearProp, $propValue, $propCode);
1555 }
1556 unset($basketProperty);
1557 if (!empty($clearPropList))
1558 $arFields['PROPS'] = $clearPropList;
1559 else
1560 unset($arFields['PROPS']);
1561 unset($clearPropList);
1562 }
1563 }
1564
1565 return true;
1566 }
1567
1568 public static function _Update($ID, &$arFields)
1569 {
1570 global $DB;
1571
1572 $ID = (int)$ID;
1573 //CSaleBasket::Init();
1574
1575 if (!CSaleBasket::CheckFields("UPDATE", $arFields, $ID))
1576 return false;
1577
1578 foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $arEvent)
1579 if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields))===false)
1580 return false;
1581
1582 $arOldFields = false;
1583 $updateHistory = isset($arFields["ORDER_ID"]) && (int)$arFields["ORDER_ID"] > 0;
1584
1585 $strUpdate = $DB->PrepareUpdate("b_sale_basket", $arFields);
1586 if (!empty($strUpdate))
1587 {
1588 if ($updateHistory)
1589 {
1590 $oldOrderIterator = CSaleBasket::GetList(
1591 array(),
1592 array('ID' => $ID),
1593 false,
1594 false,
1595 array_keys($arFields)
1596 );
1597 $arOldFields = $oldOrderIterator->Fetch();
1598 }
1599
1600 $strSql = "update b_sale_basket set ".$strUpdate.", DATE_UPDATE = ".$DB->GetNowFunction()." where ID = ".$ID;
1601 $DB->Query($strSql);
1602 }
1603 else
1604 {
1605 $updateHistory = false;
1606 }
1607
1608 if (isset($arFields["PROPS"]) && !empty($arFields["PROPS"]) && is_array($arFields["PROPS"]))
1609 {
1610 $sql = "delete from b_sale_basket_props where BASKET_ID = ".$ID;
1611
1612 $bProductXml = false;
1613 $bCatalogXml = false;
1614 foreach($arFields["PROPS"] as $prop)
1615 {
1616 if (!isset($prop['CODE']))
1617 continue;
1618 if ($prop["CODE"] == "PRODUCT.XML_ID")
1619 $bProductXml = true;
1620
1621 if ($prop["CODE"] == "CATALOG.XML_ID")
1622 $bCatalogXml = true;
1623
1624 if ($bProductXml && $bCatalogXml)
1625 break;
1626 }
1627 if (!$bProductXml)
1628 $sql .= " and CODE <> 'PRODUCT.XML_ID'";
1629 if (!$bCatalogXml)
1630 $sql .= " and CODE <> 'CATALOG.XML_ID'";
1631 $DB->Query($sql);
1632 if (!$bProductXml || !$bCatalogXml)
1633 {
1634 $sql = "delete from b_sale_basket_props where BASKET_ID = ".$ID." and CODE IS NULL";
1635 $DB->Query($sql);
1636 }
1637
1638 foreach($arFields["PROPS"] as $prop)
1639 {
1640 if (!isset($prop["NAME"]))
1641 continue;
1642 $prop["NAME"] = (string)$prop["NAME"];
1643 if($prop["NAME"] != '')
1644 {
1645 $arInsert = $DB->PrepareInsert("b_sale_basket_props", $prop);
1646 $strSql = "INSERT INTO b_sale_basket_props(BASKET_ID, ".$arInsert[0].") VALUES(".$ID.", ".$arInsert[1].")";
1647 $DB->Query($strSql);
1648 }
1649 }
1650 }
1651
1652 if ($updateHistory)
1653 CSaleOrderChange::AddRecordsByFields($arFields["ORDER_ID"], $arOldFields, $arFields, array('PROPS'), "BASKET");
1654
1655 foreach(GetModuleEvents("sale", "OnBasketUpdate", true) as $arEvent)
1656 ExecuteModuleEventEx($arEvent, Array($ID, $arFields));
1657
1658 return true;
1659 }
1660
1661 public static function Update($ID, $arFields)
1662 {
1663 global $APPLICATION;
1664
1665 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
1666
1667 if (isset($arFields["ID"]))
1668 unset($arFields["ID"]);
1669
1670 $ID = (int)$ID;
1672
1673 if ($isOrderConverted == 'N')
1674 {
1675 foreach(GetModuleEvents("sale", "OnBeforeBasketUpdate", true) as $arEvent)
1676 if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields))===false)
1677 return false;
1678 }
1679
1680 if (is_set($arFields, "QUANTITY") && floatval($arFields["QUANTITY"])<=0)
1681 {
1682 return CSaleBasket::Delete($ID);
1683 }
1684 else
1685 {
1686
1687 if ($isOrderConverted != 'N')
1688 {
1689 foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $event)
1690 {
1691 if (ExecuteModuleEventEx($event, array($ID, &$arFields)) === false)
1692 {
1693 return false;
1694 }
1695 }
1696
1698 $r = \Bitrix\Sale\Compatible\BasketCompatibility::update($ID, $arFields);
1699 if (!$r->isSuccess())
1700 {
1701 foreach($r->getErrorMessages() as $error)
1702 {
1703 $APPLICATION->ThrowException($error);
1704 }
1705
1706 return false;
1707 }
1708 return true;
1709 }
1710 else
1711 {
1712 if (is_set($arFields, "QUANTITY")) // if quantity updated and is set parent item, update all set items' quantity
1713 {
1714 $arBasket = $arFields;
1715 $oldQuantity = false;
1716 if (!isset($arBasket['TYPE']) || !isset($arBasket['SET_PARENT_ID']))
1717 {
1718 $basketIterator = CSaleBasket::GetList(
1719 array(),
1720 array('ID' => $ID),
1721 false,
1722 false,
1723 array('ID', 'TYPE', 'SET_PARENT_ID', 'QUANTITY')
1724 );
1725 if (!($basket = $basketIterator->Fetch()))
1726 return false;
1727 $arBasket['TYPE'] = (int)$basket['TYPE'];
1728 $arBasket['SET_PARENT_ID'] = (int)$basket['SET_PARENT_ID'];
1729 $arBasket['QUANTITY'] = $basket['QUANTITY'];
1730 $oldQuantity = $basket['QUANTITY'];
1731 unset($basket, $basketIterator);
1732 }
1733 if (CSaleBasketHelper::isSetParent($arBasket))
1734 {
1735 if ($oldQuantity === false)
1736 {
1737 $basketIterator = CSaleBasket::GetList(
1738 array(),
1739 array('ID' => $ID),
1740 false,
1741 false,
1742 array('ID', 'QUANTITY')
1743 );
1744 if (!($basket = $basketIterator->Fetch()))
1745 return false;
1746 $arBasket['QUANTITY'] = $basket['QUANTITY'];
1747 $oldQuantity = $basket['QUANTITY'];
1748 unset($basket, $basketIterator);
1749 }
1750 if ($oldQuantity != $arFields['QUANTITY'])
1751 {
1752 $dbSetItems = CSaleBasket::GetList(
1753 array(),
1754 array("SET_PARENT_ID" => $ID, 'TYPE' => false),
1755 false,
1756 false,
1757 array('ID', 'QUANTITY', 'SET_PARENT_ID', 'TYPE')
1758 );
1759 while ($arItem = $dbSetItems->Fetch())
1760 {
1761 $newQuantity = $arItem['QUANTITY'] / $arBasket['QUANTITY'] * $arFields['QUANTITY'];
1762 CSaleBasket::Update(
1763 $arItem['ID'],
1764 array('QUANTITY' => $newQuantity, 'SET_PARENT_ID' => (int)$arItem['SET_PARENT_ID'], 'TYPE' => (int)$arItem['TYPE'])
1765 );
1766 }
1767 unset($arItem, $dbSetItems);
1768 }
1769 }
1770 }
1771
1773 }
1774 }
1775 }
1776
1777
1778 //************** BASKET USER ********************//
1779 public static function Init($bVar = false, $bSkipFUserInit = false)
1780 {
1781 $bSkipFUserInit = ($bSkipFUserInit !== false);
1782
1783 if (Sale\Fuser::refreshSessionCurrentId() === null)
1784 {
1785 Sale\Fuser::getId($bSkipFUserInit);
1786 }
1787 }
1788
1796 public static function GetBasketUserID($bSkipFUserInit = false)
1797 {
1798 $bSkipFUserInit = ($bSkipFUserInit !== false);
1799
1800 return (int)Sale\Fuser::getId($bSkipFUserInit);
1801 }
1802
1803
1804 //************** SELECT ********************//
1805 public static function GetByID($ID)
1806 {
1807 global $DB;
1808
1809 $ID = (int)$ID;
1810 if ($ID <= 0)
1811 return false;
1812 $strSql = "SELECT * FROM b_sale_basket WHERE ID = ".$ID;
1813 $dbBasket = $DB->Query($strSql);
1814
1815 if ($arBasket = $dbBasket->Fetch())
1816 return $arBasket;
1817
1818 return false;
1819 }
1820
1821 //************** CALLBACK FUNCTIONS ********************//
1822 public static function ExecuteCallbackFunction($callbackFunc = "", $module = "", $productID = 0)
1823 {
1824 $callbackFunc = trim((string)$callbackFunc);
1825 $module = trim((string)$module);
1826 $productID = intval($productID);
1827
1828 $result = False;
1829
1830 if ($callbackFunc <> '')
1831 {
1832 if ($module <> '' && $module != "main")
1833 CModule::IncludeModule($module);
1834
1835 $arArgs = array($productID);
1836 $numArgs = func_num_args();
1837 if ($numArgs > 3)
1838 for ($i = 3; $i < $numArgs; $i++)
1839 $arArgs[] = func_get_arg($i);
1840
1841 $result = call_user_func_array($callbackFunc, $arArgs);
1842 }
1843
1844 return $result;
1845
1846 /*
1847 $callbackFunc = trim($callbackFunc);
1848 $productID = IntVal($productID);
1849 $module = Trim($module);
1850 $quantity = IntVal($quantity);
1851
1852 $result = False;
1853 if (strlen($callbackFunc) > 0)
1854 {
1855 if (strlen($module)>0 && $module != "main")
1856 CModule::IncludeModule($module);
1857
1858 $result = $callbackFunc($PRODUCT_ID, $QUANTITY, $arParams);
1859 }
1860 return $result;
1861 */
1862 }
1863
1864 public static function ReReadPrice($callbackFunc = "", $module = "", $productID = 0, $quantity = 0, $renewal = "N", $productProvider = "")
1865 {
1866 if (CSaleBasket::GetProductProvider(array("MODULE" => $module, "PRODUCT_PROVIDER_CLASS" => $productProvider)))
1867 {
1868 return $productProvider::GetProductData(array(
1869 "PRODUCT_ID" => $productID,
1870 "QUANTITY" => $quantity,
1871 "RENEWAL" => $renewal
1872 ));
1873 }
1874 else
1875 return CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity, $renewal);
1876 }
1877
1878 public static function OnOrderProduct($callbackFunc = "", $module = "", $productID = 0, $quantity = 0, $productProvider = "")
1879 {
1880 if (CSaleBasket::GetProductProvider(array("MODULE" => $module, "PRODUCT_PROVIDER_CLASS" => $productProvider)))
1881 {
1882 $productProvider::GetProductData(array(
1883 "PRODUCT_ID" => $productID,
1884 "QUANTITY" => $quantity
1885 ));
1886 }
1887 else
1888 CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity);
1889
1890 return True;
1891 }
1892
1893 public static function UpdatePrice($ID, $callbackFunc = '', $module = '', $productID = 0, $quantity = 0, $renewal = 'N', $productProvider = '', $notes = '')
1894 {
1895 $ID = (int)$ID;
1896 if ($ID <= 0)
1897 return;
1898 $callbackFunc = trim((string)$callbackFunc);
1899 $productID = (int)$productID;
1900 $module = trim((string)$module);
1901 $quantity = (float)$quantity;
1902 $renewal = ((string)$renewal == 'Y' ? 'Y' : 'N');
1903 $productProvider = trim((string)$productProvider);
1904 $notes = trim((string)$notes);
1905 $getQuantity = false;
1906
1907 $select = array();
1908 if ($callbackFunc == '' && $productProvider == '')
1909 {
1910 $getQuantity = true;
1911 $select['CALLBACK_FUNC'] = true;
1912 $select['PRODUCT_PROVIDER_CLASS'] = true;
1913 }
1914 if ($productID <= 0)
1915 {
1916 $getQuantity = true;
1917 $select['PRODUCT_ID'] = true;
1918 }
1919 if ($notes == '')
1920 $select['NOTES'] = true;
1921 if ($getQuantity)
1922 {
1923 $select['QUANTITY'] = true;
1924 $select['MODULE'] = true;
1925 }
1926 unset($getQuantity);
1927
1928 if (!empty($select))
1929 {
1930 $basketIterator = CSaleBasket::GetList(
1931 array(),
1932 array('ID' => $ID),
1933 false,
1934 false,
1935 array_keys($select)
1936 );
1937 $basket = $basketIterator->Fetch();
1938 if (empty($basket))
1939 return;
1940 if (isset($select['CALLBACK_FUNC']))
1941 $callbackFunc = trim((string)$basket['CALLBACK_FUNC']);
1942 if (isset($select['PRODUCT_PROVIDER_CLASS']))
1943 $productProvider = trim((string)$basket['PRODUCT_PROVIDER_CLASS']);
1944 if (isset($select['MODULE']))
1945 $module = trim((string)$basket['MODULE']);
1946 if (isset($select['PRODUCT_ID']))
1947 $productID = (int)$basket['PRODUCT_ID'];
1948 if (isset($select['QUANTITY']))
1949 $quantity = (float)$basket['QUANTITY'];
1950 if (isset($select['NOTES']))
1951 $notes = $basket['NOTES'];
1952 unset($basket, $basketIterator);
1953 }
1954
1955 $providerName = CSaleBasket::GetProductProvider([
1956 "MODULE" => $module,
1957 "PRODUCT_PROVIDER_CLASS" => $productProvider,
1958 ]);
1959 if ($providerName)
1960 {
1961 $arFields = $providerName::GetProductData([
1962 "PRODUCT_ID" => $productID,
1963 "QUANTITY" => $quantity,
1964 "RENEWAL" => $renewal,
1965 "BASKET_ID" => $ID,
1966 "NOTES" => $notes,
1967 ]);
1968 }
1969 else
1970 {
1971 $arFields = CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity, $renewal);
1972 }
1973
1974 if (!empty($arFields) && is_array($arFields))
1975 {
1976 $arFields["CAN_BUY"] = "Y";
1977 CSaleBasket::Update($ID, $arFields);
1978 }
1979 else
1980 {
1981 $arFields = array(
1982 "CAN_BUY" => "N"
1983 );
1984 CSaleBasket::Update($ID, $arFields);
1985 }
1986 }
1987
1999 public static function OrderBasket($orderID, $fuserID = 0, $strLang = SITE_ID, $arDiscounts = False)
2000 {
2001 $orderID = (int)$orderID;
2002 if ($orderID <= 0)
2003 return false;
2004
2005 $fuserID = (int)$fuserID;
2006 if ($fuserID <= 0)
2007 $fuserID = (int)CSaleBasket::GetBasketUserID(true);
2008 if ($fuserID <= 0)
2009 return false;
2010
2011 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
2012
2013 $arOrder = array();
2014
2015 if (empty($arOrder))
2016 {
2017 $rsOrders = CSaleOrder::GetList(
2018 array(),
2019 array('ID' => $orderID),
2020 false,
2021 false,
2022 array('ID', 'USER_ID', 'RECURRING_ID', 'LID', 'RESERVED')
2023 );
2024 if (!($arOrder = $rsOrders->Fetch()))
2025 return false;
2026 $arOrder['RECURRING_ID'] = (int)$arOrder['RECURRING_ID'];
2027 }
2028 $boolRecurring = $arOrder['RECURRING_ID'] > 0;
2029
2030 $found = false;
2031 $dbBasketList = CSaleBasket::GetList(
2032 array("PRICE" => "DESC"),
2033 array("FUSER_ID" => $fuserID, "LID" => $strLang, "ORDER_ID" => 0),
2034 false,
2035 false,
2036 array(
2037 'ID', 'ORDER_ID', 'PRODUCT_ID', 'MODULE',
2038 'CAN_BUY', 'DELAY', 'ORDER_CALLBACK_FUNC', 'PRODUCT_PROVIDER_CLASS',
2039 'QUANTITY', 'CUSTOM_PRICE'
2040 )
2041 );
2042 while ($arBasket = $dbBasketList->Fetch())
2043 {
2044 $arFields = array();
2045 if ($arBasket["DELAY"] == "N" && $arBasket["CAN_BUY"] == "Y")
2046 {
2047 if (!empty($arBasket["ORDER_CALLBACK_FUNC"]) || !empty($arBasket["PRODUCT_PROVIDER_CLASS"]))
2048 {
2050 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2051 {
2052 $arQuery = array(
2053 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2054 "QUANTITY" => $arBasket["QUANTITY"],
2055 'BASKET_ID' => $arBasket['ID']
2056 );
2057 if ($boolRecurring)
2058 {
2059 $arQuery['RENEWAL'] = 'Y';
2060 $arQuery['USER_ID'] = $arOrder['USER_ID'];
2061 $arQuery['SITE_ID'] = $strLang;
2062 }
2063 $arFields = $productProvider::OrderProduct($arQuery);
2064 }
2065 else
2066 {
2067 if ($boolRecurring)
2068 {
2070 $arBasket["ORDER_CALLBACK_FUNC"],
2071 $arBasket["MODULE"],
2072 $arBasket["PRODUCT_ID"],
2073 $arBasket["QUANTITY"],
2074 'Y',
2075 $arOrder['USER_ID'],
2076 $strLang
2077 );
2078 }
2079 else
2080 {
2082 $arBasket["ORDER_CALLBACK_FUNC"],
2083 $arBasket["MODULE"],
2084 $arBasket["PRODUCT_ID"],
2085 $arBasket["QUANTITY"]
2086 );
2087 }
2088 }
2089
2090 if (!empty($arFields) && is_array($arFields))
2091 {
2092 $arFields["CAN_BUY"] = "Y";
2093 $arFields["ORDER_ID"] = $orderID;
2094 $arBasket['CUSTOM_PRICE'] = (string)$arBasket['CUSTOM_PRICE'];
2095 if ($arBasket['CUSTOM_PRICE'] == 'Y')
2096 {
2097 if (array_key_exists('PRICE', $arFields))
2098 unset($arFields['PRICE']);
2099 if (array_key_exists('DISCOUNT_PRICE', $arFields))
2100 unset($arFields['DISCOUNT_PRICE']);
2101 if (array_key_exists('CURRENCY', $arFields))
2102 unset($arFields['CURRENCY']);
2103 if (array_key_exists('DISCOUNT_VALUE', $arFields))
2104 unset($arFields['DISCOUNT_VALUE']);
2105 if (array_key_exists('DISCOUNT_NAME', $arFields))
2106 unset($arFields['DISCOUNT_NAME']);
2107 if (array_key_exists('DISCOUNT_COUPON', $arFields))
2108 unset($arFields['DISCOUNT_COUPON']);
2109 if (array_key_exists('DISCOUNT_LIST', $arFields))
2110 unset($arFields['DISCOUNT_LIST']);
2111 if (array_key_exists('DISCOUNT', $arFields))
2112 unset($arFields['DISCOUNT']);
2113 }
2114 }
2115 else
2116 {
2117 $arFields = array(
2118 'CAN_BUY' => 'N'
2119 );
2120 $removeCoupon = DiscountCouponsManager::deleteApplyByProduct(array(
2121 'MODULE' => $arBasket['MODULE'],
2122 'PRODUCT_ID' => $arBasket['PRODUCT_ID'],
2123 'BASKET_ID' => $arBasket['ID']
2124 ));
2125 }
2126 }
2127 else
2128 {
2129 $arFields["ORDER_ID"] = $orderID;
2130 }
2131
2132 if (!empty($arFields))
2133 {
2134 if ($isOrderConverted != 'N')
2135 {
2136 $found = true;
2137 if (!\Bitrix\Sale\Compatible\DiscountCompatibility::isInited())
2138 \Bitrix\Sale\Compatible\DiscountCompatibility::init();
2139 if (\Bitrix\Sale\Compatible\DiscountCompatibility::isInited())
2140 \Bitrix\Sale\Compatible\DiscountCompatibility::setRepeatSave(true);
2141 }
2142 CSaleBasket::Update($arBasket["ID"], $arFields);
2143 }
2144 }
2145 }//end of while
2146
2147 foreach(GetModuleEvents("sale", "OnBasketOrder", true) as $arEvent)
2148 {
2149 ExecuteModuleEventEx($arEvent, array($orderID, $fuserID, $strLang, $arDiscounts));
2150 }
2151
2152 if ($isOrderConverted != 'N' && $found)
2153 {
2154 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
2155
2157 $orderClass = $registry->getOrderClassName();
2158
2159 if ($order = $orderClass::load($orderID))
2160 {
2161 if (\Bitrix\Sale\Compatible\DiscountCompatibility::isInited())
2162 \Bitrix\Sale\Compatible\DiscountCompatibility::setRepeatSave(false);
2163 $discounts = $order->getDiscount();
2164 $discounts->save();
2165 unset($discounts);
2166 }
2167 unset($order);
2168 }
2169 //reservation
2170 if ($arOrder['RESERVED'] != "Y" && COption::GetOptionString("sale", "product_reserve_condition") == "O")
2171 {
2172 if (!CSaleOrder::ReserveOrder($orderID, "Y"))
2173 return false;
2174 }
2175 return true;
2176 }
2177
2178 public static function OrderPayment($orderID, $bPaid, $recurringID = 0)
2179 {
2180 CSaleBasket::OrderDelivery($orderID, $bPaid, $recurringID);
2181 }
2182
2183 public static function OrderDelivery($orderID, $bPaid, $recurringID = 0)
2184 {
2185 global $DB, $APPLICATION;
2186
2187 $orderID = intval($orderID);
2188 if ($orderID <= 0)
2189 return False;
2190
2191 $bPaid = ($bPaid ? True : False);
2192
2193 $recurringID = intval($recurringID);
2194
2195 $arOrder = CSaleOrder::GetByID($orderID);
2196 if ($arOrder)
2197 {
2198 $dbBasketList = CSaleBasket::GetList(
2199 array("NAME" => "ASC"),
2200 array("ORDER_ID" => $orderID)
2201 );
2202
2203 while ($arBasket = $dbBasketList->Fetch())
2204 {
2205 if ($arBasket["PAY_CALLBACK_FUNC"] <> '' || $arBasket["PRODUCT_PROVIDER_CLASS"] <> '')
2206 {
2207 if ($bPaid)
2208 {
2210 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2211 {
2212 $arFields = $productProvider::DeliverProduct(array(
2213 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2214 "USER_ID" => $arOrder["USER_ID"],
2215 "PAID" => $bPaid,
2216 "ORDER_ID" => $orderID,
2217 'BASKET_ID' => $arBasket['ID']
2218 ));
2219 }
2220 else
2221 {
2223 $arBasket["PAY_CALLBACK_FUNC"],
2224 $arBasket["MODULE"],
2225 $arBasket["PRODUCT_ID"],
2226 $arOrder["USER_ID"],
2227 $bPaid,
2228 $orderID,
2229 $arBasket["QUANTITY"]
2230 );
2231 }
2232
2233 if ($arFields && is_array($arFields) && count($arFields) > 0)
2234 {
2235 $arFields["ORDER_ID"] = $orderID;
2236 $arFields["REMAINING_ATTEMPTS"] = (Defined("SALE_PROC_REC_ATTEMPTS") ? SALE_PROC_REC_ATTEMPTS : 3);
2237 $arFields["SUCCESS_PAYMENT"] = "Y";
2238
2239 if ($recurringID > 0)
2240 CSaleRecurring::Update($recurringID, $arFields);
2241 else
2243 }
2244 elseif ($recurringID > 0)
2245 {
2246 CSaleRecurring::Delete($recurringID);
2247 }
2248 }
2249 else
2250 {
2252 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2253 {
2254 $productProvider::DeliverProduct(array(
2255 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2256 "USER_ID" => $arOrder["USER_ID"],
2257 "PAID" => $bPaid,
2258 "ORDER_ID" => $orderID,
2259 'BASKET_ID' => $arBasket['ID']
2260 ));
2261 }
2262 else
2263 {
2265 $arBasket["PAY_CALLBACK_FUNC"],
2266 $arBasket["MODULE"],
2267 $arBasket["PRODUCT_ID"],
2268 $arOrder["USER_ID"],
2269 $bPaid,
2270 $orderID,
2271 $arBasket["QUANTITY"]
2272 );
2273 }
2274
2275 $dbRecur = CSaleRecurring::GetList(
2276 array(),
2277 array(
2278 "USER_ID" => $arOrder["USER_ID"],
2279 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2280 "MODULE" => $arBasket["MODULE"]
2281 )
2282 );
2283 while ($arRecur = $dbRecur->Fetch())
2284 {
2285 CSaleRecurring::Delete($arRecur["ID"]);
2286 }
2287 }
2288 }
2289 }
2290 }
2291 }
2292
2293 public static function OrderCanceled($orderID, $bCancel)
2294 {
2295 global $DB;
2296
2297 $orderID = intval($orderID);
2298 if ($orderID <= 0)
2299 return False;
2300
2301 $bCancel = (bool)$bCancel;
2302
2303 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
2304
2305 if ($isOrderConverted != 'N')
2306 {
2307 \Bitrix\Sale\Compatible\OrderCompatibility::cancel($orderID, $bCancel?'Y':'N');
2308 }
2309 else
2310 {
2311 $arOrder = CSaleOrder::GetByID($orderID);
2312 if ($arOrder)
2313 {
2314 $dbBasketList = CSaleBasket::GetList(
2315 array("NAME" => "ASC"),
2316 array("ORDER_ID" => $orderID)
2317 );
2318 while ($arBasket = $dbBasketList->Fetch())
2319 {
2320 if ($arBasket["CANCEL_CALLBACK_FUNC"] <> '' && $arBasket["PRODUCT_PROVIDER_CLASS"] == '')
2321 {
2323 $arBasket["CANCEL_CALLBACK_FUNC"],
2324 $arBasket["MODULE"],
2325 $arBasket["PRODUCT_ID"],
2326 $arBasket["QUANTITY"],
2327 $bCancel
2328 );
2329 }
2330 }
2331 }
2332 }
2333 }
2334
2342 public static function OrderReservation($orderID, $bUndoReservation = false)
2343 {
2344 global $APPLICATION;
2345
2346 if (defined("SALE_DEBUG") && SALE_DEBUG)
2347 {
2348 if ($bUndoReservation)
2349 CSaleHelper::WriteToLog("OrderReservation: undo started", array("orderId" => $orderID), "OR1");
2350 else
2351 CSaleHelper::WriteToLog("OrderReservation: started", array("orderId" => $orderID), "OR1");
2352 }
2353
2354 $orderID = (int)$orderID;
2355 if ($orderID <= 0)
2356 return false;
2357
2358 $arResult = array();
2359 $arSetData = array();
2360
2361 $arOrder = CSaleOrder::GetByID($orderID);
2362 if ($arOrder)
2363 {
2364 $obStackExp = $APPLICATION->GetException();
2365 if (is_object($obStackExp))
2366 {
2367 $APPLICATION->ResetException();
2368 }
2369
2370 $dbBasketList = CSaleBasket::GetList(
2371 array(),
2372 array("ORDER_ID" => $orderID)
2373 );
2374 while ($arBasket = $dbBasketList->Fetch())
2375 {
2376 if ($bUndoReservation && $arBasket["RESERVED"] == "N" && COption::GetOptionString("catalog", "enable_reservation") != "N")
2377 continue;
2378
2379 if (CSaleBasketHelper::isSetParent($arBasket))
2380 continue;
2381
2382 if (CSaleBasketHelper::isSetItem($arBasket))
2383 $arSetData[$arBasket["PRODUCT_ID"]] = $arBasket["SET_PARENT_ID"];
2384
2385 if (defined("SALE_DEBUG") && SALE_DEBUG)
2386 CSaleHelper::WriteToLog("Reserving product #".$arBasket["PRODUCT_ID"], array(), "OR2");
2387
2389 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2390 {
2391 if (defined("SALE_DEBUG") && SALE_DEBUG)
2392 {
2394 "Call ::ReserveProduct",
2395 array(
2396 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2397 "QUANTITY_ADD" => $arBasket["QUANTITY"],
2398 "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N"
2399 ),
2400 "OR3"
2401 );
2402 }
2403
2404 if ($arOrder["DEDUCTED"] == "Y") // order already deducted, don't reserve it
2405 {
2406 $res = array("RESULT" => true, "QUANTITY_RESERVED" => 0);
2407
2408 if (defined("SALE_DEBUG") && SALE_DEBUG)
2409 CSaleHelper::WriteToLog("Order already deducted. Product won't be reserved.", array(), "OR5");
2410 }
2411 else
2412 {
2413 $res = $productProvider::ReserveProduct(array(
2414 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2415 "QUANTITY_ADD" => $arBasket["QUANTITY"],
2416 "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N",
2417 ));
2418 }
2419
2420 if ($res["RESULT"])
2421 {
2422 $arResult[$arBasket["PRODUCT_ID"]] = $res["QUANTITY_RESERVED"];
2423
2424 $arUpdateFields = array("RESERVED" => ($bUndoReservation) ? "N" : "Y");
2425
2426 if (!$bUndoReservation && isset($res["QUANTITY_NOT_RESERVED"]))
2427 $arUpdateFields["RESERVE_QUANTITY"] = $res["QUANTITY_NOT_RESERVED"];
2428
2429 if (defined("SALE_DEBUG") && SALE_DEBUG)
2430 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reserved successfully", array("arUpdateFields" => $arUpdateFields), "OR4");
2431
2432 if (!isset($res["QUANTITY_RESERVED"]) || (isset($res["QUANTITY_RESERVED"]) && $res["QUANTITY_RESERVED"] != 0))
2433 CSaleBasket::Update($arBasket["ID"], $arUpdateFields);
2434 }
2435 else
2436 {
2437 if (defined("SALE_DEBUG") && SALE_DEBUG)
2438 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reservation error", array(), "OR4");
2439
2440 CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "N"));
2441 }
2442
2443 if ($ex = $APPLICATION->GetException())
2444 {
2445 if (defined("SALE_DEBUG") && SALE_DEBUG)
2446 {
2448 "Call ::ReserveProduct - Exception",
2449 array(
2450 "ID" => $arBasket["PRODUCT_ID"],
2451 "MESSAGE" => $ex->GetString(),
2452 "CODE" => $ex->GetID(),
2453 ),
2454 "OR4"
2455 );
2456 }
2457
2458 $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["ID"] = $arBasket["PRODUCT_ID"];
2459 $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["MESSAGE"] = $ex->GetString();
2460 $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["CODE"] = $ex->GetID();
2461 }
2462 }
2463 }
2464 if (is_object($obStackExp))
2465 {
2466 $APPLICATION->ResetException();
2467 $APPLICATION->ThrowException($obStackExp);
2468 }
2469 }
2470
2471 if (defined("SALE_DEBUG") && SALE_DEBUG)
2472 CSaleHelper::WriteToLog("OrderReservation result", array("arResult" => $arResult), "OR6");
2473
2474 return $arResult;
2475 }
2476
2486 public static function ReserveBasketProduct($basketID, $deltaQuantity, $isOrderDeducted = false)
2487 {
2488 global $APPLICATION;
2489
2490 if (defined("SALE_DEBUG") && SALE_DEBUG)
2491 {
2493 "ReserveBasketProduct: reserving product #".$basketID,
2494 array(
2495 "basketId" => $basketID,
2496 "deltaQuantity" => $deltaQuantity
2497 ),
2498 "RBP1"
2499 );
2500 }
2501
2502 $arResult = array();
2503
2504 $basketID = (int)$basketID;
2505 if ($basketID <= 0)
2506 {
2507 $arResult["RESULT"] = false;
2508 return $arResult;
2509 }
2510
2511 $deltaQuantity = (float)$deltaQuantity;
2512 if ($deltaQuantity < 0)
2513 {
2514 $deltaQuantity = abs($deltaQuantity);
2515 $bUndoReservation = true;
2516 }
2517 else
2518 {
2519 $bUndoReservation = false;
2520 }
2521
2522 $arBasket = CSaleBasket::GetByID($basketID);
2523
2524 if ($arBasket)
2525 {
2527 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2528 {
2529 if (defined("SALE_DEBUG") && SALE_DEBUG)
2530 {
2532 "Call ::ReserveProduct",
2533 array(
2534 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2535 "QUANTITY_ADD" => $deltaQuantity,
2536 "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N",
2537 "ORDER_DEDUCTED" => ($isOrderDeducted) ? "Y" : "N"
2538 ),
2539 "RBP2"
2540 );
2541 }
2542
2543 $res = $productProvider::ReserveProduct(array(
2544 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2545 "QUANTITY_ADD" => $deltaQuantity,
2546 "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N",
2547 "ORDER_DEDUCTED" => ($isOrderDeducted) ? "Y" : "N"
2548 ));
2549
2550 $updateResult = true;
2551 $arResult["RESULT"] = $res["RESULT"];
2552 if ($res["RESULT"])
2553 {
2554 $arResult[$arBasket["ID"]] = $res["QUANTITY_RESERVED"];
2555
2556 if (defined("SALE_DEBUG") && SALE_DEBUG)
2557 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reserved successfully", array(), "RBP3");
2558
2559 if ($bUndoReservation)
2560 {
2561 $updateResult = CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "N"));
2562 }
2563 elseif (!isset($res["QUANTITY_RESERVED"]) || (isset($res["QUANTITY_RESERVED"]) && $res["QUANTITY_RESERVED"] != 0))
2564 {
2565 $updateResult = CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "Y"));
2566 }
2567 }
2568 else
2569 {
2570 $arResult["ERROR"]["PRODUCT_ID"] = $arBasket["PRODUCT_ID"];
2571 $updateResult = false;
2572
2573 if (defined("SALE_DEBUG") && SALE_DEBUG)
2574 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reservation error", array(), "RBP3");
2575
2576 if (isset($res["QUANTITY_NOT_RESERVED"]))
2577 {
2578 CSaleBasket::Update($arBasket["ID"], array("RESERVE_QUANTITY" => $res["QUANTITY_NOT_RESERVED"]));
2579 }
2580 }
2581
2582 if (!$updateResult && $ex = $APPLICATION->GetException())
2583 {
2584 $arResult["ERROR"]["MESSAGE"] = $ex->GetString();
2585 $arResult["ERROR"]["CODE"] = $ex->GetID();
2586 }
2587 }
2588 }
2589
2590 if (defined("SALE_DEBUG") && SALE_DEBUG)
2591 CSaleHelper::WriteToLog("ReserveBasketProduct result", array("arResult" => $arResult), "RBP5");
2592
2593 return $arResult;
2594 }
2595
2605 public static function DeductBasketProduct($basketID, $deltaQuantity, $arStoreBarcodeData = array())
2606 {
2607 if (defined("SALE_DEBUG") && SALE_DEBUG)
2608 {
2609 CSaleHelper::WriteToLog("DeductBasketProduct",
2610 array(
2611 "basketId" => $basketID,
2612 "deltaQuantity" => $deltaQuantity,
2613 "storeBarcodeData" => $arStoreBarcodeData
2614 ),
2615 "DBP1"
2616 );
2617 }
2618
2619 global $APPLICATION;
2620 $arResult = array();
2621
2622 $basketID = (int)$basketID;
2623 if ($basketID <= 0)
2624 {
2625 $arResult["RESULT"] = false;
2626 return $arResult;
2627 }
2628
2629 $deltaQuantity = (float)$deltaQuantity;
2630 if ($deltaQuantity < 0)
2631 {
2632 $deltaQuantity = abs($deltaQuantity);
2633 $bUndoDeduction = true;
2634 }
2635 else
2636 {
2637 $bUndoDeduction = false;
2638 }
2639
2640 $arBasket = CSaleBasket::GetByID($basketID);
2641 if ($arBasket)
2642 {
2644 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2645 {
2646 if (defined("SALE_DEBUG") && SALE_DEBUG)
2647 {
2649 "Call ::DeductProduct",
2650 array(
2651 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2652 "QUANTITY" => (empty($arStoreBarcodeData)) ? $deltaQuantity : 0,
2653 "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N",
2654 "EMULATE" => "N",
2655 "PRODUCT_RESERVED" => $arBasket["RESERVED"],
2656 "STORE_DATA" => $arStoreBarcodeData
2657 ),
2658 "DBP2"
2659 );
2660 }
2661
2662 if ($bUndoDeduction)
2663 {
2664 $dbStoreBarcode = CSaleStoreBarcode::GetList(
2665 array(),
2666 array("BASKET_ID" => $arBasket["ID"]),
2667 false,
2668 false,
2669 array("ID", "BASKET_ID", "BARCODE", "QUANTITY", "STORE_ID")
2670 );
2671 while ($arRes = $dbStoreBarcode->GetNext())
2672 $arStoreBarcodeData[] = $arRes;
2673 }
2674
2675 $res = $productProvider::DeductProduct(array(
2676 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2677 "QUANTITY" => (empty($arStoreBarcodeData)) ? $deltaQuantity : 0,
2678 "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N",
2679 "EMULATE" => "N",
2680 "PRODUCT_RESERVED" => $arBasket["RESERVED"],
2681 "STORE_DATA" => $arStoreBarcodeData
2682 ));
2683
2684 $arResult["RESULT"] = $res["RESULT"];
2685
2686 if ($res["RESULT"])
2687 {
2688 if (defined("SALE_DEBUG") && SALE_DEBUG)
2689 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." deducted successfully", array(), "DBP3");
2690 }
2691 else
2692 {
2693 $arResult["ERROR"]["PRODUCT_ID"] = $arBasket["PRODUCT_ID"];
2694
2695 if ($ex = $APPLICATION->GetException())
2696 {
2697 $arResult["ERROR"]["MESSAGE"] = $ex->GetString();
2698 $arResult["ERROR"]["CODE"] = $ex->GetID();
2699 }
2700
2701 if (defined("SALE_DEBUG") && SALE_DEBUG)
2702 CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." deduction error", array(), "DBP4");
2703 }
2704 }
2705 }
2706
2707 if (defined("SALE_DEBUG") && SALE_DEBUG)
2708 CSaleHelper::WriteToLog("DeductBasketProduct result", array("arResult" => $arResult), "DBP5");
2709
2710 return $arResult;
2711 }
2712
2723 public static function OrderDeduction($orderID, $bUndoDeduction = false, $recurringID = 0, $bAutoDeduction = true, $arStoreBarcodeOrderFormData = array())
2724 {
2725 global $APPLICATION;
2726 static $storesCount = NULL;
2727 static $bAutoDeductionAllowed = NULL;
2728 $bRealDeductionAllowed = true;
2729 $defaultDeductionStore = 0;
2730 $arSavedStoreBarcodeData = array();
2731 $arItems = array();
2732 $arResult = array();
2733
2734 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
2735
2736 if (defined("SALE_DEBUG") && SALE_DEBUG)
2737 {
2739 "OrderDeduction: started",
2740 array(
2741 "orderID" => $orderID,
2742 "bUndoDeduction" => intval($bUndoDeduction),
2743 "bAutoDeduction" => intval($bAutoDeduction),
2744 "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData
2745 ),
2746 "OD1"
2747 );
2748 }
2749
2750 //TODO - recurringID - ?
2751 $orderID = intval($orderID);
2752 if ($orderID <= 0)
2753 {
2754 $arResult["RESULT"] = false;
2755 return $arResult;
2756 }
2757
2758 if ($isOrderConverted != 'N')
2759 {
2760 $ship = !$bUndoDeduction;
2762 $r = \Bitrix\Sale\Compatible\OrderCompatibility::shipment($orderID, $ship, $arStoreBarcodeOrderFormData);
2763 if (!$r->isSuccess(true))
2764 {
2765 foreach($r->getErrorMessages() as $error)
2766 {
2767// $APPLICATION->ThrowException($error);
2768
2769 $arResult["ERROR"]["MESSAGE"] = $error;
2770// $arResult["ERROR"]["CODE"] = $ex->GetID();
2771 break;
2772 }
2773
2774 $arResult["RESULT"] = false;
2775 return $arResult;
2776 }
2777
2778 $arResult["RESULT"] = true;
2779
2780 return $arResult;
2781 }
2782
2783 $dbBasketList = CSaleBasket::GetList(
2784 array(),
2785 array("ORDER_ID" => $orderID),
2786 false,
2787 false,
2788 array('ID', 'LID', 'PRODUCT_ID', 'PRODUCT_PROVIDER_CLASS', 'MODULE', 'BARCODE_MULTI', 'QUANTITY', 'RESERVED', 'TYPE', 'SET_PARENT_ID')
2789 );
2790
2791 //check basket items and emulate deduction
2792 while ($arBasket = $dbBasketList->Fetch())
2793 {
2794 if (CSaleBasketHelper::isSetParent($arBasket))
2795 continue;
2796
2797 if (defined("SALE_DEBUG") && SALE_DEBUG)
2798 CSaleHelper::WriteToLog("Deducting product #".$arBasket["PRODUCT_ID"], array(), "OD2");
2799
2801 if ($productProvider = CSaleBasket::GetProductProvider($arBasket))
2802 {
2803 if (is_null($storesCount))
2804 $storesCount = intval($productProvider::GetStoresCount(array("SITE_ID" => $arBasket["LID"])));
2805
2806 if (defined("SALE_DEBUG") && SALE_DEBUG)
2807 CSaleHelper::WriteToLog("stores count: ".$storesCount, array(), "OD3");
2808
2809 if (is_null($bAutoDeductionAllowed))
2810 {
2811 $defaultDeductionStore = COption::GetOptionString("sale", "deduct_store_id", "", $arBasket["LID"]);
2812
2813 if ($storesCount == 1 || $storesCount == -1 || intval($defaultDeductionStore) > 0) // if stores' count = 1 or stores aren't used or default deduction store is defined
2814 $bAutoDeductionAllowed = true;
2815 else
2816 $bAutoDeductionAllowed = false;
2817 }
2818
2819 if (defined("SALE_DEBUG") && SALE_DEBUG)
2820 CSaleHelper::WriteToLog("auto deduction allowed: ".intval($bAutoDeductionAllowed), array(), "OD4");
2821
2822 if ($bAutoDeduction && !$bAutoDeductionAllowed && !$bUndoDeduction)
2823 {
2824 if (defined("SALE_DEBUG") && SALE_DEBUG)
2825 CSaleHelper::WriteToLog("DDCT_AUTO_DEDUCT_WRONG_STORES_QUANTITY", array(), "OD5");
2826
2827 $APPLICATION->ThrowException(Loc::getMessage("DDCT_AUTO_DEDUCT_WRONG_STORES_QUANTITY"), "DDCT_WRONG_STORES_QUANTITY");
2828 $bRealDeductionAllowed = false;
2829 }
2830 else if ($bAutoDeduction && $arBasket["BARCODE_MULTI"] == "Y" && !$bUndoDeduction)
2831 {
2832 if (defined("SALE_DEBUG") && SALE_DEBUG)
2833 CSaleHelper::WriteToLog("DDCT_AUTO_DEDUCT_BARCODE_MULTI", array(), "OD6");
2834
2835 $APPLICATION->ThrowException(Loc::getMessage("DDCT_AUTO_DEDUCT_BARCODE_MULTI", array("#PRODUCT_ID#" => $arBasket["PRODUCT_ID"])), "DDCT_CANT_DEDUCT_BARCODE_MULTI");
2836 $bRealDeductionAllowed = false;
2837 }
2838 else
2839 {
2840 //get saved store & barcode data if stores are used to know where to return products
2841 if ($bUndoDeduction && $storesCount > 0)
2842 {
2843 $dbStoreBarcode = CSaleStoreBarcode::GetList(
2844 array(),
2845 array("BASKET_ID" => $arBasket["ID"]),
2846 false,
2847 false,
2848 array("ID", "BASKET_ID", "BARCODE", "QUANTITY", "STORE_ID")
2849 );
2850 while ($arStoreBarcode = $dbStoreBarcode->Fetch())
2851 {
2852 $arSavedStoreBarcodeData[$arBasket["ID"]][] = $arStoreBarcode;
2853 }
2854
2855 if (defined("SALE_DEBUG") && SALE_DEBUG)
2856 {
2858 "OrderDeduction: CSaleStoreBarcode data (stores) to return products to",
2859 array(
2860 "arSavedStoreBarcodeData" => $arSavedStoreBarcodeData
2861 ),
2862 "OD7"
2863 );
2864 }
2865 }
2866
2867 $arFields = array(
2868 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2869 "EMULATE" => "Y",
2870 "PRODUCT_RESERVED" => $arBasket["RESERVED"],
2871 "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N"
2872 );
2873
2874 if ($bUndoDeduction)
2875 {
2876 if ($storesCount > 0)
2877 {
2878 $arFields["QUANTITY"] = 0; //won't be used during deduction
2879 $arFields["STORE_DATA"] = $arSavedStoreBarcodeData[$arBasket["ID"]];
2880 }
2881 else
2882 {
2883 $arFields["QUANTITY"] = $arBasket["QUANTITY"];
2884 $arFields["STORE_DATA"] = array();
2885 }
2886 }
2887 else
2888 {
2889 if ($storesCount == 1)
2890 {
2891 $arFields["QUANTITY"] = 0;
2892
2893 if ($bAutoDeduction) //get the only possible store to deduct from it
2894 {
2895 $arProductStore = $productProvider::GetProductStores(array(
2896 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2897 "SITE_ID" => $arBasket["LID"],
2898 'BASKET_ID' => $arBasket['ID']
2899 ));
2900 if ($arProductStore)
2901 {
2902 $arFields["STORE_DATA"] = array(
2903 "0" => array(
2904 "STORE_ID" => $arProductStore[0]["STORE_ID"],
2905 "QUANTITY" => $arBasket["QUANTITY"],
2906 "AMOUNT" => $arProductStore[0]["AMOUNT"]
2907 )
2908 );
2909 }
2910 else
2911 {
2912 $arFields["STORE_DATA"] = array();
2913 }
2914 }
2915 else
2916 {
2917 $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]];
2918 }
2919 }
2920 else if (intval($defaultDeductionStore) > 0) // if default deduction store is defined
2921 {
2922 $arFields["QUANTITY"] = 0;
2923
2924 if ($bAutoDeduction)
2925 {
2926 $arProductStore = $productProvider::GetProductStores(array(
2927 "PRODUCT_ID" => $arBasket["PRODUCT_ID"],
2928 "SITE_ID" => $arBasket["LID"],
2929 'BASKET_ID' => $arBasket['ID']
2930 ));
2931 if ($arProductStore)
2932 {
2933 foreach ($arProductStore as $storeData)
2934 {
2935 if ($storeData["STORE_ID"] == intval($defaultDeductionStore))
2936 {
2937 $arFields["STORE_DATA"] = array(
2938 "0" => array(
2939 "STORE_ID" => $storeData["STORE_ID"],
2940 "QUANTITY" => $arBasket["QUANTITY"],
2941 "AMOUNT" => $storeData["AMOUNT"]
2942 )
2943 );
2944 break;
2945 }
2946 }
2947 }
2948 else
2949 {
2950 $arFields["STORE_DATA"] = array();
2951 }
2952 }
2953 else
2954 {
2955 $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]];
2956 }
2957 }
2958 else if ($storesCount > 1)
2959 {
2960 $arFields["QUANTITY"] = 0; //won't be used during deduction
2961 $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]];
2962 }
2963 else //store control not used
2964 {
2965 $arFields["QUANTITY"] = $arBasket["QUANTITY"];
2966 $arFields["STORE_DATA"] = array();
2967 }
2968 }
2969
2970 if (defined("SALE_DEBUG") && SALE_DEBUG)
2971 CSaleHelper::WriteToLog("Emulating ::DeductProduct call", array("arFields" => $arFields), "OD7");
2972
2973 $eventParams = array(
2974 'ORDER_ID' => $orderID,
2975 'RECURRING_ID' => $recurringID,
2976 'AUTO_DEDUCTION' => $bAutoDeduction,
2977 'STORE_DATA' => $arStoreBarcodeOrderFormData
2978 );
2979
2980 foreach (GetModuleEvents('sale', 'OnBeforeBasketDeductProduct', true) as $event)
2981 {
2982 if (ExecuteModuleEventEx($event, array($eventParams, $arBasket, &$arFields)) === false)
2983 {
2984 if (defined("SALE_DEBUG") && SALE_DEBUG)
2985 CSaleHelper::WriteToLog("Emulating ::DeductProduct call - error", array(), "OD7-1");
2986 $arResult["RESULT"] = false;
2987 return $arResult;
2988 }
2989 }
2990 unset($eventParams);
2991
2992 //emulate deduction
2993 $res = $productProvider::DeductProduct($arFields);
2994
2995 if ($res["RESULT"])
2996 {
2997 $arBasket["FIELDS"] = $arFields;
2998 $arItems[] = $arBasket;
2999
3000 if (defined("SALE_DEBUG") && SALE_DEBUG)
3001 CSaleHelper::WriteToLog("Emulating ::DeductProduct call - success", array(), "OD8");
3002 }
3003 else
3004 {
3005 $bRealDeductionAllowed = false;
3006
3007 if (defined("SALE_DEBUG") && SALE_DEBUG)
3008 CSaleHelper::WriteToLog("Emulating ::DeductProduct call - error", array(), "OD9");
3009 }
3010 }
3011
3012 if ($ex = $APPLICATION->GetException())
3013 {
3014 $arResult["ERROR"]["MESSAGE"] = $ex->GetString();
3015 $arResult["ERROR"]["CODE"] = $ex->GetID();
3016 }
3017
3018 if (!$bRealDeductionAllowed)
3019 break;
3020 }
3021 }
3022
3023 // real deduction
3024 if ($bRealDeductionAllowed)
3025 {
3026 $bProductsDeductedSuccessfully = true;
3027 $arDeductedItems = array();
3028 foreach ($arItems as $arItem)
3029 {
3031 if ($productProvider = CSaleBasket::GetProductProvider($arItem))
3032 {
3033 $arItem["FIELDS"]["EMULATE"] = "N";
3034
3035 if (defined("SALE_DEBUG") && SALE_DEBUG)
3036 CSaleHelper::WriteToLog("Call ::DeductProduct", array("fields" => $arItem["FIELDS"]), "OD10");
3037
3038 // finally real deduction
3039 $res = $productProvider::DeductProduct($arItem["FIELDS"]);
3040
3041 if ($res["RESULT"])
3042 {
3043 $arDeductedItems[] = $arItem;
3044
3045 if (!$bUndoDeduction && $storesCount > 0)
3046 {
3047 if ($bAutoDeduction)
3048 {
3049 $storeList = array_keys($res["STORES"]);
3050 $storeId = array_pop($storeList);
3051 $arStoreBarcodeFields = array(
3052 "BASKET_ID" => $arItem["ID"],
3053 "BARCODE" => "",
3054 "STORE_ID" => $storeId,
3055 "QUANTITY" => $arItem["QUANTITY"],
3056 "CREATED_BY" => ((intval($GLOBALS["USER"]->GetID())>0) ? intval($GLOBALS["USER"]->GetID()) : ""),
3057 "MODIFIED_BY" => ((intval($GLOBALS["USER"]->GetID())>0) ? intval($GLOBALS["USER"]->GetID()) : ""),
3058 );
3059
3060 if (defined("SALE_DEBUG") && SALE_DEBUG)
3061 CSaleHelper::WriteToLog("Call CSaleStoreBarcode::Add (auto deduction = true)", array("arStoreBarcodeFields" => $arStoreBarcodeFields), "OD11");
3062
3063 CSaleStoreBarcode::Add($arStoreBarcodeFields);
3064 }
3065 }
3066
3067 if ($bUndoDeduction)
3068 {
3069 $dbStoreBarcode = CSaleStoreBarcode::GetList(array(), array("BASKET_ID" => $arItem["ID"]), false, false, array("ID", "BASKET_ID"));
3070 while ($arStoreBarcode = $dbStoreBarcode->GetNext())
3071 CSaleStoreBarcode::Delete($arStoreBarcode["ID"]);
3072 }
3073
3074 $tmpRes = ($bUndoDeduction) ? "N" : "Y";
3075 CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => $tmpRes));
3076
3077 // set parent deducted status
3078 if ($bUndoDeduction)
3079 {
3080 if (CSaleBasketHelper::isSetItem($arItem))
3081 CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "N"));
3082 }
3083 else
3084 {
3085 if (CSaleBasketHelper::isSetItem($arItem) && CSaleBasketHelper::isSetDeducted($arItem["SET_PARENT_ID"]))
3086 CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "Y"));
3087 }
3088
3089 if (defined("SALE_DEBUG") && SALE_DEBUG)
3090 CSaleHelper::WriteToLog("Call ::DeductProduct - Success (DEDUCTED = ".$tmpRes.")", array(), "OD11");
3091 }
3092 else
3093 {
3094 CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => "N"));
3095 $bProductsDeductedSuccessfully = false;
3096
3097 if ($ex = $APPLICATION->GetException())
3098 {
3099 $arResult["ERROR"]["MESSAGE"] = $ex->GetString();
3100 $arResult["ERROR"]["CODE"] = $ex->GetID();
3101 }
3102
3103 if (defined("SALE_DEBUG") && SALE_DEBUG)
3104 CSaleHelper::WriteToLog("Call ::DeductProduct - Error (DEDUCTED = N)", array(), "OD12");
3105
3106 break;
3107 }
3108 }
3109 }
3110
3111 if ($bProductsDeductedSuccessfully)
3112 {
3113 $arResult["RESULT"] = true;
3114 }
3115 else //revert real deduction if error happened
3116 {
3117 $arFields = array();
3118 foreach ($arDeductedItems as $arItem)
3119 {
3121 if ($productProvider = CSaleBasket::GetProductProvider($arItem))
3122 {
3123 if ($storesCount > 0)
3124 {
3125 $arFields = array(
3126 "PRODUCT_ID" => $arItem["PRODUCT_ID"],
3127 "QUANTITY" => $arItem["QUANTITY"],
3128 "UNDO_DEDUCTION" => "Y",
3129 "EMULATE" => "N",
3130 "PRODUCT_RESERVED" => $arItem["FIELDS"]["PRODUCT_RESERVED"],
3131 "STORE_DATA" => $arItem["FIELDS"]["STORE_DATA"] //during auto deduction
3132 );
3133 }
3134 else
3135 {
3136 $arFields = array(
3137 "PRODUCT_ID" => $arItem["PRODUCT_ID"],
3138 "QUANTITY" => $arItem["QUANTITY"],
3139 "UNDO_DEDUCTION" => "Y",
3140 "PRODUCT_RESERVED" => $arItem["FIELDS"]["PRODUCT_RESERVED"],
3141 "EMULATE" => "N",
3142 );
3143 }
3144
3145 if (defined("SALE_DEBUG") && SALE_DEBUG)
3146 {
3148 "Call ::DeductProduct - Revert deduction", array(
3149 "storesCount" => $storesCount,
3150 "arFields" => $arFields
3151 ),
3152 "OD13"
3153 );
3154 }
3155
3156 $res = $productProvider::DeductProduct($arFields);
3157
3158 if ($res["RESULT"])
3159 {
3160 CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => "N"));
3161
3162 if (CSaleBasketHelper::isSetItem($arItem)) // todo - possibly not all the time, but once
3163 CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "N"));
3164 }
3165 }
3166 }
3167
3168 $arResult["RESULT"] = false;
3169 }
3170 }
3171 else
3172 {
3173 $arResult["RESULT"] = false;
3174 }
3175
3176 if (defined("SALE_DEBUG") && SALE_DEBUG)
3177 CSaleHelper::WriteToLog("OrderDeduction - result", array("arResult" => $arResult), "OD14");
3178
3179 return $arResult;
3180 }
3181
3182 public static function TransferBasket($FROM_FUSER_ID, $TO_FUSER_ID)
3183 {
3184 $FROM_FUSER_ID = (int)$FROM_FUSER_ID;
3185 $TO_FUSER_ID = (int)$TO_FUSER_ID;
3186
3187 if ($TO_FUSER_ID > 0 && $FROM_FUSER_ID > 0)
3188 {
3189 $dbTmp = CSaleUser::GetList(array("ID" => $TO_FUSER_ID));
3190 if (!empty($dbTmp))
3191 {
3192 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3193
3195 $basketClass = $registry->getBasketClassName();
3196
3197 $basketToFUser = $basketClass::loadItemsForFUser($TO_FUSER_ID, SITE_ID);
3198 $basketFromFUser = $basketClass::loadItemsForFUser($FROM_FUSER_ID, SITE_ID);
3199
3200 if ($basketFromFUser->count() > 0)
3201 {
3203 foreach ($basketFromFUser as $basketItemFrom)
3204 {
3206 $basketItemFromProperties =
3207 ($tmp = $basketItemFrom->getPropertyCollection())
3208 ? $tmp->getPropertyValues()
3209 : []
3210 ;
3211 $basketItems = $basketToFUser->getExistsItems(
3212 $basketItemFrom->getField('MODULE'),
3213 $basketItemFrom->getField('PRODUCT_ID'),
3214 $basketItemFromProperties
3215 );
3216
3217 if (count($basketItems) === 1)
3218 {
3219 $basketItem = current($basketItems);
3220 $basketItem->setField('QUANTITY', $basketItem->getQuantity() + $basketItemFrom->getQuantity());
3221 $basketItemFrom->delete();
3222 }
3223 /*
3224 * if there is no such product in the 'toFUser' basket
3225 * or there are several of them, then add a new basket item with the same product.
3226 */
3227 else
3228 {
3229 $basketItemFrom->setFieldNoDemand('FUSER_ID', $TO_FUSER_ID);
3230 }
3231 }
3232
3233 $basketToFUser->save();
3234 $basketFromFUser->save();
3235 }
3236 Sale\BasketComponentHelper::updateFUserBasket($TO_FUSER_ID, SITE_ID);
3237 Sale\BasketComponentHelper::updateFUserBasket($FROM_FUSER_ID, SITE_ID);
3238
3239 Sale\Discount\RuntimeCache\FuserCache::getInstance()->clean();
3240
3241 return true;
3242 }
3243 }
3244 return false;
3245 }
3246
3247 public static function UpdateBasketPrices($fuserID, $siteID, array $options = array())
3248 {
3249 $fuserID = (int)$fuserID;
3250 if ($fuserID <= 0)
3251 return false;
3252 $siteID = (string)$siteID;
3253 if ($siteID == '')
3254 $siteID = SITE_ID;
3255
3256 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
3257
3258 if ($isOrderConverted != 'N')
3259 {
3260 self::refreshFUserBasket($fuserID, $siteID, $options);
3261 }
3262 else
3263 {
3264
3265 $dbBasketItems = CSaleBasket::GetList(
3266 array("ALL_PRICE" => "DESC"),
3267 array(
3268 "FUSER_ID" => $fuserID,
3269 "LID" => $siteID,
3270 "ORDER_ID" => "NULL",
3271 "SUBSCRIBE" => "N"
3272 ),
3273 false,
3274 false,
3275 array(
3276 "ID", "MODULE", "PRODUCT_ID", "QUANTITY",
3277 "CALLBACK_FUNC", "PRODUCT_PROVIDER_CLASS",
3278 "CAN_BUY", "DELAY", "NOTES",
3279 "TYPE", "SET_PARENT_ID"
3280 )
3281 );
3282 while ($arItem = $dbBasketItems->Fetch())
3283 {
3284 $basketItems[] = $arItem;
3285 }
3286
3287 if (!empty($basketItems) && is_array($basketItems))
3288 {
3289 $basketItems = getRatio($basketItems);
3290
3291 foreach ($basketItems as $basketItem)
3292 {
3293 $fields = array();
3294 $basketItem['CALLBACK_FUNC'] = (string)$basketItem['CALLBACK_FUNC'];
3295 $basketItem['PRODUCT_PROVIDER_CLASS'] = (string)$basketItem['PRODUCT_PROVIDER_CLASS'];
3296
3297 if (strval(trim($basketItem['PRODUCT_PROVIDER_CLASS'])) !== '' || strval(trim($basketItem['CALLBACK_FUNC'])) !== '')
3298 {
3299 $basketItem['MODULE'] = (string)$basketItem['MODULE'];
3300 $basketItem['PRODUCT_ID'] = (int)$basketItem['PRODUCT_ID'];
3301 $basketItem['QUANTITY'] = (float)$basketItem['QUANTITY'];
3302
3303 if ($productProvider = CSaleBasket::GetProductProvider($basketItem))
3304 {
3305 $fields = $productProvider::GetProductData(array(
3306 "PRODUCT_ID" => $basketItem["PRODUCT_ID"],
3307 "QUANTITY" => $basketItem["QUANTITY"],
3308 "RENEWAL" => "N",
3309 "CHECK_COUPONS" => ('Y' == $basketItem['CAN_BUY'] && 'N' == $basketItem['DELAY'] ? 'Y' : 'N'),
3310 "CHECK_DISCOUNT" => (CSaleBasketHelper::isSetItem($basketItem) ? 'N' : 'Y'),
3311 "BASKET_ID" => $basketItem["ID"],
3312 "NOTES" => $basketItem["NOTES"]
3313 ));
3314 }
3315 else
3316 {
3318 $basketItem["CALLBACK_FUNC"],
3319 $basketItem["MODULE"],
3320 $basketItem["PRODUCT_ID"],
3321 $basketItem["QUANTITY"],
3322 "N"
3323 );
3324 }
3325
3326 if (!empty($fields) && is_array($fields))
3327 {
3328 if ($isOrderConverted != 'N' && $basketItem['DELAY'] == 'N')
3329 {
3334 }
3335 $fields['CAN_BUY'] = 'Y';
3336 $fields['TYPE'] = (int)$basketItem['TYPE'];
3337 $fields['SET_PARENT_ID'] = (int)$basketItem['SET_PARENT_ID'];
3338 }
3339 else
3340 {
3341 $fields = array('CAN_BUY' => 'N');
3342 }
3343
3344
3345 }
3346
3347 if (array_key_exists('MEASURE_RATIO', $basketItem))
3348 {
3349 $basketItemQuantity = floatval($basketItem['QUANTITY']);
3350 $basketItemRatio = floatval($basketItem['MEASURE_RATIO']);
3351
3352 $mod = roundEx(($basketItemQuantity / $basketItemRatio - round($basketItemQuantity / $basketItemRatio)), 6);
3353
3354 if ($mod != 0)
3355 {
3356 $fields['QUANTITY'] = floor(ceil($basketItemQuantity) / $basketItemRatio) * $basketItemRatio;
3357 }
3358 }
3359
3360 if (!empty($fields) && is_array($fields))
3361 {
3362 CSaleBasket::Update($basketItem['ID'], $fields);
3363 }
3364 }
3365 }
3366 }
3367 return true;
3368 }
3369
3378 public static function refreshFUserBasket($fuserID, $siteID, array $options = array())
3379 {
3380 $result = new Sale\Result();
3381
3382 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3383
3385 $basketClass = $registry->getBasketClassName();
3386
3388 $basket = $basketClass::loadItemsForFUser($fuserID, $siteID);
3389 if ($basket->count() > 0)
3390 {
3393
3394 $select = array("PRICE", 'QUANTITY', "COUPONS");
3395 $basket->refreshData($select);
3396 $warnings = array();
3397
3398 if (!empty($options) && array_key_exists('CORRECT_RATIO', $options) && $options['CORRECT_RATIO'] === 'Y')
3399 {
3400 $r = Sale\BasketComponentHelper::correctQuantityRatio($basket);
3401 if (!$r->isSuccess())
3402 {
3403 foreach ($r->getErrors() as $error)
3404 {
3405 if ($error instanceof Sale\ResultWarning)
3406 {
3407 $warnings[] = $error;
3408 }
3409 elseif ($error instanceof Sale\ResultError)
3410 {
3411 $result->addError($error);
3412 }
3413 }
3414 }
3415 }
3416
3417 if ($result->isSuccess())
3418 {
3419 $r = $basket->save();
3420 if (!$r->isSuccess())
3421 {
3422 $result->addErrors($r->getErrors());
3423 }
3424 }
3425
3426 $basketList = array();
3428 foreach ($basket as $basketItem)
3429 {
3430 $basketList[$basketItem->getId()] = $basketItem->getFieldValues();
3431 }
3432
3433 $result->addData(array('BASKET_LIST' => $basketList));
3434
3435 if (!empty($warnings))
3436 {
3437 $result->addWarnings($warnings);
3438 }
3439 }
3440
3441 return $result;
3442 }
3443
3449 public static function compareBasketProps($newProperties, $oldProperties)
3450 {
3451 $result = null;
3452 if (!is_array($newProperties) || !is_array($oldProperties))
3453 return $result;
3454 $result = true;
3455 if (empty($newProperties) && empty($oldProperties))
3456 return $result;
3457 $compareNew = array();
3458 $compareOld = array();
3459
3460 foreach ($newProperties as &$property)
3461 {
3462 if (!isset($property['VALUE']))
3463 continue;
3464 $property['VALUE'] = (string)$property['VALUE'];
3465 if ($property['VALUE'] == '')
3466 continue;
3467
3468 $propertyID = '';
3469 if (isset($property['CODE']))
3470 {
3471 $property['CODE'] = (string)$property['CODE'];
3472 if ($property['CODE'] != '')
3473 $propertyID = $property['CODE'];
3474 }
3475 if ($propertyID == '' && isset($property['NAME']))
3476 {
3477 $property['NAME'] = (string)$property['NAME'];
3478 if ($property['NAME'] != '')
3479 $propertyID = $property['NAME'];
3480 }
3481 if ($propertyID == '')
3482 continue;
3483 $compareNew[$propertyID] = $property['VALUE'];
3484 }
3485 unset($property);
3486
3487 foreach ($oldProperties as &$property)
3488 {
3489 if (!isset($property['VALUE']))
3490 continue;
3491 $property['VALUE'] = (string)$property['VALUE'];
3492 if ($property['VALUE'] == '')
3493 continue;
3494
3495 $propertyID = '';
3496 if (isset($property['CODE']))
3497 {
3498 $property['CODE'] = (string)$property['CODE'];
3499 if ($property['CODE'] != '')
3500 $propertyID = $property['CODE'];
3501 }
3502 if ($propertyID == '' && isset($property['NAME']))
3503 {
3504 $property['NAME'] = (string)$property['NAME'];
3505 if ($property['NAME'] != '')
3506 $propertyID = $property['NAME'];
3507 }
3508 if ($propertyID == '')
3509 continue;
3510 $compareOld[$propertyID] = $property['VALUE'];
3511 }
3512 unset($property);
3513
3514 $result = false;
3515 if (count($compareNew) == count($compareOld))
3516 {
3517 $result = true;
3518 foreach($compareNew as $key => $val)
3519 {
3520 if (!isset($compareOld[$key]) || $compareOld[$key] != $val)
3521 {
3522 $result = false;
3523 break;
3524 }
3525 }
3526 }
3527 unset($compareOld, $compareNew);
3528
3529 return $result;
3530 }
3531
3536 public static function getRoundFields()
3537 {
3538 $isOrderConverted = Option::get("main", "~sale_converted_15", 'Y');
3539 if ($isOrderConverted != 'N')
3540 {
3541 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3543 $basketItemClassName = $registry->getBasketItemClassName();
3544 return $basketItemClassName::getRoundFields();
3545 }
3546
3547 return array(
3548 'DISCOUNT_PRICE',
3549 'DISCOUNT_PRICE_PERCENT',
3550 );
3551 }
3552}
3553
3555{
3562 public static function GetAnonymousUserID()
3563 {
3564 $bUserExists = false;
3565
3566 $anonUserID = intval(COption::GetOptionInt("sale", "anonymous_user_id", 0));
3567
3568 if ($anonUserID > 0)
3569 {
3570 $dbUser = CUser::GetList('id', 'asc', array("ID_EQUAL_EXACT"=>$anonUserID), array("FIELDS"=>array("ID")));
3571 if ($arUser = $dbUser->Fetch())
3572 $bUserExists = true;
3573 }
3574
3575 if (!$bUserExists)
3576 {
3577 $anonUserEmail = "anonymous_".randString(9)."@example.com";
3578 $arErrors = array();
3579 $anonUserID = CSaleUser::DoAutoRegisterUser(
3580 $anonUserEmail,
3581 array("NAME" => Loc::getMessage("SU_ANONYMOUS_USER_NAME")),
3582 SITE_ID,
3583 $arErrors,
3584 array(
3585 'ACTIVE' => 'N',
3586 'EXTERNAL_AUTH_ID' => 'saleanonymous',
3587 )
3588 );
3589
3590 if ($anonUserID > 0)
3591 {
3592 COption::SetOptionInt("sale", "anonymous_user_id", $anonUserID);
3593 }
3594 else
3595 {
3596 $errorMessage = "";
3597 if (!empty($arErrors))
3598 {
3599 $errorMessage = " ";
3600 foreach ($arErrors as $value)
3601 {
3602 $errorMessage .= $value["TEXT"]."<br>";
3603 }
3604 }
3605
3606 $GLOBALS["APPLICATION"]->ThrowException(Loc::getMessage("SU_ANONYMOUS_USER_CREATE", array("#ERROR#" => $errorMessage)), "ANONYMOUS_USER_CREATE_ERROR");
3607 return 0;
3608 }
3609 }
3610
3611 return $anonUserID;
3612 }
3613
3614 public static function DoAutoRegisterUser($autoEmail, $payerName, $siteId, &$arErrors, $arOtherFields = null)
3615 {
3616 if ($siteId == null)
3617 $siteId = SITE_ID;
3618
3619 $autoEmail = trim($autoEmail);
3620
3621 $autoName = "";
3622 $autoLastName = "";
3623 $autoSecondName = "";
3624
3625 if (!is_array($payerName) && ($payerName <> ''))
3626 {
3627 $arNames = explode(" ", $payerName);
3628 $autoName = $arNames[1];
3629 $autoLastName = $arNames[0];
3630 $autoSecondName = (!empty($arNames[2]) ? trim($arNames[2]) : false);
3631 }
3632 elseif (is_array($payerName))
3633 {
3634 $autoName = $payerName["NAME"] ?? '';
3635 $autoLastName = $payerName["LAST_NAME"] ?? '';
3636 $autoSecondName = $payerName["SECOND_NAME"] ?? '';
3637 }
3638
3639 if (!empty($autoEmail))
3640 {
3641 $autoLogin = $autoEmail;
3642
3643 $pos = mb_strpos($autoLogin, "@");
3644 if ($pos !== false)
3645 $autoLogin = mb_substr($autoLogin, 0, $pos);
3646
3647 if (mb_strlen($autoLogin) > 47)
3648 $autoLogin = mb_substr($autoLogin, 0, 47);
3649
3650 while (mb_strlen($autoLogin) < 3)
3651 $autoLogin .= "_";
3652 }
3653 else
3654 {
3655 $autoLogin = "buyer";
3656 }
3657
3658 $idx = 0;
3659 $loginTmp = $autoLogin;
3660 $dbUserLogin = CUser::GetByLogin($autoLogin);
3661 while ($arUserLogin = $dbUserLogin->Fetch())
3662 {
3663 $idx++;
3664
3665 if ($idx <= 10)
3666 $autoLogin = $loginTmp.$idx;
3667 else
3668 $autoLogin = "buyer".time().GetRandomCode(2);
3669
3670 $dbUserLogin = CUser::GetByLogin($autoLogin);
3671 }
3672
3673 $groups = [];
3674
3676 {
3677 $groups = \Bitrix\Crm\Order\BuyerGroup::getDefaultGroups();
3678 }
3679 else
3680 {
3681 $defaultGroup = COption::GetOptionString("main", "new_user_registration_def_group", "");
3682
3683 if (!empty($defaultGroup))
3684 {
3685 $groups = explode(",", $defaultGroup);
3686 }
3687 }
3688
3689 $autoPassword = \CUser::GeneratePasswordByPolicy($groups);
3690
3691 $arFields = array(
3692 "LOGIN" => $autoLogin,
3693 "PASSWORD" => $autoPassword,
3694 "PASSWORD_CONFIRM" => $autoPassword,
3695 "GROUP_ID" => $groups,
3696 "LID" => $siteId,
3697 // reset department for intranet
3698 'UF_DEPARTMENT' => []
3699 );
3700
3701 if($autoName <> '')
3702 $arFields["NAME"] = $autoName;
3703
3704 if($autoLastName <> '')
3705 $arFields["LAST_NAME"] = $autoLastName;
3706
3707 if($autoSecondName <> '')
3708 $arFields["SECOND_NAME"] = $autoSecondName;
3709
3710 if($autoEmail <> '')
3711 $arFields["EMAIL"] = $autoEmail;
3712
3713 $arFields["ACTIVE"] = (isset($arOtherFields["ACTIVE"]) && $arOtherFields["ACTIVE"] == "N") ? "N" : "Y";
3714 if (isset($arOtherFields["ACTIVE"]))
3715 unset($arOtherFields["ACTIVE"]);
3716
3717 if (is_array($arOtherFields))
3718 {
3719 foreach ($arOtherFields as $key => $value)
3720 {
3721 if (!array_key_exists($key, $arFields))
3722 $arFields[$key] = $value;
3723 }
3724 }
3725
3726 $user = new CUser;
3727 $userId = $user->Add($arFields);
3728
3729 if (intval($userId) <= 0)
3730 {
3731 $arErrors[] = array("TEXT" => Loc::getMessage("STOF_ERROR_REG").(($user->LAST_ERROR <> '') ? ": ".$user->LAST_ERROR : ""));
3732 return 0;
3733 }
3734
3735 return $userId;
3736 }
3737
3738 public static function CheckFields($ACTION, &$arFields, $ID = 0)
3739 {
3740 return true;
3741 }
3742
3750 public static function GetID($bSkipFUserInit = false)
3751 {
3752 $bSkipFUserInit = ($bSkipFUserInit !== false);
3753
3754 return (int)Sale\Fuser::getId($bSkipFUserInit);
3755 }
3756
3765 public static function Update($ID, $allowUpdate = true)
3766 {
3767 Sale\Fuser::update(
3768 (int)$ID,
3769 [
3770 'update' => (bool)$allowUpdate,
3771 ]
3772 );
3773
3774 return true;
3775 }
3776
3784 public static function _Update($ID, $arFields)
3785 {
3786 global $DB;
3787
3788 $DB->StartUsingMasterOnly();
3789
3790 $ID = intval($ID);
3791 if ($ID <= 0)
3792 return False;
3793
3794 $arFields1 = array();
3795 foreach ($arFields as $key => $value)
3796 {
3797 if (mb_substr($key, 0, 1) == "=")
3798 {
3799 $arFields1[mb_substr($key, 1)] = $value;
3800 unset($arFields[$key]);
3801 }
3802 }
3803
3804 if (!CSaleUser::CheckFields("UPDATE", $arFields, $ID))
3805 return false;
3806
3807 $strUpdate = $DB->PrepareUpdate("b_sale_fuser", $arFields);
3808
3809 foreach ($arFields1 as $key => $value)
3810 {
3811 if ($strUpdate <> '') $strUpdate .= ", ";
3812 $strUpdate .= $key."=".$value." ";
3813 }
3814
3815 $strSql = "UPDATE b_sale_fuser SET ".$strUpdate." WHERE ID = ".$ID." ";
3816 $DB->Query($strSql);
3817
3818 $DB->StopUsingMasterOnly();
3819
3820 return $ID;
3821 }
3822
3823 public static function GetList($arFilter)
3824 {
3825 global $DB;
3826 $arSqlSearch = Array();
3827
3828 if (!is_array($arFilter))
3829 $filter_keys = Array();
3830 else
3831 $filter_keys = array_keys($arFilter);
3832
3833 $countarFilter = count($filter_keys);
3834 for ($i=0; $i < $countarFilter; $i++)
3835 {
3836 $val = $DB->ForSql($arFilter[$filter_keys[$i]]);
3837
3838 $key = $filter_keys[$i];
3839 if ($key[0]=="!")
3840 {
3841 $key = mb_substr($key, 1);
3842 $bInvert = true;
3843 }
3844 else
3845 $bInvert = false;
3846
3847 if (strval($val) == "")
3848 $val = 0;
3849
3850 switch(mb_strtoupper($key))
3851 {
3852 case "ID":
3853 $arSqlSearch[] = "ID ".($bInvert?"<>":"=")." ".intval($val)." ";
3854 break;
3855 case "USER_ID":
3856 $arSqlSearch[] = "USER_ID ".($bInvert?"<>":"=")." ".intval($val)." ";
3857 break;
3858 case "CODE":
3859 $arSqlSearch[] = "CODE ".($bInvert?"<>":"=")." '".$DB->ForSql($val)."' ";
3860 break;
3861 }
3862 }
3863
3864 $strSqlSearch = "";
3865 $countSqlSearch = count($arSqlSearch);
3866 for($i=0; $i < $countSqlSearch; $i++)
3867 {
3868 $strSqlSearch .= " AND ";
3869 $strSqlSearch .= " (".$arSqlSearch[$i].") ";
3870 }
3871
3872 $strSql = "SELECT ID, DATE_INSERT, DATE_UPDATE, USER_ID, CODE FROM b_sale_fuser WHERE 1 = 1 ".$strSqlSearch." ORDER BY ID DESC";
3873 $db_res = $DB->Query($strSql);
3874 return $db_res->Fetch();
3875 }
3876
3877 public static function Delete($ID)
3878 {
3879 global $DB;
3880
3881 $ID = intval($ID);
3882 foreach(GetModuleEvents("sale", "OnSaleUserDelete", true) as $arEvent)
3883 ExecuteModuleEventEx($arEvent, Array($ID));
3884
3885 $DB->Query("DELETE FROM b_sale_fuser WHERE ID = ".$ID." ", true);
3886
3887 return true;
3888 }
3889
3890 public static function OnUserLogin($new_user_id, array $params = [])
3891 {
3893 }
3894
3901 public static function UpdateSessionSaleUserID()
3902 {
3904 }
3905
3912 public static function getFUserCode()
3913 {
3914 $result = Sale\Fuser::getRegeneratedId();
3915
3916 return $result ?? 0;
3917 }
3918
3919 public static function OnUserLogout($userID)
3920 {
3922 }
3923
3924 public static function DeleteOldAgent($nDays, $speed = 0)
3925 {
3926 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
3927
3929 $basketClass = $registry->getBasketClassName();
3930
3931 return $basketClass::deleteOldAgent($nDays, $speed);
3932 }
3933
3934 public static function OnUserDelete($userID)
3935 {
3936 if($userID<=0)
3937 return false;
3938 $arSUser = CSaleUser::GetList(array("USER_ID" => $userID));
3939 if(!empty($arSUser))
3940 {
3941 if(!(CSaleBasket::DeleteAll($arSUser["ID"])))
3942 return false;
3943 if(!(CSaleUser::Delete($arSUser["ID"])))
3944 return false;
3945 }
3946 return true;
3947 }
3948}
$db_res
Определения options_user_settings.php:8
global $APPLICATION
Определения include.php:80
$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 includeModule($moduleName)
Определения loader.php:67
static getMessage($code, $replace=null, $language=null)
Определения loc.php:30
static isModuleInstalled($moduleName)
Определения modulemanager.php:125
static setBasketItemData($code, $providerData)
Определения discountcompatibility.php:497
static init($mode=self::MODE_CLIENT, $config=array())
Определения discountcompatibility.php:314
static getId($skipCreate=false)
Определения fuser.php:33
static handlerOnUserLogout($userId)
Определения fuser.php:653
static handlerOnUserLogin($userId, array $params)
Определения fuser.php:587
static refreshSessionCurrentId()
Определения fuser.php:81
static getProviderEntity($name)
Определения provider.php:1439
static getInstance($type)
Определения registry.php:183
static ConvertCurrency($valSum, $curFrom, $curTo, $valDate="")
Определения currency_rate.php:393
static GetOptionString($module_id, $name, $def="", $site=false, $bExactSite=false)
Определения option.php:8
Определения basket.php:12
static compareBasketProps($newProperties, $oldProperties)
Определения basket.php:3449
static ExecuteCallbackFunction($callbackFunc="", $module="", $productID=0)
Определения basket.php:1822
static OrderCanceled($orderID, $bCancel)
Определения basket.php:2293
static ReReadPrice($callbackFunc="", $module="", $productID=0, $quantity=0, $renewal="N", $productProvider="")
Определения basket.php:1864
static GetByID($ID)
Определения basket.php:1805
const TYPE_SET
Определения basket.php:13
static ClearProductSubscribe($LID)
Определения basket.php:59
static UpdatePrice($ID, $callbackFunc='', $module='', $productID=0, $quantity=0, $renewal='N', $productProvider='', $notes='')
Определения basket.php:1893
static OnOrderProduct($callbackFunc="", $module="", $productID=0, $quantity=0, $productProvider="")
Определения basket.php:1878
static array $currencyList
Определения basket.php:16
static _Update($ID, &$arFields)
Определения basket.php:1568
static GetBasketUserID($bSkipFUserInit=false)
Определения basket.php:1796
static Init($bVar=false, $bSkipFUserInit=false)
Определения basket.php:1779
static array $currencySiteList
Определения basket.php:15
static UpdateBasketPrices($fuserID, $siteID, array $options=array())
Определения basket.php:3247
static GetProductProvider($arBasketItem)
Определения basket.php:24
static OrderPayment($orderID, $bPaid, $recurringID=0)
Определения basket.php:2178
static AddRecordsByFields($orderId, array $arOldFields, array $arNewFields, $arDeleteFields=array(), $entityName="", $entityId=null, $entity=null, array $data=array())
Определения order_change.php:161
static SetMark($ID, $comment="", $userID=0)
Определения order.php:3089
static DoLoadProfiles($userId, $personTypeId=null)
Определения order_user_props.php:198
static Delete($ID)
Определения recurring.php:97
static Update($ID, $arFields)
Определения recurring.php:77
static Delete($ID)
Определения store_barcode.php:55
Определения basket.php:3555
static OnUserLogout($userID)
Определения basket.php:3919
static OnUserLogin($new_user_id, array $params=[])
Определения basket.php:3890
static getFUserCode()
Определения basket.php:3912
static UpdateSessionSaleUserID()
Определения basket.php:3901
static Delete($ID)
Определения basket.php:3877
static GetList($arFilter)
Определения basket.php:3823
static CheckFields($ACTION, &$arFields, $ID=0)
Определения basket.php:3738
static _Update($ID, $arFields)
Определения basket.php:3784
static OnUserDelete($userID)
Определения basket.php:3934
static Update($ID, $allowUpdate=true)
Определения basket.php:3765
static GetID($bSkipFUserInit=false)
Определения basket.php:3750
static DoAutoRegisterUser($autoEmail, $payerName, $siteId, &$arErrors, $arOtherFields=null)
Определения basket.php:3614
static GetAnonymousUserID()
Определения basket.php:3562
static GetByID($ID)
Определения site.php:749
static GetByID($ID)
Определения user.php:3820
static URN2URI($urn, $server_name='')
Определения http.php:39
static isSetParent($arItem)
Определения basket_helper.php:49
static isSetDeducted($setParentID)
Определения basket_helper.php:60
static isSetItem($arItem)
Определения basket_helper.php:26
static _ClearProductSubscribe($LID)
Определения basket.php:15
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения basket.php:33
static WriteToLog($text, $arVars=array(), $code="")
Определения helper.php:35
static IsAssociativeArray($ar)
Определения helper.php:6
static GetLangCurrency($siteId)
Определения settings.php:52
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 GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения person_type.php:7
static Add($arFields)
Определения recurring.php:169
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения recurring.php:47
static Add($arFields)
Определения store_barcode.php:7
static GetList($arOrder=Array("ID"=>"DESC"), $arFilter=Array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения store_barcode.php:97
Определения user.php:6037
if($childrenCount<=0) $mod
Определения sync.php:11
$options
Определения commerceml2.php:49
if(!is_array($prop["VALUES"])) $tmp
Определения component_props.php:203
$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
$result
Определения get_property_values.php:14
if($ajaxMode) $ID
Определения get_user.php:27
$select
Определения iblock_catalog_list.php:194
while($arParentIBlockProperty=$dbParentIBlockProperty->Fetch()) $errorMessage
$_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
$groups
Определения options.php:30
$arNames
Определения options.php:175
$siteId
Определения ajax.php:8
roundEx($value, $prec=0)
Определения tools.php:4635
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
is_set($a, $k=false)
Определения tools.php:2133
$user
Определения mysql_to_pgsql.php:33
$GLOBALS['____1690880296']
Определения license.php:1
$order
Определения payment.php:8
if(intval($iTestTransaction) > 0) $arTmp
Определения payment.php:22
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
else $userName
Определения order_form.php:75
</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
$currency
Определения template.php:266
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
const SALE_DEBUG
Определения include.php:4
const SALE_VALUE_PRECISION
Определения include.php:46
getRatio($arBasketItems)
Определения include.php:459
const SALE_PROC_REC_ATTEMPTS
Определения include.php:25
if( $reminder !=='') if(!is_array($arReminder)) $arSubscribeProd
Определения options.php:2425
$subscribeProd
Определения options.php:2426
$val
Определения options.php:1793
$orderID
Определения result.php:9
$arRes
Определения options.php:104
const SITE_ID
Определения sonet_set_content_view.php:12
$error
Определения subscription_card_product.php:20
$arFilter
Определения user_search.php:106
$fields
Определения yandex_run.php:501
if( $site[ 'SERVER_NAME']==='') if($site['SERVER_NAME']==='') $arProperties
Определения yandex_run.php:644