1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
product.php
См. документацию.
1<?php
8
10{
35
68
70 protected static $arProductCache = array();
71
73 protected static $usedCurrency = null;
75 protected static $optimalPriceWithVat = true;
77 protected static $useDiscount = true;
78
79 protected static $saleIncluded = null;
80 protected static $useSaleDiscount = null;
81 protected static $vatCache = array();
82
83 private static $existPriceTypeDiscounts = false;
84
92 public static function setUsedCurrency($currency)
93 {
95 }
96
103 public static function getUsedCurrency()
104 {
106 return $config['CURRENCY'];
107 }
108
115 public static function clearUsedCurrency()
116 {
118 }
119
127 public static function setPriceVatIncludeMode($mode)
128 {
129 Catalog\Product\Price\Calculation::setConfig(array('RESULT_WITH_VAT' => $mode));
130 }
131
138 public static function getPriceVatIncludeMode()
139 {
141 }
142
150 public static function setUseDiscount($use)
151 {
152 Catalog\Product\Price\Calculation::setConfig(array('USE_DISCOUNTS' => $use));
153 }
154
161 public static function getUseDiscount()
162 {
164 }
165
171 public static function ClearCache()
172 {
173 self::$vatCache = [];
174 }
175
180 public static function isAvailable($product)
181 {
182 $result = true;
183 if (!empty($product) && is_array($product))
184 {
185 if (isset($product['QUANTITY']) && isset($product['QUANTITY_TRACE']) && isset($product['CAN_BUY_ZERO']))
186 {
187 $result = !((float)$product['QUANTITY'] <= 0 && $product['QUANTITY_TRACE'] == 'Y' && $product['CAN_BUY_ZERO'] == 'N');
188 }
189 }
190 return $result;
191 }
192
200 public static function IsExistProduct($intID)
201 {
203 return (!empty($data));
204 }
205
206 public static function CheckFields($ACTION, &$arFields, $ID = 0)
207 {
208 global $APPLICATION;
209
210 $arMsg = array();
211 $boolResult = true;
212
213 $ACTION = mb_strtoupper($ACTION);
214 $ID = (int)$ID;
215 if ($ACTION == "ADD" && (!is_set($arFields, "ID") || (int)$arFields["ID"]<=0))
216 {
217 $arMsg[] = array('id' => 'ID','text' => Loc::getMessage('KGP_EMPTY_ID'));
218 $boolResult = false;
219 }
220 if ($ACTION != "ADD" && $ID <= 0)
221 {
222 $arMsg[] = array('id' => 'ID','text' => Loc::getMessage('KGP_EMPTY_ID'));
223 $boolResult = false;
224 }
225
226 $clearFields = array(
227 'NEGATIVE_AMOUNT_TRACE',
228 '~NEGATIVE_AMOUNT_TRACE',
229 '~TYPE',
230 '~AVAILABLE'
231 );
232 if ($ACTION =='UPDATE')
233 {
234 $clearFields[] = 'ID';
235 $clearFields[] = '~ID';
236 }
237 if ($ACTION == 'ADD')
238 {
239 $clearFields[] = 'BUNDLE';
240 $clearFields[] = '~BUNDLE';
241 }
242
243 foreach ($clearFields as $fieldName)
244 {
245 if (array_key_exists($fieldName, $arFields))
246 unset($arFields[$fieldName]);
247 }
248 unset($fieldName, $clearFields);
249
250 if ('ADD' == $ACTION)
251 {
252 if (!array_key_exists('SUBSCRIBE', $arFields))
253 $arFields['SUBSCRIBE'] = '';
254 if (!isset($arFields['TYPE']))
257 }
258
259 if (is_set($arFields, "ID") || $ACTION=="ADD")
260 $arFields["ID"] = (int)$arFields["ID"];
261 if (is_set($arFields, "QUANTITY") || $ACTION=="ADD")
262 $arFields["QUANTITY"] = doubleval($arFields["QUANTITY"]);
263 if (is_set($arFields, "QUANTITY_RESERVED") || $ACTION=="ADD")
264 $arFields["QUANTITY_RESERVED"] = doubleval($arFields["QUANTITY_RESERVED"]);
265 if (is_set($arFields, "OLD_QUANTITY"))
266 $arFields["OLD_QUANTITY"] = doubleval($arFields["OLD_QUANTITY"]);
267 if (is_set($arFields, "WEIGHT") || $ACTION=="ADD")
268 $arFields["WEIGHT"] = doubleval($arFields["WEIGHT"]);
269 if (is_set($arFields, "WIDTH") || $ACTION=="ADD")
270 $arFields["WIDTH"] = doubleval($arFields["WIDTH"]);
271 if (is_set($arFields, "LENGTH") || $ACTION=="ADD")
272 $arFields["LENGTH"] = doubleval($arFields["LENGTH"]);
273 if (is_set($arFields, "HEIGHT") || $ACTION=="ADD")
274 $arFields["HEIGHT"] = doubleval($arFields["HEIGHT"]);
275
276 if (is_set($arFields, "VAT_ID") || $ACTION=="ADD")
277 $arFields["VAT_ID"] = intval($arFields["VAT_ID"]);
278 if ((is_set($arFields, "VAT_INCLUDED") || $ACTION=="ADD") && ($arFields["VAT_INCLUDED"] != "Y"))
279 $arFields["VAT_INCLUDED"] = "N";
280
281 if ((is_set($arFields, "QUANTITY_TRACE") || $ACTION=="ADD") && ($arFields["QUANTITY_TRACE"] != "Y" && $arFields["QUANTITY_TRACE"] != "N"))
282 $arFields["QUANTITY_TRACE"] = "D";
283 if ((is_set($arFields, "CAN_BUY_ZERO") || $ACTION=="ADD") && ($arFields["CAN_BUY_ZERO"] != "Y" && $arFields["CAN_BUY_ZERO"] != "N"))
284 $arFields["CAN_BUY_ZERO"] = "D";
285 if (isset($arFields['CAN_BUY_ZERO']))
286 $arFields['NEGATIVE_AMOUNT_TRACE'] = $arFields['CAN_BUY_ZERO'];
287
288 if ((is_set($arFields, "PRICE_TYPE") || $ACTION=="ADD") && ($arFields["PRICE_TYPE"] != "R") && ($arFields["PRICE_TYPE"] != "T"))
289 $arFields["PRICE_TYPE"] = "S";
290
291 if ((is_set($arFields, "RECUR_SCHEME_TYPE") || $ACTION=="ADD") && ($arFields["RECUR_SCHEME_TYPE"] == '' || !in_array($arFields["RECUR_SCHEME_TYPE"], Catalog\ProductTable::getPaymentPeriods(false))))
292 {
293 $arFields["RECUR_SCHEME_TYPE"] = self::TIME_PERIOD_DAY;
294 }
295
296 if ((is_set($arFields, "RECUR_SCHEME_LENGTH") || $ACTION=="ADD") && (intval($arFields["RECUR_SCHEME_LENGTH"])<=0))
297 $arFields["RECUR_SCHEME_LENGTH"] = 0;
298
299 if ((is_set($arFields, "TRIAL_PRICE_ID") || $ACTION=="ADD") && (intval($arFields["TRIAL_PRICE_ID"])<=0))
300 $arFields["TRIAL_PRICE_ID"] = false;
301
302 if ((is_set($arFields, "WITHOUT_ORDER") || $ACTION=="ADD") && ($arFields["WITHOUT_ORDER"] != "Y"))
303 $arFields["WITHOUT_ORDER"] = "N";
304
305 if ((is_set($arFields, "SELECT_BEST_PRICE") || $ACTION=="ADD") && ($arFields["SELECT_BEST_PRICE"] != "N"))
306 $arFields["SELECT_BEST_PRICE"] = "Y";
307
308 $existPurchasingPrice = array_key_exists('PURCHASING_PRICE', $arFields);
309 $existPurchasingCurrency = array_key_exists('PURCHASING_CURRENCY', $arFields);
310 if ($ACTION == 'ADD')
311 {
312 $purchasingPrice = false;
313 $purchasingCurrency = false;
314
315 if ($existPurchasingPrice)
316 {
317 $purchasingPrice = static::checkPriceValue($arFields['PURCHASING_PRICE']);
318 if ($purchasingPrice !== false)
319 {
320 $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']);
321 if ($purchasingCurrency === false)
322 {
323 $arMsg[] = array('id' => 'PURCHASING_CURRENCY','text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY'));
324 $boolResult = false;
325 }
326 }
327 }
328
329 $arFields['PURCHASING_PRICE'] = $purchasingPrice;
330 $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency;
331 unset($purchasingCurrency, $purchasingPrice);
332 }
333 else
334 {
335 if ($existPurchasingPrice || $existPurchasingCurrency)
336 {
337 if ($existPurchasingPrice)
338 {
339 $arFields['PURCHASING_PRICE'] = static::checkPriceValue($arFields['PURCHASING_PRICE']);
340 if ($arFields['PURCHASING_PRICE'] === false)
341 {
342 $arFields['PURCHASING_CURRENCY'] = false;
343 }
344 else
345 {
346 if ($existPurchasingCurrency)
347 {
348 $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']);
349 if ($purchasingCurrency === false)
350 {
351 $arMsg[] = array('id' => 'PURCHASING_CURRENCY', 'text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY'));
352 $boolResult = false;
353 }
354 else
355 {
356 $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency;
357 }
358 unset($purchasingCurrency);
359 }
360 }
361 }
362 elseif ($existPurchasingCurrency)
363 {
364 $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']);
365 if ($purchasingCurrency === false)
366 {
367 $arMsg[] = array('id' => 'PURCHASING_CURRENCY', 'text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY'));
368 $boolResult = false;
369 }
370 else
371 {
372 $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency;
373 }
374 unset($purchasingCurrency);
375 }
376 }
377 }
378 unset($existPurchasingCurrency, $existPurchasingPrice);
379
380 if ((is_set($arFields, 'BARCODE_MULTI') || 'ADD' == $ACTION) && 'Y' != $arFields['BARCODE_MULTI'])
381 $arFields['BARCODE_MULTI'] = 'N';
382 if (array_key_exists('SUBSCRIBE', $arFields))
383 {
384 if ('Y' != $arFields['SUBSCRIBE'] && 'N' != $arFields['SUBSCRIBE'])
385 $arFields['SUBSCRIBE'] = 'D';
386 }
387 if (array_key_exists('BUNDLE', $arFields))
389
390 if ($boolResult)
391 {
392 $availableFieldsList = array(
393 'QUANTITY',
394 'QUANTITY_TRACE',
395 'CAN_BUY_ZERO'
396 );
397 $needCalculateAvailable = false;
398 $copyFields = $arFields;
399 if (isset($copyFields['QUANTITY_TRACE']) && $copyFields['QUANTITY_TRACE'] == 'D')
400 $copyFields['QUANTITY_TRACE'] = Main\Config\Option::get('catalog', 'default_quantity_trace');
401 if (isset($copyFields['CAN_BUY_ZERO']) && $copyFields['CAN_BUY_ZERO'] == 'D')
402 $copyFields['CAN_BUY_ZERO'] = Main\Config\Option::get('catalog', 'default_can_buy_zero');
403
404 if (!isset($arFields['AVAILABLE']))
405 {
406 if (
407 !isset($arFields['TYPE'])
411 )
412 {
413 if (
414 $ACTION == 'ADD'
415 && (
418 )
419 )
420 {
421 $needCalculateAvailable = true;
422 }
423 elseif ($ACTION == 'UPDATE')
424 {
425 $needFields = array();
426 foreach ($availableFieldsList as $availableField)
427 {
428 if (isset($arFields[$availableField]))
429 $needCalculateAvailable = true;
430 else
431 $needFields[] = $availableField;
432 }
433 unset($availableField);
434 if ($needCalculateAvailable && !empty($needFields))
435 {
436 $productIterator = Catalog\ProductTable::getList(array(
437 'select' => $needFields,
438 'filter' => array('=ID' => $ID)
439 ));
440 $product = $productIterator->fetch();
441 unset($productIterator);
442 if (!empty($product) && is_array($product))
443 {
444 foreach ($availableFieldsList as $availableField)
445 {
446 if (isset($copyFields[$availableField]))
447 continue;
448 $copyFields[$availableField] = $product[$availableField];
449 }
450 unset($availableField);
451 }
452 unset($product);
453 }
454 unset($needFields);
455 }
456 }
458 {
459 $offerList = CCatalogSku::getOffersList(array($ID), 0, array('ACTIVE' => 'Y'), array('ID'));
460 if (!empty($offerList[$ID]))
461 {
462 $skuAvailable = false;
463 $offerIterator = Catalog\ProductTable::getList(array(
464 'select' => array('ID', 'QUANTITY', 'QUANTITY_TRACE', 'CAN_BUY_ZERO'),
465 'filter' => array('@ID' => array_keys($offerList[$ID]))
466 ));
467 while ($offer = $offerIterator->fetch())
468 {
470 $skuAvailable = true;
471 }
472 unset($offer, $offerIterator);
473 if ($skuAvailable)
474 {
475 $arFields['AVAILABLE'] = 'Y';
476 $arFields['QUANTITY'] = '0';
477 $arFields['QUANTITY_TRACE'] = 'N';
478 $arFields['CAN_BUY'] = 'Y';
479 }
480 else
481 {
482 $arFields['AVAILABLE'] = 'N';
483 $arFields['QUANTITY'] = '0';
484 $arFields['QUANTITY_TRACE'] = 'Y';
485 $arFields['CAN_BUY'] = 'N';
486 }
487 }
488 else
489 {
490 $arFields['AVAILABLE'] = 'N';
491 }
492 unset($offerList);
493 }
494 }
495 if ($needCalculateAvailable)
496 $arFields['AVAILABLE'] = Catalog\ProductTable::calculateAvailable($copyFields);
497 unset($copyFields);
498 }
499
500 if (!$boolResult)
501 {
502 $obError = new CAdminException($arMsg);
503 $APPLICATION->ThrowException($obError);
504 }
505 return $boolResult;
506 }
507
516 public static function Add($fields, $checkExist = true)
517 {
518 $existProduct = false;
519 $checkExist = ($checkExist !== false);
520
521 if (empty($fields['ID']))
522 return false;
523 $fields['ID'] = (int)$fields['ID'];
524 if ($fields['ID'] <= 0)
525 return false;
526
527 if ($checkExist)
528 {
530 if (!empty($data))
531 $existProduct = !empty($data['ID']);
532 unset($data);
533 }
534
535 self::normalizeFields($fields);
536
537 if ($existProduct)
539 else
541 $success = $result->isSuccess();
542 if (!$success)
543 self::convertErrors($result);
544 unset($result);
545
546 return $success;
547 }
548
557 public static function Update($id, $fields)
558 {
559 $id = (int)$id;
560 if ($id <= 0)
561 return false;
562 if (!is_array($fields))
563 return false;
564
565 self::normalizeFields($fields);
566
568 $success = $result->isSuccess();
569 if (!$success)
570 self::convertErrors($result);
571 unset($result);
572
573 return $success;
574 }
575
583 public static function Delete($id)
584 {
585 $id = (int)$id;
586 if ($id <= 0)
587 return false;
588
590
591 return $result->isSuccess();
592 }
593
594 public static function ParseQueryBuildField($field)
595 {
596 $field = (string)$field;
597 if ($field == '')
598 return false;
599 $field = mb_strtoupper($field);
600 if (strncmp($field, 'CATALOG_', 8) != 0)
601 return false;
602
603 $iNum = 0;
604 $field = mb_substr($field, 8);
605 $p = mb_strrpos($field, '_');
606 if ($p !== false && $p > 0)
607 {
608 $iNum = (int)mb_substr($field, $p + 1);
609 if ($iNum > 0)
610 $field = mb_substr($field, 0, $p);
611 }
612 return array(
613 'FIELD' => $field,
614 'NUM' => $iNum
615 );
616 }
617
625 public static function GetByID($ID)
626 {
627 $ID = (int)$ID;
628 if ($ID <= 0)
629 return false;
630
632 'select' => [
633 'ID', 'QUANTITY', 'QUANTITY_RESERVED', 'QUANTITY_TRACE', 'QUANTITY_TRACE_ORIG', 'WEIGHT', 'WIDTH', 'LENGTH', 'HEIGHT', 'MEASURE',
634 'VAT_ID', 'VAT_INCLUDED', 'CAN_BUY_ZERO', 'CAN_BUY_ZERO_ORIG', 'NEGATIVE_AMOUNT_TRACE', 'NEGATIVE_AMOUNT_TRACE_ORIG',
635 'PRICE_TYPE', 'RECUR_SCHEME_TYPE', 'RECUR_SCHEME_LENGTH', 'TRIAL_PRICE_ID', 'WITHOUT_ORDER', 'SELECT_BEST_PRICE',
636 'TMP_ID', 'PURCHASING_PRICE', 'PURCHASING_CURRENCY', 'BARCODE_MULTI', 'SUBSCRIBE', 'SUBSCRIBE_ORIG',
637 'TYPE', 'BUNDLE', 'AVAILABLE', 'TIMESTAMP_X'
638 ],
639 'filter' => ['=ID' => $ID]
640 ]);
641 $result = $iterator->fetch();
642 unset($iterator);
643 if (empty($result))
644 return false;
645 if ($result['TIMESTAMP_X'] !== null and $result['TIMESTAMP_X'] instanceof Main\Type\DateTime)
646 {
647 $result['TIMESTAMP_X'] = $result['TIMESTAMP_X']->toString();
648 }
649 return $result;
650 }
651
659 public static function GetByIDEx($ID, $boolAllValues = false)
660 {
661 $boolAllValues = ($boolAllValues === true);
662 $ID = (int)$ID;
663 if ($ID <= 0)
664 return false;
665 $arFilter = array("ID" => $ID, "ACTIVE" => "Y", "ACTIVE_DATE" => "Y");
666
667 $dbIBlockElement = CIBlockElement::GetList(array(), $arFilter);
668 if ($arIBlockElement = $dbIBlockElement->GetNext())
669 {
670 if ($arIBlock = CIBlock::GetArrayByID($arIBlockElement["IBLOCK_ID"]))
671 {
672 $arIBlockElement["IBLOCK_ID"] = $arIBlock["ID"];
673 $arIBlockElement["IBLOCK_NAME"] = htmlspecialcharsbx($arIBlock["NAME"]);
674 $arIBlockElement["~IBLOCK_NAME"] = $arIBlock["NAME"];
675 $arIBlockElement["PROPERTIES"] = false;
676 $dbProps = CIBlockElement::GetProperty($arIBlock["ID"], $ID, "sort", "asc", array("ACTIVE"=>"Y", "NON_EMPTY"=>"Y"));
677 if ($arProp = $dbProps->Fetch())
678 {
679 $arAllProps = array();
680 do
681 {
682 $strID = ($arProp["CODE"] <> '' ? $arProp["CODE"] : $arProp["ID"]);
683 if (is_array($arProp["VALUE"]))
684 {
685 foreach ($arProp["VALUE"] as &$strOneValue)
686 {
687 $strOneValue = htmlspecialcharsbx($strOneValue);
688 }
689 if (isset($strOneValue))
690 unset($strOneValue);
691 }
692 else
693 {
694 $arProp["VALUE"] = htmlspecialcharsbx($arProp["VALUE"]);
695 }
696
697 if (is_array($arProp["DEFAULT_VALUE"]))
698 {
699 foreach ($arProp["DEFAULT_VALUE"] as $index => $value)
700 {
701 if (is_string($value))
702 $arProp["DEFAULT_VALUE"][$index] = htmlspecialcharsbx($value);
703 }
704 }
705 else
706 {
707 $arProp["DEFAULT_VALUE"] = htmlspecialcharsbx($arProp["DEFAULT_VALUE"]);
708 }
709
710 if ($boolAllValues && 'Y' == $arProp['MULTIPLE'])
711 {
712 if (!isset($arAllProps[$strID]))
713 {
714 $arAllProps[$strID] = array(
715 "NAME" => htmlspecialcharsbx($arProp["NAME"]),
716 "VALUE" => array($arProp["VALUE"]),
717 "VALUE_ENUM" => array(htmlspecialcharsbx($arProp["VALUE_ENUM"])),
718 "VALUE_XML_ID" => array(htmlspecialcharsbx($arProp["VALUE_XML_ID"])),
719 "DEFAULT_VALUE" => $arProp["DEFAULT_VALUE"],
720 "SORT" => htmlspecialcharsbx($arProp["SORT"]),
721 "MULTIPLE" => $arProp['MULTIPLE'],
722 );
723 }
724 else
725 {
726 $arAllProps[$strID]['VALUE'][] = $arProp["VALUE"];
727 $arAllProps[$strID]['VALUE_ENUM'][] = htmlspecialcharsbx($arProp["VALUE_ENUM"]);
728 $arAllProps[$strID]['VALUE_XML_ID'][] = htmlspecialcharsbx($arProp["VALUE_XML_ID"]);
729 }
730 }
731 else
732 {
733 $arAllProps[$strID] = array(
734 "NAME" => htmlspecialcharsbx($arProp["NAME"]),
735 "VALUE" => $arProp["VALUE"],
736 "VALUE_ENUM" => htmlspecialcharsbx($arProp["VALUE_ENUM"]),
737 "VALUE_XML_ID" => htmlspecialcharsbx($arProp["VALUE_XML_ID"]),
738 "DEFAULT_VALUE" => $arProp["DEFAULT_VALUE"],
739 "SORT" => htmlspecialcharsbx($arProp["SORT"]),
740 "MULTIPLE" => $arProp['MULTIPLE'],
741 );
742 }
743 }
744 while($arProp = $dbProps->Fetch());
745
746 $arIBlockElement["PROPERTIES"] = $arAllProps;
747 }
748
749 // bugfix: 2007-07-31 by Sigurd
750 $arIBlockElement["PRODUCT"] = CCatalogProduct::GetByID($ID);
751
752 $dbPrices = CPrice::GetList(array("SORT" => "ASC"), array("PRODUCT_ID" => $ID));
753 if ($arPrices = $dbPrices->Fetch())
754 {
755 $arAllPrices = array();
756 do
757 {
758 $arAllPrices[$arPrices["CATALOG_GROUP_ID"]] = array(
759 "EXTRA_ID" => intval($arPrices["EXTRA_ID"]),
760 "PRICE" => doubleval($arPrices["PRICE"]),
761 "CURRENCY" => htmlspecialcharsbx($arPrices["CURRENCY"])
762 );
763 }
764 while($arPrices = $dbPrices->Fetch());
765
766 $arIBlockElement["PRICES"] = $arAllPrices;
767 }
768
769 return $arIBlockElement;
770 }
771 }
772
773 return false;
774 }
775
784 public static function QuantityTracer($ProductID, $DeltaQuantity)
785 {
786 $boolClearCache = false;
787
788 $ProductID = (int)$ProductID;
789 if ($ProductID <= 0)
790 return false;
791 $DeltaQuantity = (float)$DeltaQuantity;
792 if ($DeltaQuantity==0)
793 return false;
794
795 $rsProducts = CCatalogProduct::GetList(
796 array(),
797 array('ID' => $ProductID),
798 false,
799 false,
800 array('ID', 'CAN_BUY_ZERO', 'NEGATIVE_AMOUNT_TRACE', 'QUANTITY_TRACE', 'QUANTITY', 'ELEMENT_IBLOCK_ID')
801 );
802 if (($arProduct = $rsProducts->Fetch())
803 && ($arProduct["QUANTITY_TRACE"]=="Y"))
804 {
805 $strAllowNegativeAmount = $arProduct["NEGATIVE_AMOUNT_TRACE"];
806
807 $arFields = array();
808 $arFields["QUANTITY"] = (float)$arProduct["QUANTITY"] - $DeltaQuantity;
809
810 if ('Y' != $arProduct['CAN_BUY_ZERO'])
811 {
812 if (defined("BX_COMP_MANAGED_CACHE"))
813 {
814 $boolClearCache = (0 >= $arFields["QUANTITY"]*$arProduct["QUANTITY"]);
815 }
816 }
817
818 if ('Y' != $arProduct['CAN_BUY_ZERO'] || 'Y' != $strAllowNegativeAmount)
819 {
820 if (0 >= $arFields["QUANTITY"])
821 $arFields["QUANTITY"] = 0;
822 }
823
824 $arFields['OLD_QUANTITY'] = $arProduct["QUANTITY"];
825 CCatalogProduct::Update($arProduct["ID"], $arFields);
826
827 if ($boolClearCache)
828 CIBlock::clearIblockTagCache($arProduct['ELEMENT_IBLOCK_ID']);
829
830 $arProduct['OLD_QUANTITY'] = $arFields['OLD_QUANTITY'];
831 $arProduct['QUANTITY'] = $arFields['QUANTITY'];
832 $arProduct['ALLOW_NEGATIVE_AMOUNT'] = $strAllowNegativeAmount;
833 $arProduct['DELTA'] = $DeltaQuantity;
834 foreach (GetModuleEvents("catalog", "OnProductQuantityTrace", true) as $arEvent)
835 {
836 ExecuteModuleEventEx($arEvent, array($arProduct["ID"], $arProduct));
837 }
838
839 return true;
840 }
841
842 return false;
843 }
844
851 public static function GetNearestQuantityPrice($productID, $quantity = 1, $arUserGroups = array())
852 {
853 static $eventOnGetExists = null;
854 static $eventOnResultExists = null;
855
856 global $APPLICATION;
857
858 if ($eventOnGetExists === true || $eventOnGetExists === null)
859 {
860 foreach (GetModuleEvents('catalog', 'OnGetNearestQuantityPrice', true) as $arEvent)
861 {
862 $eventOnGetExists = true;
863 $mxResult = ExecuteModuleEventEx(
864 $arEvent,
865 array(
866 $productID,
867 $quantity,
868 $arUserGroups
869 )
870 );
871 if ($mxResult !== true)
872 return $mxResult;
873 }
874 if ($eventOnGetExists === null)
875 $eventOnGetExists = false;
876 }
877
878 // Check input params
879 $productID = (int)$productID;
880 if ($productID <= 0)
881 {
882 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_PRODUCT_ID_ABSENT"), "NO_PRODUCT_ID");
883 return false;
884 }
885
886 $quantity = (float)$quantity;
887 if ($quantity <= 0)
888 {
889 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_QUANTITY_ABSENT"), "NO_QUANTITY");
890 return false;
891 }
892
893 if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|')
894 $arUserGroups = array((int)$arUserGroups);
895
896 if (!is_array($arUserGroups))
897 $arUserGroups = array();
898
899 if (!in_array(2, $arUserGroups))
900 $arUserGroups[] = 2;
901
902 $quantityDifference = -1;
903 $nearestQuantity = -1;
904
905 // Find nearest quantity
906 $priceTypeList = self::getAllowedPriceTypes($arUserGroups);
907 if (empty($priceTypeList))
908 return false;
909
911 'select' => array('ID', 'QUANTITY_FROM', 'QUANTITY_TO'),
912 'filter' => array(
913 '=PRODUCT_ID' => $productID,
914 '@CATALOG_GROUP_ID' => $priceTypeList,
915 )
916 ));
917 while ($arPriceList = $iterator->fetch())
918 {
919 $arPriceList['QUANTITY_FROM'] = (float)$arPriceList['QUANTITY_FROM'];
920 $arPriceList['QUANTITY_TO'] = (float)$arPriceList['QUANTITY_TO'];
921 if ($quantity >= $arPriceList["QUANTITY_FROM"]
922 && ($quantity <= $arPriceList["QUANTITY_TO"] || $arPriceList["QUANTITY_TO"] == 0))
923 {
924 $nearestQuantity = $quantity;
925 break;
926 }
927
928 if ($quantity < $arPriceList["QUANTITY_FROM"])
929 {
930 $nearestQuantity_tmp = $arPriceList["QUANTITY_FROM"];
931 $quantityDifference_tmp = $arPriceList["QUANTITY_FROM"] - $quantity;
932 }
933 else
934 {
935 $nearestQuantity_tmp = $arPriceList["QUANTITY_TO"];
936 $quantityDifference_tmp = $quantity - $arPriceList["QUANTITY_TO"];
937 }
938
939 if ($quantityDifference < 0 || $quantityDifference_tmp < $quantityDifference)
940 {
941 $quantityDifference = $quantityDifference_tmp;
942 $nearestQuantity = $nearestQuantity_tmp;
943 }
944 }
945 unset($arPriceList, $iterator);
946 unset($priceTypeList);
947
948 if ($eventOnResultExists === true || $eventOnResultExists === null)
949 {
950 foreach (GetModuleEvents('catalog', 'OnGetNearestQuantityPriceResult', true) as $arEvent)
951 {
952 $eventOnResultExists = true;
953 if (ExecuteModuleEventEx($arEvent, array(&$nearestQuantity)) === false)
954 return false;
955 }
956 if ($eventOnResultExists === null)
957 $eventOnResultExists = false;
958 }
959
960 return ($nearestQuantity > 0 ? $nearestQuantity : false);
961 }
962
973 public static function GetOptimalPrice($intProductID, $quantity = 1, $arUserGroups = array(), $renewal = "N", $priceList = array(), $siteID = false, $arDiscountCoupons = false)
974 {
975 static $eventOnGetExists = null;
976 static $eventOnResultExists = null;
977
978 global $APPLICATION;
979
980 if ($eventOnGetExists === true || $eventOnGetExists === null)
981 {
982 foreach (GetModuleEvents('catalog', 'OnGetOptimalPrice', true) as $arEvent)
983 {
984 $mxResult = ExecuteModuleEventEx(
985 $arEvent,
986 array(
987 $intProductID,
988 $quantity,
989 $arUserGroups,
990 $renewal,
991 $priceList,
992 $siteID,
993 $arDiscountCoupons
994 )
995 );
996 if ($mxResult === null)
997 {
998 continue;
999 }
1000 $eventOnGetExists = true;
1001 if ($mxResult !== true)
1002 {
1003 self::updateUserHandlerOptimalPrice(
1004 $mxResult,
1005 ['PRODUCT_ID' => $intProductID]
1006 );
1007 return $mxResult;
1008 }
1009 }
1010 if ($eventOnGetExists === null)
1011 $eventOnGetExists = false;
1012 }
1013
1014 $intProductID = (int)$intProductID;
1015 if ($intProductID <= 0)
1016 {
1017 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_PRODUCT_ID_ABSENT"), "NO_PRODUCT_ID");
1018 return false;
1019 }
1020
1021 $quantity = (float)$quantity;
1022 if ($quantity <= 0)
1023 {
1024 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_QUANTITY_ABSENT"), "NO_QUANTITY");
1025 return false;
1026 }
1027
1028 if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|')
1029 $arUserGroups = array((int)$arUserGroups);
1030
1031 if (!is_array($arUserGroups))
1032 $arUserGroups = array();
1033
1034 if (!in_array(2, $arUserGroups))
1035 $arUserGroups[] = 2;
1037
1038 $renewal = ($renewal == 'Y' ? 'Y' : 'N');
1039
1040 if ($siteID === false)
1041 $siteID = SITE_ID;
1042
1044 if (empty($resultCurrency))
1045 {
1046 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY"));
1047 return false;
1048 }
1049
1050 $intIBlockID = (int)CIBlockElement::GetIBlockByID($intProductID);
1051 if ($intIBlockID <= 0)
1052 {
1053 $APPLICATION->ThrowException(
1055 'BT_MOD_CATALOG_PROD_ERR_ELEMENT_ID_NOT_FOUND',
1056 array('#ID#' => $intProductID)
1057 ),
1058 'NO_ELEMENT'
1059 );
1060 return false;
1061 }
1062
1063 if (!isset($priceList) || !is_array($priceList))
1064 $priceList = array();
1065
1066 if (empty($priceList))
1067 {
1068 $priceTypeList = self::getAllowedPriceTypes($arUserGroups);
1069 if (empty($priceTypeList))
1070 return false;
1071
1073 'select' => array('ID', 'CATALOG_GROUP_ID', 'PRICE', 'CURRENCY', 'PRICE_SCALE'),
1074 'filter' => array(
1075 '=PRODUCT_ID' => $intProductID,
1076 '@CATALOG_GROUP_ID' => $priceTypeList,
1077 array(
1078 'LOGIC' => 'OR',
1079 '<=QUANTITY_FROM' => $quantity,
1080 '=QUANTITY_FROM' => null
1081 ),
1082 array(
1083 'LOGIC' => 'OR',
1084 '>=QUANTITY_TO' => $quantity,
1085 '=QUANTITY_TO' => null
1086 )
1087 ),
1088 'order' => array('CATALOG_GROUP_ID' => 'ASC')
1089 ));
1090 while ($row = $iterator->fetch())
1091 {
1092 $row['ELEMENT_IBLOCK_ID'] = $intIBlockID;
1093 $priceList[] = $row;
1094 }
1095 unset($row, $iterator);
1096 unset($priceTypeList);
1097 }
1098 else
1099 {
1100 foreach (array_keys($priceList) as $priceIndex)
1101 $priceList[$priceIndex]['ELEMENT_IBLOCK_ID'] = $intIBlockID;
1102 unset($priceIndex);
1103 }
1104
1105 if (empty($priceList))
1106 return false;
1107
1108 $vat = CCatalogProduct::GetVATDataByID($intProductID);
1109 if (!empty($vat))
1110 {
1111 if ($vat['EXCLUDE_VAT'] === 'N')
1112 {
1113 $vat['RATE'] = $vat['RATE'] * 0.01;
1114 }
1115 }
1116 else
1117 {
1118 $vat = [
1119 'RATE' => null,
1120 'VAT_INCLUDED' => 'N',
1121 'EXCLUDE_VAT' => 'Y',
1122 ];
1123 }
1124 unset($iterator);
1125
1128 if ($isNeedDiscounts)
1129 {
1130 if ($arDiscountCoupons === false)
1131 $arDiscountCoupons = CCatalogDiscountCoupon::GetCoupons();
1132 }
1133
1134 $minimalPrice = array();
1135
1136 if (self::$saleIncluded === null)
1138 $isNeedleToMinimizeCatalogGroup = self::isNeedleToMinimizeCatalogGroup($priceList);
1139
1140 foreach ($priceList as $priceData)
1141 {
1142 $priceData['VAT_RATE'] = $vat['RATE'];
1143 $priceData['VAT_INCLUDED'] = $vat['VAT_INCLUDED'];
1144 $priceData['NO_VAT'] = $vat['EXCLUDE_VAT'];
1145
1146 $currentPrice = (float)$priceData['PRICE'];
1147 if ($priceData['NO_VAT'] === 'N')
1148 {
1149 if ($priceData['VAT_INCLUDED'] === 'N')
1150 {
1151 $currentPrice *= (1 + $priceData['VAT_RATE']);
1152 }
1153 }
1154 if ($priceData['CURRENCY'] != $resultCurrency)
1155 $currentPrice = CCurrencyRates::ConvertCurrency($currentPrice, $priceData['CURRENCY'], $resultCurrency);
1156 $currentPrice = Catalog\Product\Price\Calculation::roundPrecision($currentPrice);
1157
1158 $result = array(
1159 'BASE_PRICE' => $currentPrice,
1160 'COMPARE_PRICE' => $currentPrice,
1161 'PRICE' => $currentPrice,
1162 'CURRENCY' => $resultCurrency,
1163 'DISCOUNT_LIST' => array(),
1164 'RAW_PRICE' => $priceData
1165 );
1166 if ($isNeedDiscounts)
1167 {
1168 $arDiscounts = CCatalogDiscount::GetDiscount(
1169 $intProductID,
1171 array($priceData['CATALOG_GROUP_ID']),
1172 $arUserGroups,
1173 $renewal,
1174 $siteID,
1175 $arDiscountCoupons
1176 );
1177
1178 $discountResult = CCatalogDiscount::applyDiscountList($currentPrice, $resultCurrency, $arDiscounts);
1179 unset($arDiscounts);
1180 if ($discountResult === false)
1181 return false;
1182 $result['PRICE'] = $discountResult['PRICE'];
1183 $result['COMPARE_PRICE'] = $discountResult['PRICE'];
1184 $result['DISCOUNT_LIST'] = $discountResult['DISCOUNT_LIST'];
1185 unset($discountResult);
1186 }
1187 elseif($isNeedleToMinimizeCatalogGroup)
1188 {
1189 $calculateData = $priceData;
1190 $calculateData['PRICE'] = $currentPrice;
1191 $calculateData['CURRENCY'] = $resultCurrency;
1192 $possibleSalePrice = self::getPossibleSalePrice(
1193 $intProductID,
1194 $calculateData,
1195 $quantity,
1196 $siteID,
1197 $arUserGroups,
1198 $arDiscountCoupons
1199 );
1200 unset($calculateData);
1201 if ($possibleSalePrice === null)
1202 return false;
1203 $result['COMPARE_PRICE'] = $possibleSalePrice;
1204 unset($possibleSalePrice);
1205 }
1206
1207 if ($priceData['NO_VAT'] === 'N')
1208 {
1209 if (!$resultWithVat)
1210 {
1211 $result['PRICE'] /= (1 + $priceData['VAT_RATE']);
1212 $result['COMPARE_PRICE'] /= (1 + $priceData['VAT_RATE']);
1213 $result['BASE_PRICE'] /= (1 + $priceData['VAT_RATE']);
1214 }
1215 }
1216
1217 $result['UNROUND_PRICE'] = $result['PRICE'];
1218 $result['UNROUND_BASE_PRICE'] = $result['BASE_PRICE'];
1219 if (Catalog\Product\Price\Calculation::isComponentResultMode())
1220 {
1221 $result['BASE_PRICE'] = Catalog\Product\Price::roundPrice(
1222 $priceData['CATALOG_GROUP_ID'],
1223 $result['BASE_PRICE'],
1224 $resultCurrency
1225 );
1226 $result['PRICE'] = Catalog\Product\Price::roundPrice(
1227 $priceData['CATALOG_GROUP_ID'],
1228 $result['PRICE'],
1229 $resultCurrency
1230 );
1231 if (
1232 empty($result['DISCOUNT_LIST'])
1233 || Catalog\Product\Price\Calculation::compare($result['BASE_PRICE'], $result['PRICE'], '<=')
1234 )
1235 {
1236 $result['BASE_PRICE'] = $result['PRICE'];
1237 }
1238 $result['COMPARE_PRICE'] = $result['PRICE'];
1239 }
1240
1241 if (empty($minimalPrice) || $minimalPrice['COMPARE_PRICE'] > $result['COMPARE_PRICE'])
1242 {
1243 $minimalPrice = $result;
1244 }
1245 elseif (
1246 $minimalPrice['COMPARE_PRICE'] == $result['COMPARE_PRICE']
1247 && $minimalPrice['RAW_PRICE']['PRICE_SCALE'] > $result['RAW_PRICE']['PRICE_SCALE']
1248 )
1249 {
1250 $minimalPrice = $result;
1251 }
1252
1253 unset($currentPrice, $result);
1254 }
1255 unset($priceData);
1256 unset($vat);
1257
1258 $discountValue = ($minimalPrice['BASE_PRICE'] - $minimalPrice['PRICE']);
1259
1260 if ($minimalPrice['RAW_PRICE']['NO_VAT'] === 'N')
1261 {
1262 $vatIncluded = $resultWithVat ? 'Y' : 'N';
1263 }
1264 else
1265 {
1266 $vatIncluded = 'N';
1267 }
1268 unset($minimalPrice['RAW_PRICE']['PRICE_SCALE']);
1269 $arResult = array(
1270 'PRICE' => $minimalPrice['RAW_PRICE'],
1271 'RESULT_PRICE' => array(
1272 'ID' => $minimalPrice['RAW_PRICE']['ID'],
1273 'PRICE_TYPE_ID' => $minimalPrice['RAW_PRICE']['CATALOG_GROUP_ID'],
1274 'BASE_PRICE' => $minimalPrice['BASE_PRICE'],
1275 'DISCOUNT_PRICE' => $minimalPrice['PRICE'],
1276 'CURRENCY' => $resultCurrency,
1277 'DISCOUNT' => $discountValue,
1278 'PERCENT' => (
1279 $minimalPrice['BASE_PRICE'] > 0 && $discountValue > 0
1280 ? round((100*$discountValue)/$minimalPrice['BASE_PRICE'], 0)
1281 : 0
1282 ),
1283 'VAT_RATE' => $minimalPrice['RAW_PRICE']['VAT_RATE'],
1284 'VAT_INCLUDED' => $vatIncluded,
1285 'NO_VAT' => $minimalPrice['RAW_PRICE']['NO_VAT'],
1286 'UNROUND_BASE_PRICE' => $minimalPrice['UNROUND_BASE_PRICE'],
1287 'UNROUND_DISCOUNT_PRICE' => $minimalPrice['UNROUND_PRICE']
1288 ),
1289 'DISCOUNT_PRICE' => $minimalPrice['PRICE'],
1290 'DISCOUNT' => array(),
1291 'DISCOUNT_LIST' => array(),
1292 'PRODUCT_ID' => $intProductID
1293 );
1294 if (!empty($minimalPrice['DISCOUNT_LIST']))
1295 {
1296 reset($minimalPrice['DISCOUNT_LIST']);
1297 $arResult['DISCOUNT'] = current($minimalPrice['DISCOUNT_LIST']);
1298 $arResult['DISCOUNT_LIST'] = $minimalPrice['DISCOUNT_LIST'];
1299 }
1300 unset($minimalPrice);
1301
1302 if ($eventOnResultExists === true || $eventOnResultExists === null)
1303 {
1304 foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent)
1305 {
1306 $eventOnResultExists = true;
1307 if (ExecuteModuleEventEx($arEvent, array(&$arResult)) === false)
1308 return false;
1309 }
1310 if ($eventOnResultExists === null)
1311 $eventOnResultExists = false;
1312 }
1313
1314 return $arResult;
1315 }
1316
1317 public static function GetOptimalPriceList(array $products, $arUserGroups = array(), $renewal = "N", $priceList = array(), $siteID = false, $needCoupons = true)
1318 {
1319 $needCoupons = ($needCoupons === true);
1320
1321 $resultList = array();
1322
1323 $iblockListId = array();
1324 $productIblockGetIdList = array();
1325 $ignoreList = array();
1326
1328
1329 foreach ($products as $productId => $productData)
1330 {
1332 array(
1333 'USE_DISCOUNTS' => (isset($productData['BUNDLE_CHILD']) && $productData['BUNDLE_CHILD'] === true ? false : $useDiscount),
1334 )
1335 );
1336
1337 foreach (GetModuleEvents('catalog', 'OnGetOptimalPrice', true) as $arEvent)
1338 {
1339 if (!empty($productData['QUANTITY_LIST']))
1340 {
1341 foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
1342 {
1343 //TODO: remove this hack after refactoring new provider
1344 if ($quantity <= 0)
1345 continue;
1346 $mxResult = ExecuteModuleEventEx(
1347 $arEvent,
1348 array(
1349 $productId,
1350 $quantity,
1351 $arUserGroups,
1352 $renewal,
1353 $priceList,
1354 $siteID,
1355 $needCoupons ? false : array()
1356 )
1357 );
1358 if ($mxResult === null)
1359 {
1360 continue 2;
1361 }
1362 if ($mxResult !== true)
1363 {
1364 self::updateUserHandlerOptimalPrice(
1365 $mxResult,
1366 ['PRODUCT_ID' => $productId]
1367 );
1368 $resultList[$productId][$productData['BASKET_CODE']] = $mxResult;
1369 $ignoreList[$productId."|".$quantity] = true;
1370 continue 3;
1371 }
1372 }
1373 }
1374 }
1375
1376 if (!empty($productData['QUANTITY_LIST']))
1377 {
1378 foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
1379 {
1380 $resultList[$productId][$basketCode] = false;
1381 }
1382 }
1383 else
1384 {
1385 $resultList[$productId][$productData['BASKET_CODE']] = false;
1386 }
1387
1388 if (!isset($iblockListId[$productId]) && isset($productData['IBLOCK_ID']) && $productData['IBLOCK_ID'] > 0)
1389 {
1390 $iblockListId[$productId] = $productData['IBLOCK_ID'];
1391 }
1392
1393 if (!isset($iblockListId[$productId]))
1394 {
1395 $productIblockGetIdList[] = $productId;
1396 }
1397 }
1398
1399 global $APPLICATION;
1400
1401 if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|')
1402 $arUserGroups = array((int)$arUserGroups);
1403
1404 if (!is_array($arUserGroups))
1405 $arUserGroups = array();
1406
1407 if (!in_array(2, $arUserGroups))
1408 $arUserGroups[] = 2;
1410
1411 $renewal = ($renewal == 'Y' ? 'Y' : 'N');
1412
1413 if ($siteID === false)
1414 $siteID = SITE_ID;
1415
1417 if (empty($resultCurrency))
1418 {
1419 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY"));
1420 return false;
1421 }
1422
1423 if (!empty($productIblockGetIdList))
1424 {
1425 $iblockIdList = CIBlockElement::GetIBlockByIDList($productIblockGetIdList);
1426 if (!empty($iblockIdList) && is_array($iblockIdList))
1427 {
1428 $iblockListId = $iblockIdList + $iblockListId;
1429 }
1430 }
1431
1432 if (!isset($priceList) || !is_array($priceList))
1433 $priceList = array();
1434
1435 if (empty($priceList))
1436 {
1437 $priceTypeList = self::getAllowedPriceTypes($arUserGroups);
1438 if (empty($priceTypeList))
1439 {
1440 if (!empty($resultList))
1441 {
1442 return $resultList;
1443 }
1444
1445 return false;
1446 }
1447
1449 'select' => array(
1450 'ID', 'PRODUCT_ID', 'CATALOG_GROUP_ID',
1451 'PRICE', 'CURRENCY', 'QUANTITY_FROM', 'QUANTITY_TO', 'PRICE_SCALE'
1452 ),
1453 'filter' => array(
1454 '=PRODUCT_ID' => array_keys($products),
1455 '@CATALOG_GROUP_ID' => $priceTypeList
1456 ),
1457 ));
1458 while ($row = $iterator->fetch())
1459 {
1460 $row['ELEMENT_IBLOCK_ID'] = $iblockListId[$row['PRODUCT_ID']];
1461
1462 if (isset($products[$row['PRODUCT_ID']]))
1463 {
1464 $productData = $products[$row['PRODUCT_ID']];
1465 if (!empty($productData['QUANTITY_LIST']))
1466 {
1467 foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
1468 {
1469 if(isset($ignoreList[$row['PRODUCT_ID']."|".$quantity]))
1470 {
1471 continue 2;
1472 }
1473 }
1474 }
1475
1476 $quantityList = array();
1477 if (!empty($productData['QUANTITY']))
1478 {
1479 $quantityList = array($productData['QUANTITY']);
1480 }
1481
1482 if (!empty($productData['QUANTITY_LIST']))
1483 {
1484 $quantityList = $productData['QUANTITY_LIST'];
1485 }
1486
1487 foreach ($quantityList as $basketCode => $quantity)
1488 {
1489 $checkQuantity = abs(floatval($quantity));
1490 if (($row['QUANTITY_FROM'] <= $checkQuantity || empty($row['QUANTITY_FROM']))
1491 && ($row['QUANTITY_TO'] >= $checkQuantity || empty($row['QUANTITY_TO'])))
1492 {
1493 $row['QUANTITY'] = floatval($quantity);
1494 $row['BASKET_CODE'] = $basketCode;
1495 $priceList[] = $row;
1496 }
1497 }
1498 }
1499 }
1500 unset($row, $iterator);
1501 unset($cacheKey);
1502 }
1503 else
1504 {
1505 foreach ($priceList as $priceIndex => $priceData)
1506 {
1507 $priceList[$priceIndex]['ELEMENT_IBLOCK_ID'] = $iblockListId[$priceData['PRODUCT_ID']];
1508 }
1509 unset($priceIndex);
1510 }
1511
1512 if (empty($priceList))
1513 {
1514 if (!empty($resultList))
1515 {
1516 return $resultList;
1517 }
1518
1519 return false;
1520 }
1521
1522 Main\Type\Collection::sortByColumn($priceList, ['BASKET_CODE' => SORT_ASC, 'CATALOG_GROUP_ID' => SORT_ASC]);
1523
1524 $vatList = CCatalogProduct::GetVATDataByIDList(array_keys($products));
1525 if (!empty($vatList))
1526 {
1527 foreach ($vatList as $productId => $vatValue)
1528 {
1529 if ($vatValue === false)
1530 {
1531 $vatList[$productId] = [
1532 'RATE' => null,
1533 'VAT_INCLUDED' => 'N',
1534 'EXCLUDE_VAT' => 'Y',
1535 ];
1536 }
1537 else
1538 {
1539 if ($vatValue['EXCLUDE_VAT'] === 'N')
1540 {
1541 $vatList[$productId]['RATE'] = $vatValue['RATE'] * 0.01;
1542 }
1543 }
1544 }
1545 }
1546
1549
1550 $discountList = array();
1551
1552 if (self::$saleIncluded === null)
1554 $isNeedleToMinimizeCatalogGroup = self::isNeedleToMinimizeCatalogGroup($priceList);
1555
1556 $lastProductId = false;
1557 $lastBasketCode = false;
1558 $ignoreProductIdList = array();
1559 $coupons = array();
1560 $minimalPrice = array();
1561
1562 foreach ($priceList as $priceData)
1563 {
1564 $productId = $priceData['PRODUCT_ID'];
1565 $basketCode = $priceData['BASKET_CODE'];
1566
1567 if (in_array($productId, $ignoreProductIdList))
1568 {
1569 continue;
1570 }
1571
1572 if ($lastBasketCode != $basketCode)
1573 {
1574 if ($lastBasketCode !== false)
1575 {
1576 foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent)
1577 {
1578 if (ExecuteModuleEventEx($arEvent, array(&$resultList[$lastProductId][$lastBasketCode])) === false)
1579 {
1580 continue;
1581 }
1582 }
1583
1584 $productHash = array(
1585 'MODULE' => 'catalog',
1586 'PRODUCT_ID' => $lastProductId,
1587 'BASKET_ID' => $lastBasketCode
1588 );
1589 if (!empty($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST']))
1590 {
1591 $applyCoupons = array();
1592 foreach ($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'] as $discount)
1593 {
1594 if (!empty($discount['COUPON']))
1595 {
1596 $applyCoupons[] = $discount['COUPON'];
1597 }
1598 }
1599 if (!empty($applyCoupons))
1600 {
1601 $resultApply = Sale\DiscountCouponsManager::setApplyByProduct($productHash, $applyCoupons);
1602 }
1603 }
1604 }
1605
1606 if ($isNeedDiscounts && $needCoupons)
1607 {
1608 $coupons = static::getCoupons($productId, $basketCode);
1609 }
1610
1611 $lastBasketCode = $basketCode;
1612 $lastProductId = $productId;
1613
1615 array(
1616 'USE_DISCOUNTS' => (isset($products[$productId]['BUNDLE_CHILD']) && $products[$productId]['BUNDLE_CHILD'] === true ? false : $useDiscount),
1617 )
1618 );
1620 }
1621
1622 $vat = $vatList[$priceData['PRODUCT_ID']];
1623
1624 $priceData['VAT_RATE'] = $vat['RATE'];
1625 $priceData['VAT_INCLUDED'] = $vat['VAT_INCLUDED'];
1626 $priceData['NO_VAT'] = $vat['EXCLUDE_VAT'];
1627
1628 $currentPrice = (float)$priceData['PRICE'];
1629 if ($priceData['NO_VAT'] === 'N')
1630 {
1631 if ($priceData['VAT_INCLUDED'] == 'N')
1632 {
1633 $currentPrice *= (1 + $priceData['VAT_RATE']);
1634 }
1635 }
1636
1637 if ($priceData['CURRENCY'] != $resultCurrency)
1638 $currentPrice = CCurrencyRates::ConvertCurrency($currentPrice, $priceData['CURRENCY'], $resultCurrency);
1639 $currentPrice = Catalog\Product\Price\Calculation::roundPrecision($currentPrice);
1640
1641 $result = array(
1642 'BASE_PRICE' => $currentPrice,
1643 'COMPARE_PRICE' => $currentPrice,
1644 'PRICE' => $currentPrice,
1645 'CURRENCY' => $resultCurrency,
1646 'DISCOUNT_LIST' => array(),
1647 'RAW_PRICE' => $priceData
1648 );
1649
1650 if ($isNeedDiscounts)
1651 {
1652 $discountList[$priceData['PRODUCT_ID']] = \CCatalogDiscount::GetDiscount(
1653 $productId,
1654 $iblockListId[$priceData['PRODUCT_ID']],
1655 array($priceData['CATALOG_GROUP_ID']),
1656 $arUserGroups,
1657 $renewal,
1658 $siteID,
1659 $coupons
1660 );
1661
1662 $discountResult = \CCatalogDiscount::applyDiscountList($currentPrice, $resultCurrency, $discountList[$priceData['PRODUCT_ID']]);
1663 if ($discountResult === false)
1664 {
1665 $ignoreProductIdList[] = $productId;
1666 $resultList[$productId][$basketCode] = false;
1667 continue;
1668 }
1669
1670 $result['PRICE'] = $discountResult['PRICE'];
1671 $result['COMPARE_PRICE'] = $discountResult['PRICE'];
1672 $result['DISCOUNT_LIST'] = $discountResult['DISCOUNT_LIST'];
1673 unset($discountResult);
1674 }
1675 elseif($isNeedleToMinimizeCatalogGroup)
1676 {
1677 if (!isset($products[$productId]['QUANTITY_LIST'][$basketCode]))
1678 continue;
1679
1680 $calculateData = $priceData;
1681 $calculateData['PRICE'] = $currentPrice;
1682 $calculateData['CURRENCY'] = $resultCurrency;
1683 $possibleSalePrice = self::getPossibleSalePrice(
1684 $productId,
1685 $calculateData,
1686 $products[$productId]['QUANTITY_LIST'][$basketCode],
1687 $siteID,
1688 $arUserGroups,
1689 ($needCoupons ? false: [])
1690 );
1691 unset($calculateData);
1692 if ($possibleSalePrice === null)
1693 continue;
1694 $result['COMPARE_PRICE'] = $possibleSalePrice;
1695 unset($possibleSalePrice);
1696 }
1697
1698 if ($priceData['NO_VAT'] === 'N')
1699 {
1700 if (!$resultWithVat)
1701 {
1702 $result['PRICE'] /= (1 + $priceData['VAT_RATE']);
1703 $result['COMPARE_PRICE'] /= (1 + $priceData['VAT_RATE']);
1704 $result['BASE_PRICE'] /= (1 + $priceData['VAT_RATE']);
1705 }
1706 }
1707
1708 $result['UNROUND_PRICE'] = $result['PRICE'];
1709 $result['UNROUND_BASE_PRICE'] = $result['BASE_PRICE'];
1710 if (Catalog\Product\Price\Calculation::isComponentResultMode())
1711 {
1712 $result['BASE_PRICE'] = Catalog\Product\Price::roundPrice(
1713 $priceData['CATALOG_GROUP_ID'],
1714 $result['BASE_PRICE'],
1715 $resultCurrency
1716 );
1717 $result['PRICE'] = Catalog\Product\Price::roundPrice(
1718 $priceData['CATALOG_GROUP_ID'],
1719 $result['PRICE'],
1720 $resultCurrency
1721 );
1722 if (
1723 empty($result['DISCOUNT_LIST'])
1724 || Catalog\Product\Price\Calculation::compare($result['BASE_PRICE'], $result['PRICE'], '<=')
1725 )
1726 {
1727 $result['BASE_PRICE'] = $result['PRICE'];
1728 }
1729 $result['COMPARE_PRICE'] = $result['PRICE'];
1730 }
1731
1732 if (
1733 empty($minimalPrice[$basketCode])
1734 || $minimalPrice[$basketCode]['COMPARE_PRICE'] > $result['COMPARE_PRICE']
1735 )
1736 {
1737 $minimalPrice[$basketCode] = $result;
1738 }
1739 elseif (
1740 $minimalPrice[$basketCode]['COMPARE_PRICE'] == $result['COMPARE_PRICE']
1741 && $minimalPrice[$basketCode]['RAW_PRICE']['PRICE_SCALE'] > $result['RAW_PRICE']['PRICE_SCALE']
1742 )
1743 {
1744 $minimalPrice[$basketCode] = $result;
1745 }
1746
1747 unset($currentPrice, $result);
1748
1749 $discountValue = ($minimalPrice[$basketCode]['BASE_PRICE'] - $minimalPrice[$basketCode]['PRICE']);
1750
1751 if ($minimalPrice[$basketCode]['RAW_PRICE']['NO_VAT'] === 'N')
1752 {
1753 $vatIncluded = $resultWithVat ? 'Y' : 'N';
1754 }
1755 else
1756 {
1757 $vatIncluded = 'N';
1758 }
1759 unset($minimalPrice[$basketCode]['RAW_PRICE']['PRICE_SCALE']);
1760 $productResult = array(
1761 'PRICE' => $minimalPrice[$basketCode]['RAW_PRICE'],
1762 'RESULT_PRICE' => array(
1763 'ID' => $minimalPrice[$basketCode]['RAW_PRICE']['ID'],
1764 'PRICE_TYPE_ID' => $minimalPrice[$basketCode]['RAW_PRICE']['CATALOG_GROUP_ID'],
1765 'BASE_PRICE' => $minimalPrice[$basketCode]['BASE_PRICE'],
1766 'DISCOUNT_PRICE' => $minimalPrice[$basketCode]['PRICE'],
1767 'CURRENCY' => $resultCurrency,
1768 'DISCOUNT' => $discountValue,
1769 'PERCENT' => (
1770 $minimalPrice[$basketCode]['BASE_PRICE'] > 0 && $discountValue > 0
1771 ? round((100 * $discountValue)/$minimalPrice[$basketCode]['BASE_PRICE'], 0)
1772 : 0
1773 ),
1774 'VAT_RATE' => $minimalPrice[$basketCode]['RAW_PRICE']['VAT_RATE'],
1775 'VAT_INCLUDED' => $vatIncluded,
1776 'NO_VAT' => $minimalPrice[$basketCode]['RAW_PRICE']['NO_VAT'],
1777 'UNROUND_BASE_PRICE' => $minimalPrice[$basketCode]['UNROUND_BASE_PRICE'],
1778 'UNROUND_DISCOUNT_PRICE' => $minimalPrice[$basketCode]['UNROUND_PRICE']
1779 ),
1780 'DISCOUNT_PRICE' => $minimalPrice[$basketCode]['PRICE'],
1781 'DISCOUNT' => array(),
1782 'DISCOUNT_LIST' => array(),
1783 'PRODUCT_ID' => $productId
1784 );
1785
1786 if (!empty($minimalPrice[$basketCode]['DISCOUNT_LIST']))
1787 {
1788 reset($minimalPrice[$basketCode]['DISCOUNT_LIST']);
1789 $productResult['DISCOUNT'] = current($minimalPrice[$basketCode]['DISCOUNT_LIST']);
1790 $productResult['DISCOUNT_LIST'] = $minimalPrice[$basketCode]['DISCOUNT_LIST'];
1791 }
1792
1793 $resultList[$productId][$priceData['BASKET_CODE']] = $productResult;
1794
1795 }
1796 unset($minimalPrice);
1797 unset($priceData);
1798 unset($vat);
1799
1800 if ($lastBasketCode !== false)
1801 {
1802 foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent)
1803 {
1804 if (ExecuteModuleEventEx($arEvent, array(&$resultList[$lastProductId][$lastBasketCode])) === false)
1805 {
1806 break;
1807 }
1808 }
1809
1810 $productHash = array(
1811 'MODULE' => 'catalog',
1812 'PRODUCT_ID' => $lastProductId,
1813 'BASKET_ID' => $lastBasketCode
1814 );
1815 if (!empty($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST']))
1816 {
1817 $applyCoupons = array();
1818 foreach ($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'] as $discount)
1819 {
1820 if (!empty($discount['COUPON']))
1821 {
1822 $applyCoupons[] = $discount['COUPON'];
1823 }
1824 }
1825 if (!empty($applyCoupons))
1826 {
1827 Sale\DiscountCouponsManager::setApplyByProduct($productHash, $applyCoupons);
1828 }
1829 }
1830 }
1831
1832 return $resultList;
1833 }
1834
1841 private static function getCoupons($productId, $basketCode)
1842 {
1843 $productHash = array(
1844 'MODULE' => 'catalog',
1845 'PRODUCT_ID' => $productId,
1846 'BASKET_ID' => $basketCode
1847 );
1848 $coupons = Sale\DiscountCouponsManager::getForApply(array('MODULE_ID' => 'catalog'), $productHash);
1849 if (!empty($coupons))
1850 {
1851 $coupons = array_keys($coupons);
1852 }
1853
1854 return $coupons;
1855 }
1856
1863 public static function CountPriceWithDiscount($price, $currency, $discounts)
1864 {
1865 static $eventOnGetExists = null;
1866 static $eventOnResultExists = null;
1867
1868 if ($eventOnGetExists === true || $eventOnGetExists === null)
1869 {
1870 foreach (GetModuleEvents('catalog', 'OnCountPriceWithDiscount', true) as $arEvent)
1871 {
1872 $eventOnGetExists = true;
1873 $mxResult = ExecuteModuleEventEx($arEvent, array($price, $currency, $discounts));
1874 if ($mxResult !== true)
1875 return $mxResult;
1876 }
1877 if ($eventOnGetExists === null)
1878 $eventOnGetExists = false;
1879 }
1880
1882 if ($currency === false)
1883 return false;
1884
1885 $price = (float)$price;
1886 if ($price <= 0)
1887 return $price;
1888
1889 $currentMinPrice = $price;
1890 if (!empty($discounts) && is_array($discounts))
1891 {
1893 if ($result === false)
1894 return false;
1895
1896 $currentMinPrice = $result['PRICE'];
1897 }
1898
1899 if ($eventOnResultExists === true || $eventOnResultExists === null)
1900 {
1901 foreach (GetModuleEvents('catalog', 'OnCountPriceWithDiscountResult', true) as $arEvent)
1902 {
1903 $eventOnResultExists = true;
1904 if (ExecuteModuleEventEx($arEvent, array(&$currentMinPrice)) === false)
1905 return false;
1906 }
1907 if ($eventOnResultExists === null)
1908 $eventOnResultExists = false;
1909 }
1910
1911 return $currentMinPrice;
1912 }
1913
1914 public static function GetProductSections($ID)
1915 {
1917 global $stackCacheManager;
1918
1919 $ID = (int)$ID;
1920 if ($ID <= 0)
1921 return false;
1922
1923 $cacheTime = CATALOG_CACHE_DEFAULT_TIME;
1924 if (defined('CATALOG_CACHE_TIME'))
1925 $cacheTime = intval(CATALOG_CACHE_TIME);
1926
1927 $arProductSections = array();
1928
1929 $dbElementSections = CIBlockElement::GetElementGroups($ID, false, array('ID', 'ADDITIONAL_PROPERTY_ID'));
1930 while ($arElementSections = $dbElementSections->Fetch())
1931 {
1932 if ((int)$arElementSections['ADDITIONAL_PROPERTY_ID'] > 0)
1933 continue;
1934 $arSectionsTmp = array();
1935
1936 $strCacheKey = "p".$arElementSections["ID"];
1937
1938 $stackCacheManager->SetLength("catalog_group_parents", 50);
1939 $stackCacheManager->SetTTL("catalog_group_parents", $cacheTime);
1940 if ($stackCacheManager->Exist("catalog_group_parents", $strCacheKey))
1941 {
1942 $arSectionsTmp = $stackCacheManager->Get("catalog_group_parents", $strCacheKey);
1943 }
1944 else
1945 {
1946 $dbSection = CIBlockSection::GetList(
1947 array(),
1948 array('ID' => $arElementSections["ID"]),
1949 false,
1950 array(
1951 'ID',
1952 'IBLOCK_ID',
1953 'LEFT_MARGIN',
1954 'RIGHT_MARGIN',
1955 )
1956 );
1957 if ($arSection = $dbSection->Fetch())
1958 {
1959 $dbSectionTree = CIBlockSection::GetList(
1960 array("LEFT_MARGIN" => "DESC"),
1961 array(
1962 "IBLOCK_ID" => $arSection["IBLOCK_ID"],
1963 "ACTIVE" => "Y",
1964 "GLOBAL_ACTIVE" => "Y",
1965 "IBLOCK_ACTIVE" => "Y",
1966 "<=LEFT_BORDER" => $arSection["LEFT_MARGIN"],
1967 ">=RIGHT_BORDER" => $arSection["RIGHT_MARGIN"]
1968 ),
1969 false,
1970 array('ID')
1971 );
1972 while ($arSectionTree = $dbSectionTree->Fetch())
1973 {
1974 $arSectionTree["ID"] = intval($arSectionTree["ID"]);
1975 $arSectionsTmp[] = $arSectionTree["ID"];
1976 }
1977 unset($arSectionTree, $dbSectionTree);
1978 }
1979 unset($arSection, $dbSection);
1980
1981 $stackCacheManager->Set("catalog_group_parents", $strCacheKey, $arSectionsTmp);
1982 }
1983
1984 $arProductSections = array_merge($arProductSections, $arSectionsTmp);
1985 }
1986 unset($arElementSections, $dbElementSections);
1987
1988 $arProductSections = array_unique($arProductSections);
1989
1990 return $arProductSections;
1991 }
1992
1993 public static function OnIBlockElementDelete($ProductID)
1994 {
1996
1997 return $result->isSuccess();
1998 }
1999
2005 public static function OnAfterIBlockElementUpdate($arFields) {}
2006
2007 public static function CheckProducts($arItemIDs)
2008 {
2009 if (!is_array($arItemIDs))
2010 $arItemIDs = array($arItemIDs);
2012 if (empty($arItemIDs))
2013 return false;
2014 $arProductList = array();
2015 $rsProducts = CCatalogProduct::GetList(
2016 array(),
2017 array('@ID' => $arItemIDs),
2018 false,
2019 false,
2020 array('ID')
2021 );
2022 while ($arProduct = $rsProducts->Fetch())
2023 {
2024 $arProduct['ID'] = (int)$arProduct['ID'];
2025 $arProductList[$arProduct['ID']] = true;
2026 }
2027 if (empty($arProductList))
2028 return false;
2029 $boolFlag = true;
2030 foreach ($arItemIDs as &$intItemID)
2031 {
2032 if (!isset($arProductList[$intItemID]))
2033 {
2034 $boolFlag = false;
2035 break;
2036 }
2037 }
2038 unset($intItemID);
2039 return $boolFlag;
2040 }
2041
2051 public static function GetQueryBuildArrays($order, $filter, $select)
2052 {
2053 $result = [
2054 'SELECT' => '',
2055 'FROM' => '',
2056 'WHERE' => '',
2057 'ORDER' => []
2058 ];
2059
2060 $getListParameters = [];
2061 if (!empty($select) && is_array($select))
2062 $getListParameters['select'] = $select;
2063 if (!empty($filter) && is_array($filter))
2064 $getListParameters['filter'] = $filter;
2065 if (!empty($order) && is_array($order))
2066 $getListParameters['order'] = $order;
2067
2068 $query = \CProductQueryBuilder::makeQuery($getListParameters);
2069 if (!empty($query))
2070 {
2071 if (!empty($query['select']))
2072 $result['SELECT'] = ', '.implode(', ', $query['select']).' ';
2073 if (!empty($query['join']))
2074 $result['FROM'] = ' '.implode(' ', $query['join']).' ';
2075 if (!empty($query['filter']))
2076 $result['WHERE'] = ' and '.implode(' and ', $query['filter']);
2077 if (!empty($query['order']))
2078 $result['ORDER'] = $query['order'];
2079 }
2080 unset($query);
2081
2082 return $result;
2083 }
2084
2094 public static function GetTimePeriodTypes($boolFull = false)
2095 {
2097 }
2098
2106 private static function updateUserHandlerOptimalPrice(&$userResult, array $params)
2107 {
2108 global $APPLICATION;
2109
2110 if (empty($userResult) || !is_array($userResult))
2111 {
2112 $userResult = false;
2113 return;
2114 }
2115 if (
2116 (empty($userResult['PRICE']) || !is_array($userResult['PRICE']))
2117 && ((empty($userResult['RESULT_PRICE']) || !is_array($userResult['RESULT_PRICE'])))
2118 )
2119 {
2120 $userResult = false;
2121 return;
2122 }
2123
2124 $resultCurrency = Catalog\Product\Price\Calculation::getCurrency();
2125 if (empty($resultCurrency))
2126 {
2127 $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY"));
2128 $userResult = false;
2129 return;
2130 }
2131
2132 if (!isset($userResult['PRODUCT_ID']))
2133 $userResult['PRODUCT_ID'] = $params['PRODUCT_ID'];
2134
2135 $oldDiscountExist = !empty($userResult['DISCOUNT']) && is_array($userResult['DISCOUNT']);
2136 if ($oldDiscountExist)
2137 {
2138 if (empty($userResult['DISCOUNT']['MODULE_ID']))
2139 $userResult['DISCOUNT']['MODULE_ID'] = 'catalog';
2140 if ($userResult['DISCOUNT']['CURRENCY'] != $resultCurrency)
2141 Catalog\DiscountTable::convertCurrency($userResult['DISCOUNT'], $resultCurrency);
2142 }
2143
2144 if (!isset($userResult['DISCOUNT_LIST']) || !is_array($userResult['DISCOUNT_LIST']))
2145 {
2146 $userResult['DISCOUNT_LIST'] = [];
2147 if ($oldDiscountExist)
2148 $userResult['DISCOUNT_LIST'][] = $userResult['DISCOUNT'];
2149 }
2150 unset($oldDiscountExist);
2151
2152 foreach ($userResult['DISCOUNT_LIST'] as &$discount)
2153 {
2154 if (empty($discount['MODULE_ID']))
2155 $discount['MODULE_ID'] = 'catalog';
2156 if ($discount['CURRENCY'] != $resultCurrency)
2157 Catalog\DiscountTable::convertCurrency($discount, $resultCurrency);
2158 }
2159 unset($discount);
2160
2161 if (isset($userResult['PRICE']) && is_array($userResult['PRICE']))
2162 {
2163 if (!isset($userResult['PRICE']['VAT_RATE']))
2164 {
2165 $vat = CCatalogProduct::GetVATDataByID($userResult['PRODUCT_ID']);
2166 if (!empty($vat))
2167 $vat['RATE'] = (float)$vat['RATE'] * 0.01;
2168 else
2169 $vat = ['RATE' => 0.0, 'VAT_INCLUDED' => 'Y'];
2170 $userResult['PRICE']['VAT_RATE'] = $vat['RATE'];
2171 $userResult['PRICE']['VAT_INCLUDED'] = $vat['VAT_INCLUDED'];
2172 unset($vat);
2173 }
2174 }
2175 if (empty($userResult['RESULT_PRICE']) || !is_array($userResult['RESULT_PRICE']))
2176 {
2177 $userResult['RESULT_PRICE'] = CCatalogDiscount::calculateDiscountList(
2178 $userResult['PRICE'],
2179 $resultCurrency,
2180 $userResult['DISCOUNT_LIST'],
2181 Catalog\Product\Price\Calculation::isIncludingVat()
2182 );
2183 }
2184
2185 if (!isset($userResult['RESULT_PRICE']['CURRENCY']))
2186 $userResult['RESULT_PRICE']['CURRENCY'] = $resultCurrency;
2187
2188 if (!isset($userResult['RESULT_PRICE']['PRICE_TYPE_ID']))
2189 {
2190 if (isset($userResult['PRICE']['CATALOG_GROUP_ID']))
2191 $userResult['RESULT_PRICE']['PRICE_TYPE_ID'] = $userResult['PRICE']['CATALOG_GROUP_ID'];
2192 }
2193
2194 if (!isset($userResult['RESULT_PRICE']['ID']))
2195 {
2196 if (isset($userResult['PRICE']['ID']))
2197 {
2198 $userResult['RESULT_PRICE']['ID'] = $userResult['PRICE']['ID'];
2199 }
2200 }
2201
2202 $componentResultMode = Catalog\Product\Price\Calculation::isComponentResultMode();
2203
2204 if (!isset($userResult['RESULT_PRICE']['UNROUND_DISCOUNT_PRICE']))
2205 {
2206 $userResult['RESULT_PRICE']['UNROUND_DISCOUNT_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE'];
2207 if ($componentResultMode)
2208 {
2209 $userResult['RESULT_PRICE']['DISCOUNT_PRICE'] = Catalog\Product\Price::roundPrice(
2210 $userResult['RESULT_PRICE']['PRICE_TYPE_ID'],
2211 $userResult['RESULT_PRICE']['DISCOUNT_PRICE'],
2212 $userResult['RESULT_PRICE']['CURRENCY']
2213 );
2214 }
2215 }
2216
2217 if (!isset($userResult['RESULT_PRICE']['UNROUND_BASE_PRICE']))
2218 {
2219 $userResult['RESULT_PRICE']['UNROUND_BASE_PRICE'] = $userResult['RESULT_PRICE']['BASE_PRICE'];
2220 if ($componentResultMode)
2221 {
2222 $userResult['RESULT_PRICE']['BASE_PRICE'] = Catalog\Product\Price::roundPrice(
2223 $userResult['RESULT_PRICE']['PRICE_TYPE_ID'],
2224 $userResult['RESULT_PRICE']['BASE_PRICE'],
2225 $userResult['RESULT_PRICE']['CURRENCY']
2226 );
2227 }
2228 }
2229
2230 if ($componentResultMode)
2231 {
2232 if (
2233 empty($userResult['DISCOUNT_LIST'])
2234 || Catalog\Product\Price\Calculation::compare(
2235 $userResult['RESULT_PRICE']['BASE_PRICE'],
2236 $userResult['RESULT_PRICE']['DISCOUNT_PRICE'],
2237 '<='
2238 ))
2239 {
2240 $userResult['RESULT_PRICE']['BASE_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE'];
2241 }
2242 }
2243
2244 $discountValue = $userResult['RESULT_PRICE']['BASE_PRICE'] - $userResult['RESULT_PRICE']['DISCOUNT_PRICE'];
2245 $userResult['RESULT_PRICE']['DISCOUNT'] = $discountValue;
2246 $userResult['RESULT_PRICE']['PERCENT'] = (
2247 $userResult['RESULT_PRICE']['BASE_PRICE'] > 0 && $discountValue > 0
2248 ? round((100*$discountValue)/$userResult['RESULT_PRICE']['BASE_PRICE'], 0)
2249 : 0
2250 );
2251 unset($discountValue);
2252
2253 if (!isset($userResult['RESULT_PRICE']['VAT_RATE']))
2254 {
2255 if (isset($userResult['PRICE']['VAT_RATE']))
2256 {
2257 $userResult['RESULT_PRICE']['VAT_RATE'] = $userResult['PRICE']['VAT_RATE'];
2258 $userResult['RESULT_PRICE']['VAT_INCLUDED'] = $userResult['PRICE']['VAT_INCLUDED'];
2259 }
2260 else
2261 {
2262 $vat = CCatalogProduct::GetVATDataByID($userResult['PRODUCT_ID']);
2263 if (!empty($vat))
2264 $vat['RATE'] = (float)$vat['RATE'] * 0.01;
2265 else
2266 $vat = ['RATE' => 0.0, 'VAT_INCLUDED' => 'Y'];
2267 $userResult['RESULT_PRICE']['VAT_RATE'] = $vat['RATE'];
2268 $userResult['RESULT_PRICE']['VAT_INCLUDED'] = $vat['VAT_INCLUDED'];
2269 unset($vat);
2270 }
2271 }
2272
2273 $userResult['DISCOUNT_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE'];
2274 }
2275
2288 protected static function __PrimaryDiscountFilter(&$arDiscount, &$arPriceDiscount, &$arDiscSave, &$arParams)
2289 {
2290 if (isset($arParams['PRICE']) && isset($arParams['CURRENCY']))
2291 {
2292 $arParams['PRICE'] = (float)$arParams['PRICE'];
2293 $arParams['BASE_PRICE'] = $arParams['PRICE'];
2294 if ($arParams['PRICE'] > 0)
2295 {
2296 $arPriceDiscount = array();
2297 $arDiscSave = array();
2298
2299 foreach ($arDiscount as $arOneDiscount)
2300 {
2301 $changeData = ($arParams['CURRENCY'] != $arOneDiscount['CURRENCY']);
2303 $dblDiscountValue = 0.0;
2304 $arOneDiscount['PRIORITY'] = (int)$arOneDiscount['PRIORITY'];
2305 if (CCatalogDiscount::TYPE_FIX == $arOneDiscount['VALUE_TYPE'])
2306 {
2307 $dblDiscountValue = (
2308 !$changeData
2309 ? $arOneDiscount['VALUE']
2310 : round(
2311 CCurrencyRates::ConvertCurrency($arOneDiscount['VALUE'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']),
2313 )
2314 );
2315 if ($arParams['PRICE'] < $dblDiscountValue)
2316 continue;
2317 $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue;
2318 if ($changeData)
2319 $arOneDiscount['VALUE'] = $arOneDiscount['DISCOUNT_CONVERT'];
2320 }
2321 elseif (CCatalogDiscount::TYPE_SALE == $arOneDiscount['VALUE_TYPE'])
2322 {
2323 $dblDiscountValue = (
2324 !$changeData
2325 ? $arOneDiscount['VALUE']
2326 : round(
2327 CCurrencyRates::ConvertCurrency($arOneDiscount['VALUE'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']),
2329 )
2330 );
2331 if ($arParams['PRICE'] <= $dblDiscountValue)
2332 continue;
2333 $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue;
2334 if ($changeData)
2335 $arOneDiscount['VALUE'] = $arOneDiscount['DISCOUNT_CONVERT'];
2336 }
2337 elseif (CCatalogDiscount::TYPE_PERCENT == $arOneDiscount['VALUE_TYPE'])
2338 {
2339 if (100 < $arOneDiscount["VALUE"])
2340 continue;
2341 if ($arOneDiscount['TYPE'] == CCatalogDiscount::ENTITY_ID && $arOneDiscount["MAX_DISCOUNT"] > 0)
2342 {
2343 $dblDiscountValue = (
2344 !$changeData
2345 ? $arOneDiscount['MAX_DISCOUNT']
2346 : round(
2347 CCurrencyRates::ConvertCurrency($arOneDiscount['MAX_DISCOUNT'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']),
2349 )
2350 );
2351 $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue;
2352 if ($changeData)
2353 $arOneDiscount['MAX_DISCOUNT'] = $arOneDiscount['DISCOUNT_CONVERT'];
2354 }
2355 }
2356 if ($changeData)
2357 $arOneDiscount['CURRENCY'] = $arParams['CURRENCY'];
2358 if ($arOneDiscount['TYPE'] == CCatalogDiscountSave::ENTITY_ID)
2359 {
2360 $arDiscSave[] = $arOneDiscount;
2361 }
2362 else
2363 {
2364 $arPriceDiscount[$arOneDiscount['PRIORITY']][] = $arOneDiscount;
2365 }
2366 }
2367
2368 if (!empty($arPriceDiscount))
2369 krsort($arPriceDiscount);
2370 }
2371 }
2372 }
2373
2385 protected static function __CalcOnePriority(&$arDiscounts, &$arResultDiscount, &$arParams)
2386 {
2387 $boolResult = false;
2388 if (isset($arParams['PRICE']) && isset($arParams['CURRENCY']))
2389 {
2390 $arParams['PRICE'] = (float)$arParams['PRICE'];
2391 $arParams['BASE_PRICE'] = (float)$arParams['BASE_PRICE'];
2392 if ($arParams['PRICE'] > 0)
2393 {
2394 $dblCurrentPrice = $arParams['PRICE'];
2395 do
2396 {
2397 $dblMinPrice = -1;
2398 $strMinKey = -1;
2399 $boolApply = false;
2400 foreach ($arDiscounts as $strDiscountKey => $arOneDiscount)
2401 {
2402 $boolDelete = false;
2403 $dblPriceTmp = -1;
2404 switch($arOneDiscount['VALUE_TYPE'])
2405 {
2407 $dblTempo = round((
2409 ? $arParams['BASE_PRICE']
2410 : $dblCurrentPrice
2411 )*$arOneDiscount['VALUE']/100,
2413 );
2414 if (isset($arOneDiscount['DISCOUNT_CONVERT']))
2415 {
2416 if ($dblTempo > $arOneDiscount['DISCOUNT_CONVERT'])
2417 $dblTempo = $arOneDiscount['DISCOUNT_CONVERT'];
2418 }
2419 $dblPriceTmp = $dblCurrentPrice - $dblTempo;
2420 break;
2422 if ($arOneDiscount['DISCOUNT_CONVERT'] > $dblCurrentPrice)
2423 {
2424 $boolDelete = true;
2425 }
2426 else
2427 {
2428 $dblPriceTmp = $dblCurrentPrice - $arOneDiscount['DISCOUNT_CONVERT'];
2429 }
2430 break;
2432 if (!($arOneDiscount['DISCOUNT_CONVERT'] < $dblCurrentPrice))
2433 {
2434 $boolDelete = true;
2435 }
2436 else
2437 {
2438 $dblPriceTmp = $arOneDiscount['DISCOUNT_CONVERT'];
2439 }
2440 break;
2441 }
2442 if ($boolDelete)
2443 {
2444 unset($arDiscounts[$strDiscountKey]);
2445 }
2446 else
2447 {
2448 if (-1 == $dblMinPrice || $dblMinPrice > $dblPriceTmp)
2449 {
2450 $dblMinPrice = $dblPriceTmp;
2451 $strMinKey = $strDiscountKey;
2452 $boolApply = true;
2453 }
2454 }
2455 }
2456 if ($boolApply)
2457 {
2458 $dblCurrentPrice = $dblMinPrice;
2459 $arResultDiscount[] = $arDiscounts[$strMinKey];
2460 if ('Y' == $arDiscounts[$strMinKey]['LAST_DISCOUNT'])
2461 {
2462 $arDiscounts = array();
2463 $arParams['LAST_DISCOUNT'] = 'Y';
2464 }
2465 unset($arDiscounts[$strMinKey]);
2466 }
2467 } while (!empty($arDiscounts));
2468 if ($boolApply)
2469 {
2470 $arParams['PRICE'] = $dblCurrentPrice;
2471 }
2472 $boolResult = true;
2473 }
2474 }
2475 return $boolResult;
2476 }
2477
2489 protected static function __CalcDiscSave(&$arDiscSave, &$arResultDiscount, &$arParams)
2490 {
2491 $boolResult = false;
2492 if (isset($arParams['PRICE']) && isset($arParams['CURRENCY']))
2493 {
2494 $arParams['PRICE'] = (float)$arParams['PRICE'];
2495 if (0 < $arParams['PRICE'])
2496 {
2497 $dblCurrentPrice = $arParams['PRICE'];
2498 $dblMinPrice = -1;
2499 $strMinKey = -1;
2500 $boolApply = false;
2501 foreach ($arDiscSave as $strDiscountKey => $arOneDiscount)
2502 {
2503 $dblPriceTmp = -1;
2504 $boolDelete = false;
2505 switch($arOneDiscount['VALUE_TYPE'])
2506 {
2508 $dblPriceTmp = round($dblCurrentPrice*(1 - $arOneDiscount['VALUE']/100.0), CATALOG_VALUE_PRECISION);
2509 break;
2511 if ($arOneDiscount['DISCOUNT_CONVERT'] > $dblCurrentPrice)
2512 {
2513 $boolDelete = true;
2514 }
2515 else
2516 {
2517 $dblPriceTmp = $dblCurrentPrice - $arOneDiscount['DISCOUNT_CONVERT'];
2518 }
2519 break;
2520 }
2521 if (!$boolDelete)
2522 {
2523 if (-1 == $dblMinPrice || $dblMinPrice > $dblPriceTmp)
2524 {
2525 $dblMinPrice = $dblPriceTmp;
2526 $strMinKey = $strDiscountKey;
2527 $boolApply = true;
2528 }
2529 }
2530 }
2531 if ($boolApply)
2532 {
2533 $arParams['PRICE'] = $dblMinPrice;
2534 $arResultDiscount[] = $arDiscSave[$strMinKey];
2535 }
2536 $boolResult = true;
2537 }
2538 }
2539 return $boolResult;
2540 }
2541
2542 protected static function getQueryBuildCurrencyScale($filter, $priceTypeId)
2543 {
2544 $result = array();
2545 if (!isset($filter['CATALOG_CURRENCY_SCALE_'.$priceTypeId]))
2546 return $result;
2547 $currencyId = Currency\CurrencyManager::checkCurrencyID($filter['CATALOG_CURRENCY_SCALE_'.$priceTypeId]);
2548 if ($currencyId === false)
2549 return $result;
2550
2551 $currency = CCurrency::GetByID($currencyId);
2552 if (empty($currency))
2553 return $result;
2554
2555 $result['CURRENCY'] = $currency['CURRENCY'];
2556 $result['BASE_RATE'] = $currency['CURRENT_BASE_RATE'];
2557
2558 return $result;
2559 }
2560
2561 protected static function getQueryBuildPriceScaled($prices, $scale)
2562 {
2563 $result = array();
2564 $scale = (float)$scale;
2565 if (!is_array($prices))
2566 $prices = array($prices);
2567 if (empty($prices) || $scale <= 0)
2568 return $result;
2569 foreach ($prices as &$value)
2570 $result[] = (float)$value*$scale;
2571 unset($value);
2572 return $result;
2573 }
2574
2575 protected static function initSaleSettings()
2576 {
2577 if (self::$saleIncluded === null)
2578 self::$saleIncluded = Main\Loader::includeModule('sale');
2579 if (self::$saleIncluded)
2580 {
2581 self::$useSaleDiscount = (string)Main\Config\Option::get('sale', 'use_sale_discount_only') == 'Y';
2582 if (self::$useSaleDiscount)
2583 {
2584 //TODO: replace runtime to reference after sale 17.5.2 will be stable
2585 $row = Sale\Internals\DiscountEntitiesTable::getList(array(
2586 'select' => array('ID'),
2587 'filter' => array(
2588 '=MODULE_ID' => 'catalog',
2589 '=ENTITY' => 'PRICE',
2590 '=FIELD_ENTITY' => 'CATALOG_GROUP_ID',
2591 '=FIELD_TABLE' => 'CATALOG_GROUP_ID',
2592 '=ACTIVE_DISCOUNT.ACTIVE' => 'Y'
2593 ),
2594 'runtime' => array(
2595 new Main\Entity\ReferenceField(
2596 'ACTIVE_DISCOUNT',
2597 'Bitrix\Sale\Internals\Discount',
2598 array('=this.DISCOUNT_ID' => 'ref.ID'),
2599 array('join_type' => 'LEFT')
2600 )
2601 ),
2602 'limit' => 1,
2603 ))->fetch();
2604 self::$existPriceTypeDiscounts = !empty($row);
2605 unset($row);
2606 }
2607 }
2608 }
2609
2610 private static function isNeedleToMinimizeCatalogGroup(array $priceList)
2611 {
2612 if (self::$saleIncluded === null)
2614
2615 if (
2616 !self::$saleIncluded ||
2617 !self::$useSaleDiscount ||
2618 count($priceList) < 2
2619 )
2620 return false;
2621
2622 return self::$existPriceTypeDiscounts;
2623 }
2624
2625 private static function getPossibleSalePrice($intProductID, array $priceData, $quantity, $siteID, array $userGroups, $coupons)
2626 {
2627 $possibleSalePrice = null;
2628
2629 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
2630
2631 if (empty($priceData))
2632 return $possibleSalePrice;
2633
2634 $isCompatibilityUsed = Sale\Compatible\DiscountCompatibility::isUsed();
2635 Sale\Compatible\DiscountCompatibility::stopUsageCompatible();
2636
2637 $freezeCoupons = (empty($coupons) && is_array($coupons));
2638
2639 if ($freezeCoupons)
2640 Sale\DiscountCouponsManager::freezeCouponStorage();
2641
2643 static $basket = null,
2645 $basketItem = null;
2646
2647 if ($basket !== null)
2648 {
2649 if ($basket->getSiteId() != $siteID)
2650 {
2651 $basket = null;
2652 $basketItem = null;
2653 }
2654 }
2655 if ($basket === null)
2656 {
2658 $basketClassName = $registry->getBasketClassName();
2659
2660 $basket = $basketClassName::create($siteID);
2661 $basketItem = $basket->createItem('catalog', $intProductID);
2662 }
2663
2664 $fields = array(
2665 'PRODUCT_ID' => $intProductID,
2666 'QUANTITY' => $quantity,
2667 'LID' => $siteID,
2668 'PRODUCT_PRICE_ID' => $priceData['ID'],
2669 'PRICE' => $priceData['PRICE'],
2670 'BASE_PRICE' => $priceData['PRICE'],
2671 'DISCOUNT_PRICE' => 0,
2672 'CURRENCY' => $priceData['CURRENCY'],
2673 'CAN_BUY' => 'Y',
2674 'DELAY' => 'N',
2675 'PRICE_TYPE_ID' => (int)$priceData['CATALOG_GROUP_ID']
2676 );
2677
2678 $basketItem->setFieldsNoDemand($fields);
2679
2680 $discount = Sale\Discount::buildFromBasket($basket, new Sale\Discount\Context\UserGroup($userGroups));
2681
2682 $discount->setExecuteModuleFilter(array('all', 'catalog'));
2683 $discount->calculate();
2684
2685 $calcResults = $discount->getApplyResult(true);
2686 if ($calcResults && !empty($calcResults['PRICES']['BASKET']))
2687 {
2688 $possibleSalePrice = reset($calcResults['PRICES']['BASKET']);
2689 $possibleSalePrice = $possibleSalePrice['PRICE'];
2690 }
2691
2692 if ($freezeCoupons)
2693 Sale\DiscountCouponsManager::unFreezeCouponStorage();
2694 $discount->setExecuteModuleFilter(array('all', 'sale', 'catalog'));
2695
2696 if ($isCompatibilityUsed === true)
2697 {
2698 Sale\Compatible\DiscountCompatibility::revertUsageCompatible();
2699 }
2700
2701 return $possibleSalePrice;
2702 }
2703
2704 private static function checkPriceValue($price)
2705 {
2706 $result = false;
2707
2708 if ($price !== null && $price !== false)
2709 {
2710 if (is_string($price))
2711 {
2712 $price = str_replace(',', '.', $price);
2713 if ($price !== '' && is_numeric($price))
2714 {
2715 $price = (float)$price;
2716 if (is_finite($price))
2717 $result = $price;
2718 }
2719 }
2720 elseif (
2721 is_int($price)
2722 || (is_float($price) && is_finite($price))
2723 )
2724 {
2725 $result = $price;
2726 }
2727 }
2728
2729 return $result;
2730 }
2731
2732 private static function checkPriceCurrency($currency)
2733 {
2734 $result = false;
2735 if ($currency !== null && $currency !== false && $currency !== '')
2737 return $result;
2738 }
2739
2744 private static function getAllowedPriceTypes(array $userGroups): array
2745 {
2746 static $priceTypeCache = array();
2747
2748 Main\Type\Collection::normalizeArrayValuesByInt($userGroups, true);
2749 if (empty($userGroups))
2750 return array();
2751
2752 $cacheKey = 'U'.implode('_', $userGroups);
2753 if (!isset($priceTypeCache[$cacheKey]))
2754 {
2755 $priceTypeCache[$cacheKey] = array();
2756 $priceIterator = Catalog\GroupAccessTable::getList(array(
2757 'select' => array('CATALOG_GROUP_ID'),
2758 'filter' => array('@GROUP_ID' => $userGroups, '=ACCESS' => Catalog\GroupAccessTable::ACCESS_BUY),
2759 'order' => array('CATALOG_GROUP_ID' => 'ASC')
2760 ));
2761 while ($priceType = $priceIterator->fetch())
2762 {
2763 $priceTypeId = (int)$priceType['CATALOG_GROUP_ID'];
2764 $priceTypeCache[$cacheKey][$priceTypeId] = $priceTypeId;
2765 unset($priceTypeId);
2766 }
2767 unset($priceType, $priceIterator);
2768 }
2769
2770 return $priceTypeCache[$cacheKey];
2771 }
2772
2773 private static function convertErrors(Main\Entity\Result $result): void
2774 {
2775 global $APPLICATION;
2776
2777 $oldMessages = [];
2778 foreach ($result->getErrorMessages() as $errorText)
2779 {
2780 $oldMessages[] = ['text' => $errorText];
2781 }
2782 unset($errorText);
2783
2784 if (!empty($oldMessages))
2785 {
2786 $error = new CAdminException($oldMessages);
2787 $APPLICATION->ThrowException($error);
2788 unset($error);
2789 }
2790 unset($oldMessages);
2791 }
2792
2793 private static function normalizeFields(array &$fields): void
2794 {
2795 if (isset($fields['QUANTITY']) && $fields['QUANTITY'] === '')
2796 {
2797 $fields['QUANTITY'] = 0;
2798 }
2799 if (isset($fields['QUANTITY_RESERVED']) && $fields['QUANTITY_RESERVED'] === '')
2800 {
2801 $fields['QUANTITY_RESERVED'] = 0;
2802 }
2803 if (isset($fields['WEIGHT']) && $fields['WEIGHT'] === '')
2804 {
2805 $fields['WEIGHT'] = 0;
2806 }
2807 }
2808}
$arParams
Определения access_dialog.php:21
const CATALOG_VALUE_PRECISION
Определения include.php:109
const CATALOG_CACHE_DEFAULT_TIME
Определения include.php:110
global $APPLICATION
Определения include.php:80
$arResult
Определения generate_coupon.php:16
$boolFlag
Определения generate_coupon.php:21
static update($id, array $data)
Определения entity.php:229
static getList(array $parameters)
Определения entity.php:78
static add(array $data)
Определения entity.php:150
static getCacheItem($id, bool $load=false)
Определения entity.php:396
static delete($id)
Определения product.php:64
static roundPrecision($value)
Определения calculation.php:148
static setConfig(array $config)
Определения calculation.php:46
const PAYMENT_PERIOD_DAY
Определения product.php:83
const PAYMENT_PERIOD_YEAR
Определения product.php:88
const STATUS_YES
Определения product.php:66
const TYPE_EMPTY_SKU
Определения product.php:75
static getPaymentPeriods($descr=false)
Определения product.php:878
const TYPE_SET
Определения product.php:71
const TYPE_SKU
Определения product.php:72
const TYPE_FREE_OFFER
Определения product.php:74
const STATUS_NO
Определения product.php:67
const PAYMENT_PERIOD_MONTH
Определения product.php:85
const TYPE_OFFER
Определения product.php:73
const PAYMENT_PERIOD_SEMIYEAR
Определения product.php:87
static calculateAvailable($fields)
Определения product.php:737
const PAYMENT_PERIOD_WEEK
Определения product.php:84
const PAYMENT_PERIOD_QUART
Определения product.php:86
const TYPE_PRODUCT
Определения product.php:70
const PAYMENT_PERIOD_DOUBLE_YEAR
Определения product.php:89
const PAYMENT_PERIOD_HOUR
Определения product.php:82
static checkCurrencyID($currency)
Определения currencymanager.php:35
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 getList(array $parameters=array())
Определения datamanager.php:431
static normalizeArrayValuesByInt(&$map, $sorted=true)
Определения collection.php:150
static sortByColumn(array &$array, $columns, $callbacks='', $defaultValueIfNotSetValue=null, $preserveKeys=false)
Определения collection.php:24
static setApplyByProduct($product, $couponsList, $oldMode=false)
static GetCoupons()
Определения discount_coupon.php:207
static isUsedSaleDiscountOnly()
Определения discount.php:4246
const ENTITY_ID
Определения discount.php:22
static calculateDiscountList($priceData, $currency, &$discountList, $getWithVat=true)
Определения discount.php:2311
const TYPE_PERCENT
Определения discount.php:18
static applyDiscountList($price, $currency, &$discountList)
Определения discount.php:2173
static getUseBasePrice()
Определения discount.php:181
const TYPE_SALE
Определения discount.php:20
const TYPE_FIX
Определения discount.php:19
const ENTITY_ID
Определения discount_save.php:10
const TYPE_PERCENT
Определения discount_save.php:12
const TYPE_FIX
Определения discount_save.php:13
Определения product.php:10
static GetOptimalPriceList(array $products, $arUserGroups=array(), $renewal="N", $priceList=array(), $siteID=false, $needCoupons=true)
Определения product.php:1317
static $useDiscount
Определения product.php:77
static GetProductSections($ID)
Определения product.php:1914
static $useSaleDiscount
Определения product.php:80
static OnAfterIBlockElementUpdate($arFields)
Определения product.php:2005
static clearUsedCurrency()
Определения product.php:115
static getPriceVatIncludeMode()
Определения product.php:138
static initSaleSettings()
Определения product.php:2575
static $usedCurrency
Определения product.php:73
static $optimalPriceWithVat
Определения product.php:75
static GetByIDEx($ID, $boolAllValues=false)
Определения product.php:659
const TIME_PERIOD_SEMIYEAR
Определения product.php:59
static GetQueryBuildArrays($order, $filter, $select)
Определения product.php:2051
static setUsedCurrency($currency)
Определения product.php:92
static Delete($id)
Определения product.php:583
const TYPE_EMPTY_SKU
Определения product.php:34
static GetNearestQuantityPrice($productID, $quantity=1, $arUserGroups=array())
Определения product.php:851
static setUseDiscount($use)
Определения product.php:150
static CheckProducts($arItemIDs)
Определения product.php:2007
static GetByID($ID)
Определения product.php:625
static IsExistProduct($intID)
Определения product.php:200
const TYPE_SET
Определения product.php:18
const TYPE_SKU
Определения product.php:22
static __CalcDiscSave(&$arDiscSave, &$arResultDiscount, &$arParams)
Определения product.php:2489
static $saleIncluded
Определения product.php:79
static CheckFields($ACTION, &$arFields, $ID=0)
Определения product.php:206
static Update($id, $fields)
Определения product.php:557
const TIME_PERIOD_DOUBLE_YEAR
Определения product.php:67
const TYPE_FREE_OFFER
Определения product.php:30
const TIME_PERIOD_HOUR
Определения product.php:39
const TIME_PERIOD_WEEK
Определения product.php:47
static isAvailable($product)
Определения product.php:180
const TYPE_OFFER
Определения product.php:26
static getUsedCurrency()
Определения product.php:103
static OnIBlockElementDelete($ProductID)
Определения product.php:1993
static getUseDiscount()
Определения product.php:161
const TIME_PERIOD_YEAR
Определения product.php:63
static Add($fields, $checkExist=true)
Определения product.php:516
static getQueryBuildPriceScaled($prices, $scale)
Определения product.php:2561
static __CalcOnePriority(&$arDiscounts, &$arResultDiscount, &$arParams)
Определения product.php:2385
static getQueryBuildCurrencyScale($filter, $priceTypeId)
Определения product.php:2542
static __PrimaryDiscountFilter(&$arDiscount, &$arPriceDiscount, &$arDiscSave, &$arParams)
Определения product.php:2288
static $vatCache
Определения product.php:81
static $arProductCache
Определения product.php:70
static ParseQueryBuildField($field)
Определения product.php:594
static ClearCache()
Определения product.php:171
const TYPE_PRODUCT
Определения product.php:14
const TIME_PERIOD_DAY
Определения product.php:43
static GetOptimalPrice($intProductID, $quantity=1, $arUserGroups=array(), $renewal="N", $priceList=array(), $siteID=false, $arDiscountCoupons=false)
Определения product.php:973
const TIME_PERIOD_QUART
Определения product.php:55
const TIME_PERIOD_MONTH
Определения product.php:51
static QuantityTracer($ProductID, $DeltaQuantity)
Определения product.php:784
static setPriceVatIncludeMode($mode)
Определения product.php:127
static CountPriceWithDiscount($price, $currency, $discounts)
Определения product.php:1863
static GetTimePeriodTypes($boolFull=false)
Определения product.php:2094
static GetByID($currency)
Определения currency.php:453
static checkCurrencyID($currency)
Определения currency.php:714
static ConvertCurrency($valSum, $curFrom, $curTo, $valDate="")
Определения currency_rate.php:393
static GetVATDataByID($id)
Определения product.php:220
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения product.php:23
static GetVATDataByIDList(array $list)
Определения product.php:204
static GetList($arOrder=array(), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array())
Определения price.php:20
static makeQuery(array $parameters, array $options=[])
Определения querybuilder.php:76
$arFields
Определения dblapprove.php:5
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
if($ajaxMode) $ID
Определения get_user.php:27
$p
Определения group_list_element_edit.php:23
$offerList
Определения iblock_catalog_edit.php:142
$select
Определения iblock_catalog_list.php:194
$filter
Определения iblock_catalog_list.php:54
$siteID
Определения cron_frame.php:12
$ACTION
Определения csv_new_setup.php:27
$success
Определения mail_entry.php:69
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
is_set($a, $k=false)
Определения tools.php:2133
Определения basket.php:2
Определения ufield.php:9
Определения collection.php:2
$order
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$config
Определения quickway.php:69
$discount
Определения waybill.php:788
</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
$currency
Определения template.php:266
$vat
Определения template.php:273
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
const SITE_ID
Определения sonet_set_content_view.php:12
$error
Определения subscription_card_product.php:20
$arFilter
Определения user_search.php:106
if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_CATALOG_EXPORT_EDIT)) if((!isset($_REQUEST['IBLOCK_ID']))||($_REQUEST['IBLOCK_ID']=='')) $intIBlockID
Определения yandex_detail.php:44
$arIBlock['PROPERTY']
Определения yandex_detail.php:172
$iterator
Определения yandex_run.php:610
if(!empty($XML_DATA['PRICE'])) $priceTypeList
Определения yandex_run.php:872
$fields
Определения yandex_run.php:501
$vatList
Определения yandex_run.php:916