Current Path : /var/www/u0635749/data/www/hobbyclick.ru/public/bitrix/modules/sale/general/ |
Current File : /var/www/u0635749/data/www/hobbyclick.ru/public/bitrix/modules/sale/general/basket.php |
<?php use Bitrix\Main\Localization\Loc; use Bitrix\Sale; use Bitrix\Sale\DiscountCouponsManager; use Bitrix\Currency; Loc::loadMessages(__FILE__); class CAllSaleBasket { const TYPE_SET = 1; protected static $currencySiteList = array(); protected static $currencyList = array(); /** * Checks if the basket item has product provider class implementing IBXSaleProductProvider interface * * @param array $arBasketItem - array of basket item fields * @return mixed */ public static function GetProductProvider($arBasketItem) { if (!is_array($arBasketItem) || empty($arBasketItem) || !isset($arBasketItem["MODULE"]) || !isset($arBasketItem["PRODUCT_PROVIDER_CLASS"]) || ($arBasketItem["PRODUCT_PROVIDER_CLASS"] == '') ) return false; $productProviderClass = $arBasketItem["PRODUCT_PROVIDER_CLASS"]; if (CModule::IncludeModule($arBasketItem["MODULE"]) && class_exists($productProviderClass) && ((array_key_exists("IBXSaleProductProvider", class_implements($productProviderClass)))) ) { return $productProviderClass; } $providerClass = Sale\Internals\Catalog\Provider::getProviderEntity($arBasketItem["PRODUCT_PROVIDER_CLASS"]); if ($providerClass instanceof Sale\SaleProviderBase) { return '\Bitrix\Catalog\Product\CatalogProviderCompatibility'; } return false; } /** * Removes old product subscription * * @param string $LID - site for cleaning * @return bool */ public static function ClearProductSubscribe($LID) { CSaleBasket::_ClearProductSubscribe($LID); return "CSaleBasket::ClearProductSubscribe('".$LID."');"; } /** * Sends product subscription letter * * @param integer $ID - code product * @param string $MODULE - module product * @return bool */ public static function ProductSubscribe($ID, $MODULE) { $ID = (int)$ID; $MODULE = trim($MODULE); if ($ID <= 0 || $MODULE == '') return false; $arSubscribeProd = array(); $subscribeProd = COption::GetOptionString("sale", "subscribe_prod", ""); if ($subscribeProd != '') $arSubscribeProd = unserialize($subscribeProd, ['allowed_classes' => false]); $rsItemsBasket = CSaleBasket::GetList( array("USER_ID" => "DESC", "LID" => "ASC"), array( "PRODUCT_ID" => $ID, "SUBSCRIBE" => "Y", "CAN_BUY" => "N", "ORDER_ID" => "NULL", ">USER_ID" => "0", "MODULE" => $MODULE ), false, false, array('ID', 'FUSER_ID', 'USER_ID', 'MODULE', 'PRODUCT_ID', 'CURRENCY', 'DATE_INSERT', 'QUANTITY', 'LID', 'DELAY', 'CALLBACK_FUNC', 'SUBSCRIBE', 'PRODUCT_PROVIDER_CLASS') ); while ($arItemsBasket = $rsItemsBasket->Fetch()) { $LID = $arItemsBasket["LID"]; if (isset($arSubscribeProd[$LID]) && $arSubscribeProd[$LID]["use"] == "Y") { $sendEmailList = array(); $USER_ID = $arItemsBasket['USER_ID']; $arMailProp = array(); $arPayerProp = array(); // load user profiles $arUserProfiles = CSaleOrderUserProps::DoLoadProfiles($USER_ID); if (!empty($arUserProfiles)) { // select person type $dbPersonType = CSalePersonType::GetList(array("SORT" => "ASC"), array("LID" => $LID), false, false, array('ID')); while ($arPersonType = $dbPersonType->Fetch()) { // select ID props is mail $dbProperties = CSaleOrderProps::GetList( array(), array("PERSON_TYPE_ID" => $arPersonType["ID"], "IS_EMAIL" => "Y", "ACTIVE" => "Y"), false, false, array('ID', 'PERSON_TYPE_ID') ); while ($arProperties = $dbProperties->Fetch()) $arMailProp[$arProperties["PERSON_TYPE_ID"]] = $arProperties["ID"]; // select ID props is name $dbProperties = CSaleOrderProps::GetList( array(), array("PERSON_TYPE_ID" => $arPersonType["ID"], "IS_PAYER" => "Y", "ACTIVE" => "Y"), false, false, array('ID', 'PERSON_TYPE_ID') ); while ($arProperties = $dbProperties->Fetch()) $arPayerProp[$arProperties["PERSON_TYPE_ID"]] = $arProperties["ID"]; }//end while } $rsUser = CUser::GetByID($USER_ID); $arUser = $rsUser->Fetch(); $userName = $arUser["LAST_NAME"]; if ($userName != '') $userName .= " "; $userName .= $arUser["NAME"]; // select of user name to be sent $arUserSendName = array(); if (!empty($arUserProfiles) && !empty($arPayerProp)) { foreach($arPayerProp as $personType => $namePropID) { if (isset($arUserProfiles[$personType])) { foreach($arUserProfiles[$personType] as $profiles) { if (isset($profiles["VALUES"][$namePropID]) && $profiles["VALUES"][$namePropID] != '') { $arUserSendName[$personType] = trim($profiles["VALUES"][$namePropID]); break; } else { $arUserSendName[$personType] = $userName; } } } else { $arUserSendName[$personType] = $userName; } } } else { $arUserSendName[] = $userName; } // select of e-mail to be sent $arUserSendMail = array(); if (!empty($arUserProfiles) && !empty($arMailProp)) { foreach($arMailProp as $personType => $mailPropID) { if (isset($arUserProfiles[$personType])) { foreach($arUserProfiles[$personType] as $profiles) { if (isset($profiles["VALUES"][$mailPropID]) && $profiles["VALUES"][$mailPropID] != '') { $arUserSendMail[$personType] = trim($profiles["VALUES"][$mailPropID]); break; } else { $arUserSendMail[$personType] = $arUser["EMAIL"]; } } } else { $arUserSendMail[$personType] = $arUser["EMAIL"]; } } } else { $arUserSendMail[] = $arUser["EMAIL"]; } /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arItemsBasket)) { $arCallback = $productProvider::GetProductData(array( "PRODUCT_ID" => $ID, "QUANTITY" => 1, "RENEWAL" => "N", "USER_ID" => $USER_ID, "SITE_ID" => $LID, "BASKET_ID" => $arItemsBasket["ID"] )); } elseif (isset($arItemsBasket["CALLBACK_FUNC"]) && !empty($arItemsBasket["CALLBACK_FUNC"])) { $arCallback = CSaleBasket::ExecuteCallbackFunction( trim($arItemsBasket["CALLBACK_FUNC"]), $MODULE, $ID, 1, "N", $USER_ID, $LID ); } if (!empty($arCallback)) { $arCallback["QUANTITY"] = 1; $arCallback["DELAY"] = "N"; $arCallback["SUBSCRIBE"] = "N"; CSaleBasket::Update($arItemsBasket["ID"], $arCallback); } //send mail if (!empty($arUserSendMail) && !empty($arCallback)) { $eventName = "SALE_SUBSCRIBE_PRODUCT"; $event = new CEvent; foreach ($arUserSendMail as $personType => $mail) { $checkMail = mb_strtolower($mail); if (isset($sendEmailList[$checkMail])) continue; $sendName = $userName; if (isset($arUserSendName[$personType]) && $arUserSendName[$personType] != '') $sendName = $arUserSendName[$personType]; $arFields = array( "EMAIL" => $mail, "USER_NAME" => $sendName, "NAME" => $arCallback["NAME"], "PAGE_URL" => CHTTP::URN2URI($arCallback["DETAIL_PAGE_URL"]), "SALE_EMAIL" => COption::GetOptionString("sale", "order_email", "order@".$_SERVER["SERVER_NAME"]), ); $event->Send($eventName, $LID, $arFields, "N"); $sendEmailList[$checkMail] = true; } } }// end if bSend }// end while $arItemsBasket return true; } public static function DoGetUserShoppingCart($siteId, $userId, $shoppingCart, &$arErrors, $arCoupons = array(), $orderId = 0, $enableCustomCurrency = false) { $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); $siteId = trim($siteId); if (empty($siteId)) { $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_PARAM_SITE_ERROR')); return null; } $userId = intval($userId); if (!is_array($shoppingCart)) { if (intval($shoppingCart)."|" != $shoppingCart."|") { $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_PARAM_SK_ERROR')); return null; } $shoppingCart = intval($shoppingCart); $dbShoppingCartItems = CSaleBasket::GetList( array("NAME" => "ASC"), array( "FUSER_ID" => $shoppingCart, "LID" => $siteId, "ORDER_ID" => "NULL", "DELAY" => "N", ), false, false, array( "ID", "LID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "QUANTITY", "DELAY", "CAN_BUY", "PRICE", "WEIGHT", "NAME", "CURRENCY", "CATALOG_XML_ID", "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS", "RESERVED", "DEDUCTED", "RESERVE_QUANTITY", "DIMENSIONS", "TYPE", "SET_PARENT_ID" ) ); $arTmp = array(); while ($arShoppingCartItem = $dbShoppingCartItems->Fetch()) $arTmp[] = $arShoppingCartItem; $shoppingCart = $arTmp; } $arOldShoppingCart = array(); if ($orderId != 0) // for existing basket we need old data to calculate quantity delta for availability checking { $dbs = CSaleBasket::GetList( array("NAME" => "ASC"), array( "LID" => $siteId, "ORDER_ID" => $orderId, "DELAY" => "N", ), false, false, array( "ID", "LID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "PRODUCT_PRICE_ID", "PRICE", "QUANTITY", "DELAY", "CAN_BUY", "PRICE", "WEIGHT", "NAME", "CURRENCY", "CATALOG_XML_ID", "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS", "RESERVED", "DEDUCTED", "BARCODE_MULTI", "DIMENSIONS", "TYPE", "SET_PARENT_ID" ) ); while ($arOldShoppingCartItem = $dbs->Fetch()) $arOldShoppingCart[$arOldShoppingCartItem["ID"]] = $arOldShoppingCartItem; } if (CSaleHelper::IsAssociativeArray($shoppingCart)) $shoppingCart = array($shoppingCart); if (!empty($arCoupons)) { if (!is_array($arCoupons)) $arCoupons = array($arCoupons); foreach(GetModuleEvents("sale", "OnSetCouponList", true) as $arEvent) ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array())); foreach ($arCoupons as &$coupon) $couponResult = DiscountCouponsManager::add($coupon); unset($coupon, $couponResult); } if(!is_bool($enableCustomCurrency)) { $enableCustomCurrency = false; } $arResult = array(); $emptyID = 1; foreach ($shoppingCart as $itemIndex => $arShoppingCartItem) { if ((array_key_exists("CALLBACK_FUNC", $arShoppingCartItem) && !empty($arShoppingCartItem["CALLBACK_FUNC"])) || (array_key_exists("PRODUCT_PROVIDER_CLASS", $arShoppingCartItem) && !empty($arShoppingCartItem["PRODUCT_PROVIDER_CLASS"]))) { // get quantity difference to check its availability if ($orderId != 0) $quantity = $arShoppingCartItem["QUANTITY"] - $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["QUANTITY"]; else $quantity = $arShoppingCartItem["QUANTITY"]; $customPrice = (isset($arShoppingCartItem['CUSTOM_PRICE']) && $arShoppingCartItem['CUSTOM_PRICE'] == 'Y'); $existBasketID = (isset($arShoppingCartItem['ID']) && (int)$arShoppingCartItem['ID'] > 0); /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arShoppingCartItem)) { if ($existBasketID) { $basketID = $arShoppingCartItem['ID']; } elseif (isset($arShoppingCartItem["ID_TMP"])) { $basketID = $arShoppingCartItem["ID_TMP"]; } else { $basketID = 'tmp_'.$emptyID; $emptyID++; } $providerParams = array( "PRODUCT_ID" => $arShoppingCartItem["PRODUCT_ID"], "QUANTITY" => ($quantity > 0) ? $quantity : $arShoppingCartItem["QUANTITY"], "RENEWAL" => "N", "USER_ID" => $userId, "SITE_ID" => $siteId, "BASKET_ID" => $basketID, "CHECK_QUANTITY" => ($quantity > 0) ? "Y" : "N", "CHECK_COUPONS" => ('Y' == $arShoppingCartItem['CAN_BUY'] && (!array_key_exists('DELAY', $arShoppingCartItem) || 'Y' != $arShoppingCartItem['DELAY']) ? 'Y' : 'N'), "CHECK_PRICE" => ($customPrice ? "N" : "Y") ); if (isset($arShoppingCartItem['NOTES'])) $providerParams['NOTES'] = $arShoppingCartItem['NOTES']; $arFieldsTmp = $productProvider::GetProductData($providerParams); unset($providerParams); } else { $arFieldsTmp = CSaleBasket::ExecuteCallbackFunction( $arShoppingCartItem["CALLBACK_FUNC"], $arShoppingCartItem["MODULE"], $arShoppingCartItem["PRODUCT_ID"], $quantity, "N", $userId, $siteId ); if (!empty($arFieldsTmp) && is_array($arFieldsTmp)) { if ($customPrice) unset($arFieldsTmp['PRICE'], $arFieldsTmp['CURRENCY']); } } if (!empty($arFieldsTmp) && is_array($arFieldsTmp)) { $arFieldsTmp["CAN_BUY"] = "Y"; $arFieldsTmp["SUBSCRIBE"] = "N"; $arFieldsTmp['TYPE'] = (int)$arShoppingCartItem['TYPE']; $arFieldsTmp['SET_PARENT_ID'] = $arShoppingCartItem['SET_PARENT_ID']; $arFieldsTmp['LID'] = $siteId; } else { $arFieldsTmp = array("CAN_BUY" => "N"); } if ($isOrderConverted != 'N') { if (!Sale\Compatible\DiscountCompatibility::isInited()) Sale\Compatible\DiscountCompatibility::init(); $basketCode = (Sale\Compatible\DiscountCompatibility::usedByClient() ? $arShoppingCartItem['ID'] : $itemIndex); Sale\Compatible\DiscountCompatibility::setBasketItemData($basketCode, $arFieldsTmp); } if ($existBasketID) { $arFieldsTmp["IGNORE_CALLBACK_FUNC"] = "Y"; CSaleBasket::Update($arShoppingCartItem["ID"], $arFieldsTmp); $dbTmp = CSaleBasket::GetList( array(), array("ID" => $arShoppingCartItem["ID"]), false, false, array( "ID", "CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "QUANTITY", "DELAY", "CAN_BUY", "PRICE", "TYPE", "SET_PARENT_ID", "WEIGHT", "NAME", "CURRENCY", "CATALOG_XML_ID", "VAT_RATE", "NOTES", "DISCOUNT_PRICE", "DETAIL_PAGE_URL", "PRODUCT_PROVIDER_CLASS", "DIMENSIONS" ) ); $arTmp = $dbTmp->Fetch(); foreach ($arTmp as $key => $val) $arShoppingCartItem[$key] = $val; } else { foreach ($arFieldsTmp as $key => $val) { // update returned quantity for the product if quantity difference is available if ($orderId != 0 && $key == "QUANTITY" && $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["RESERVED"] == "Y" && $quantity > 0) { $arShoppingCartItem[$key] = $val + $arOldShoppingCart[$arShoppingCartItem["ID_TMP"]]["QUANTITY"]; } else { $arShoppingCartItem[$key] = $val; } } } } if ($arShoppingCartItem["CAN_BUY"] == "Y") { if(!$enableCustomCurrency) { $baseLangCurrency = CSaleLang::GetLangCurrency($siteId); if ($baseLangCurrency != $arShoppingCartItem["CURRENCY"]) { $arShoppingCartItem["PRICE"] = CCurrencyRates::ConvertCurrency($arShoppingCartItem["PRICE"], $arShoppingCartItem["CURRENCY"], $baseLangCurrency); if (is_set($arShoppingCartItem, "DISCOUNT_PRICE")) $arShoppingCartItem["DISCOUNT_PRICE"] = CCurrencyRates::ConvertCurrency($arShoppingCartItem["DISCOUNT_PRICE"], $arShoppingCartItem["CURRENCY"], $baseLangCurrency); $arShoppingCartItem["CURRENCY"] = $baseLangCurrency; } } $arShoppingCartItem["PRICE"] = \Bitrix\Sale\PriceMaths::roundPrecision($arShoppingCartItem["PRICE"]); $arShoppingCartItem["QUANTITY"] = floatval($arShoppingCartItem["QUANTITY"]); $arShoppingCartItem["WEIGHT"] = floatval($arShoppingCartItem["WEIGHT"]); $arShoppingCartItem["DIMENSIONS"] = unserialize($arShoppingCartItem["DIMENSIONS"], ['allowed_classes' => false]); $arShoppingCartItem["VAT_RATE"] = floatval($arShoppingCartItem["VAT_RATE"]); $arShoppingCartItem["DISCOUNT_PRICE"] = roundEx($arShoppingCartItem["DISCOUNT_PRICE"], SALE_VALUE_PRECISION); if ($arShoppingCartItem["VAT_RATE"] > 0) $arShoppingCartItem["VAT_VALUE"] = \Bitrix\Sale\PriceMaths::roundPrecision(($arShoppingCartItem["PRICE"] / ($arShoppingCartItem["VAT_RATE"] + 1)) * $arShoppingCartItem["VAT_RATE"]); //$arShoppingCartItem["VAT_VALUE"] = roundEx((($arShoppingCartItem["PRICE"] / ($arShoppingCartItem["VAT_RATE"] + 1)) * $arShoppingCartItem["VAT_RATE"]), SALE_VALUE_PRECISION); if ($arShoppingCartItem["DISCOUNT_PRICE"] > 0) $arShoppingCartItem["DISCOUNT_PRICE_PERCENT"] = $arShoppingCartItem["DISCOUNT_PRICE"] * 100 / ($arShoppingCartItem["DISCOUNT_PRICE"] + $arShoppingCartItem["PRICE"]); $arResult[$itemIndex] = $arShoppingCartItem; } } if (isset($arShoppingCartItem)) unset($arShoppingCartItem); if (!empty($arCoupons) && is_array($arCoupons)) { foreach(GetModuleEvents("sale", "OnClearCouponList", true) as $arEvent) ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array())); } return $arResult; } /** * Changes product quantity in the catalog. * Used in the DoSaveOrderBasket to actualize basket items quantity * after some operations with the order are made in the order_new form * * Depending on the state of the order (reserved/deducted) * and the state of the product (reserved/deducted) calls appropriate provider methods * * If the quantity is 0 and CHECK_QUANTITY is N, this method is used only to call OrderProduct method to actualize coupon data * * @param array $arBasketItem - basket item data array * @param int $deltaQuantity - quantity to be changed. Can be zero, in this case CHECK_QUANTITY should be N * @param bool $isOrderReserved - order reservation flag * @param bool $isOrderDeducted - order deduction flag * @param array $arStoreBarcodeOrderFormData - array of barcode and stores from order_new form to be used for deduction * @param array $arAdditionalParams - user id, site id, check_quantity flag * @return bool */ public static function DoChangeProductQuantity($arBasketItem, $deltaQuantity, $isOrderReserved = false, $isOrderDeducted = false, $arStoreBarcodeOrderFormData = array(), $arAdditionalParams = array()) { global $APPLICATION; if (!array_key_exists("CHECK_QUANTITY", $arAdditionalParams) || $arAdditionalParams["CHECK_QUANTITY"] != "N") $arAdditionalParams["CHECK_QUANTITY"] = "Y"; if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "DoChangeProductQuantity - Started", array( "arBasketItem" => $arBasketItem, "deltaQuantity" => $deltaQuantity, "isOrderReserved" => intval($isOrderReserved), "isOrderDeducted" => intval($isOrderDeducted), "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData, "checkQuantity" => $arAdditionalParams["CHECK_QUANTITY"] ), "DCPQ1" ); } /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasketItem)) { $productProvider::OrderProduct( array( "PRODUCT_ID" => $arBasketItem["PRODUCT_ID"], "QUANTITY" => ($deltaQuantity <= 0 ? $arBasketItem['QUANTITY'] : $deltaQuantity), "RENEWAL" => "N", "USER_ID" => $arAdditionalParams["USER_ID"], "SITE_ID" => $arAdditionalParams["SITE_ID"], "CHECK_QUANTITY" => $arAdditionalParams["CHECK_QUANTITY"], "BASKET_ID" => $arBasketItem['ID'] ) ); if ($deltaQuantity == 0 && $arAdditionalParams["CHECK_QUANTITY"] == 'N') return true; if ($isOrderDeducted) // we need to reserve and deduct product { $quantityPreviouslyLeftToReserve = ($arBasketItem["RESERVED"] == "Y") ? floatval($arBasketItem["RESERVE_QUANTITY"]) : 0; if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveBasketProduct", array( "arBasketItemID" => $arBasketItem["ID"], "deltaQuantity" => $deltaQuantity, "quantityPreviouslyLeftToReserve" => $quantityPreviouslyLeftToReserve, "isOrderDeducted" => $isOrderDeducted ), "DCPQ2" ); } $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve, $isOrderDeducted); if (array_key_exists("ERROR", $arRes)) { CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"]))); return false; } if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::DeductBasketProduct", array( "arBasketItemID" => $arBasketItem["ID"], "deltaQuantity" => $deltaQuantity, "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData ), "DCPQ3" ); } $arDeductResult = CSaleBasket::DeductBasketProduct($arBasketItem["ID"], $deltaQuantity, $arStoreBarcodeOrderFormData); if (array_key_exists("ERROR", $arDeductResult)) { CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"]))); $APPLICATION->ThrowException(Loc::getMessage("SKGB_DEDUCT_ERROR", array("#MESSAGE#" => $arDeductResult["ERROR"]["MESSAGE"])), "DEDUCTION_ERROR"); return false; } } else if ($isOrderReserved && !$isOrderDeducted) // we need to reserve product { if ($arBasketItem["RESERVED"] == "Y") { $quantityPreviouslyLeftToReserve = floatval($arBasketItem["RESERVE_QUANTITY"]); if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveBasketProduct", array( "arBasketItemID" => $arBasketItem["ID"], "deltaQuantity" => $deltaQuantity, "quantityPreviouslyLeftToReserve" => $quantityPreviouslyLeftToReserve ), "DCPQ4" ); } $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve); if (array_key_exists("ERROR", $arRes)) { CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"]))); return false; } } else { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveBasketProduct", array( "arBasketItemID" => $arBasketItem["ID"], "deltaQuantity" => $deltaQuantity ), "DCPQ5" ); } $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity); if (array_key_exists("ERROR", $arRes)) { CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"]))); return false; } } } else // order not reserved, not deducted { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveBasketProduct", array( "arBasketItemID" => $arBasketItem["ID"], "deltaQuantity" => $deltaQuantity ), "DCPQ6" ); } if ($arBasketItem["RESERVED"] == "Y") // we undo product reservation { $quantityPreviouslyLeftToReserve = floatval($arBasketItem["RESERVE_QUANTITY"]); $arRes = CSaleBasket::ReserveBasketProduct($arBasketItem["ID"], $deltaQuantity + $quantityPreviouslyLeftToReserve); if (array_key_exists("ERROR", $arRes)) { CSaleOrder::SetMark($arAdditionalParams["ORDER_ID"], Loc::getMessage("SKGB_RESERVE_ERROR", array("#MESSAGE#" => $arRes["ERROR"]["MESSAGE"]))); return false; } } } } else // provider is not used. old logic without reservation { if ($deltaQuantity < 0) { CSaleBasket::ExecuteCallbackFunction( $arBasketItem["CANCEL_CALLBACK_FUNC"], $arBasketItem["MODULE"], $arBasketItem["PRODUCT_ID"], abs($deltaQuantity), true ); } else if ($deltaQuantity > 0) { CSaleBasket::ExecuteCallbackFunction( $arBasketItem["ORDER_CALLBACK_FUNC"], $arBasketItem["MODULE"], $arBasketItem["PRODUCT_ID"], $deltaQuantity, "N", $arAdditionalParams["USER_ID"], $arAdditionalParams["SITE_ID"] ); } else if ($deltaQuantity == 0) { CSaleBasket::ExecuteCallbackFunction( $arBasketItem["ORDER_CALLBACK_FUNC"], $arBasketItem["MODULE"], $arBasketItem["PRODUCT_ID"], $arBasketItem['QUANTITY'], "N", $arAdditionalParams["USER_ID"], $arAdditionalParams["SITE_ID"] ); } } return true; } /** * Updates information about basket products after changes have been made in the order_new form * (saves newly added basket items, changes their quantity, saves barcodes etc) * * @param int $orderId - order ID * @param string $siteId - site ID * @param bool $userId - user ID * @param array $arShoppingCart - array of basket items * @param array $arErrors * @param array $arCoupons * @param array $arStoreBarcodeOrderFormData - array of stores and barcodes for deduction (from order_new form) * @param bool $bSaveBarcodes - flat to save given barcode data. Used if the order is already deducted or at least has saved other barcodes * @return bool */ public static function DoSaveOrderBasket($orderId, $siteId, $userId, &$arShoppingCart, &$arErrors, $arCoupons = array(), $arStoreBarcodeOrderFormData = array(), $bSaveBarcodes = false) { global $DB, $USER, $APPLICATION; $currentUserID = 0; if (isset($USER) && $USER instanceof CUser) $currentUserID = (int)$USER->GetID(); if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog("DoSaveOrderBasket - Started", array( "orderId" => $orderId, "siteId" => $siteId, "userId" => $userId, "arShoppingCart" => $arShoppingCart, "bSaveBarcodes" => $bSaveBarcodes, "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData ), "DSOB1" ); } $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); $orderId = (int)$orderId; if ($orderId <= 0) return false; if (empty($arShoppingCart) || !is_array($arShoppingCart)) { $arErrors[] = array("CODE" => "PARAM", "TEXT" => Loc::getMessage('SKGB_SHOPPING_CART_EMPTY')); return false; } $isOrderReserved = false; $isOrderDeducted = false; $dbOrderTmp = CSaleOrder::GetList( array(), array("ID" => $orderId), false, false, array("ID", "RESERVED", "DEDUCTED") ); if ($arOrder = $dbOrderTmp->Fetch()) { if ($arOrder["RESERVED"] == "Y") $isOrderReserved = true; if ($arOrder["DEDUCTED"] == "Y") $isOrderDeducted = true; } $arOldItems = array(); $dbItems = CSaleBasket::GetList( array(), array("ORDER_ID" => $orderId), false, false, array( "ID", "QUANTITY", "CANCEL_CALLBACK_FUNC", "MODULE", "PRODUCT_ID", "PRODUCT_PROVIDER_CLASS", "RESERVED", "RESERVE_QUANTITY", "TYPE", "SET_PARENT_ID" ) ); while ($arItem = $dbItems->Fetch()) { $arOldItems[$arItem["ID"]] = array( "QUANTITY" => $arItem["QUANTITY"], "CANCEL_CALLBACK_FUNC" => $arItem["CANCEL_CALLBACK_FUNC"], "PRODUCT_PROVIDER_CLASS" => $arItem["PRODUCT_PROVIDER_CLASS"], "MODULE" => $arItem["MODULE"], "PRODUCT_ID" => $arItem["PRODUCT_ID"], "RESERVED" => $arItem["RESERVED"], "RESERVE_QUANTITY" => $arItem["RESERVE_QUANTITY"], "TYPE" => $arItem["TYPE"], "SET_PARENT_ID" => $arItem["SET_PARENT_ID"] ); } if (!empty($arCoupons)) { if (!is_array($arCoupons)) $arCoupons = array($arCoupons); foreach (GetModuleEvents("sale", "OnSetCouponList", true) as $arEvent) ExecuteModuleEventEx($arEvent, array($userId, $arCoupons, array())); foreach ($arCoupons as &$coupon) $couponResult = DiscountCouponsManager::add($coupon); unset($coupon, $couponResult); } $arFUserListTmp = CSaleUser::GetList(array("USER_ID" => $userId)); if (empty($arFUserListTmp)) { $arFields = array( "=DATE_INSERT" => $DB->GetNowFunction(), "=DATE_UPDATE" => $DB->GetNowFunction(), "USER_ID" => $userId, "CODE" => md5(time().randString(10)), ); $FUSER_ID = CSaleUser::_Add($arFields); } else { $FUSER_ID = $arFUserListTmp["ID"]; } $arTmpSetParentId = array(); //TODO: is orders converted? if ($isOrderConverted == 'N') { // re-sort basket data so newly added Set parents come before Set items (used to correctly add Set items to the table) usort($arShoppingCart, array("CSaleBasketHelper", "cmpSetData")); foreach ($arShoppingCart as &$arItem) { $arItemKeys = array_keys($arItem); foreach ($arItemKeys as $fieldName) { if(array_key_exists("~".$fieldName, $arItem)) { if ((is_array($arItem["~".$fieldName]) && !empty($arItem["~".$fieldName])) || (!is_array($arItem["~".$fieldName]) && $arItem["~".$fieldName] <> '')) { $arItem[$fieldName] = $arItem["~".$fieldName]; } unset($arItem["~".$fieldName]); } } $arItem = array_filter($arItem, array("CSaleBasketHelper", "filterFields")); } unset($arItem); foreach ($arShoppingCart as $arItem) { if (mb_strpos($arItem["SET_PARENT_ID"], "tmp") !== false) $arTmpSetParentId[$arItem["SET_PARENT_ID"]] = $arItem["SET_PARENT_ID"]; } } $orderBasketPool = array(); // iterate over basket data to save it to basket or change quantity (and reserve/deduct accordingly) foreach ($arShoppingCart as &$arItem) { foreach ($arItem as $tmpKey => $tmpVal) { if (is_array($tmpVal) && !in_array($tmpKey, array("STORES", "CATALOG", "PROPS"))) $arItem[$tmpKey] = serialize($tmpVal); } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DoSaveOrderBasket - Item", array("arItem" => $arItem), "DSOB2"); if (array_key_exists("ID", $arItem) && (int)$arItem["ID"] > 0) { $arItem["ID"] = (int)$arItem["ID"]; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DoSaveOrderBasket - Product #".$arItem["ID"]." already in the basket", array(), "DSOB3"); // product already in the basket, change quantity if (array_key_exists($arItem["ID"], $arOldItems)) { //TODO: is order converted? if ($isOrderConverted == 'N') { if (!CSaleBasketHelper::isSetParent($arItem)) { $arAdditionalParams = array( "ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId ); $quantity = $arItem["QUANTITY"] - $arOldItems[$arItem["ID"]]["QUANTITY"]; $arAdditionalParams["CHECK_QUANTITY"] = ($quantity > 0) ? "Y" : "N"; if ($quantity != 0) { self::DoChangeProductQuantity( $arItem, $quantity, $isOrderReserved, $isOrderDeducted, $arStoreBarcodeOrderFormData[$arItem["ID"]], $arAdditionalParams ); } else { $arAdditionalParams['CHECK_QUANTITY'] = 'N'; self::DoChangeProductQuantity( $arItem, $quantity, $isOrderReserved, $isOrderDeducted, $arStoreBarcodeOrderFormData[$arItem["ID"]], $arAdditionalParams ); } } } unset($arOldItems[$arItem["ID"]]); } else { //TODO: is order converted? if ($isOrderConverted == 'N') { if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem)) { self::DoChangeProductQuantity( $arItem, $arItem["QUANTITY"], $isOrderReserved, $isOrderDeducted, $arStoreBarcodeOrderFormData[$arItem["ID"]], array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId) ); } } } if(intval($arItem["FUSER_ID"]) <= 0) { $arFuserItems = CSaleUser::GetList(array("USER_ID" => intval($userId))); $arItem["FUSER_ID"] = $arFuserItems["ID"]; } if (CSaleBasketHelper::isSetItem($arItem)) // quantity for set items will be changed when parent item is updated unset($arItem["QUANTITY"]); //TODO: is order converted? if ($isOrderConverted != 'N') { $fields = array("IGNORE_CALLBACK_FUNC" => "Y") + $arItem; $orderBasketPool[$arItem["ID"]] = array("ORDER_ID" => $orderId); foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $event) { if (ExecuteModuleEventEx($event, array($arItem["ID"], &$fields)) === false) { return false; } } /** @var \Bitrix\Sale\Result $r */ $r = \Bitrix\Sale\Compatible\BasketCompatibility::update($arItem["ID"], $fields); if (!$r->isSuccess(true)) { foreach($r->getErrorMessages() as $error) { $APPLICATION->ThrowException($error); } return false; } } else { CSaleBasket::Update($arItem["ID"], array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem); } } else // new product in the basket { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DoSaveOrderBasket - new product in the basket", array(), "DSOB4"); unset($arItem["ID"]); /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arItem)) //if we need to use new logic { $oldSetParentId = -1; if (CSaleBasketHelper::isSetParent($arItem) && array_key_exists($arItem["SET_PARENT_ID"], $arTmpSetParentId)) { $oldSetParentId = $arItem["SET_PARENT_ID"]; $arItem["MANUAL_SET_ITEMS_INSERTION"] = "Y"; } if (CSaleBasketHelper::isSetItem($arItem) && array_key_exists($arItem["SET_PARENT_ID"], $arTmpSetParentId)) { $arItem["SET_PARENT_ID"] = $arTmpSetParentId[$arItem["SET_PARENT_ID"]]; } $arItem["ID"] = CSaleBasket::Add(array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem); if($APPLICATION->GetException()) { return false; } if (isset($arItem["MANUAL_SET_ITEMS_INSERTION"])) $arTmpSetParentId[$oldSetParentId] = $arItem["ID"]; if ($bSaveBarcodes) { if ($arItem["BARCODE_MULTI"] == "N") //saving only store quantity info { if (is_array($arItem["STORES"])) { foreach ($arItem["STORES"] as $arStore) { $arStoreBarcodeFields = array( "BASKET_ID" => $arItem["ID"], "BARCODE" => "", "STORE_ID" => $arStore["STORE_ID"], "QUANTITY" => $arStore["QUANTITY"], "CREATED_BY" => ($currentUserID > 0 ? $currentUserID : ''), "MODIFIED_BY" => ($currentUserID > 0 ? $currentUserID : '') ); CSaleStoreBarcode::Add($arStoreBarcodeFields); } } } else // BARCODE_MULTI = Y { if (!empty($arItem["STORES"]) && is_array($arItem["STORES"])) { foreach ($arItem["STORES"] as $arStore) { if (isset($arStore["BARCODE"]) && isset($arStore["BARCODE_FOUND"])) { foreach ($arStore["BARCODE"] as $barcodeId => $barcodeValue) { // save only non-empty and valid barcodes TODO - if errors? if ($barcodeValue <> '' && $arStore["BARCODE_FOUND"][$barcodeId] == "Y") { $arStoreBarcodeFields = array( "BASKET_ID" => $arItem["ID"], "BARCODE" => $barcodeValue, "STORE_ID" => $arStore["STORE_ID"], "QUANTITY" => 1, "CREATED_BY" => ($currentUserID > 0 ? $currentUserID : ''), "MODIFIED_BY" => ($currentUserID > 0 ? $currentUserID : '') ); CSaleStoreBarcode::Add($arStoreBarcodeFields); } } } } } } } if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem)) { self::DoChangeProductQuantity( $arItem, $arItem["QUANTITY"], $isOrderReserved, $isOrderDeducted, $arItem["STORES"], array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId) ); } if ($FUSER_ID > 0) $arItem["FUSER_ID"] = $FUSER_ID; } else { if ($arItem["QUANTITY"] != 0 && !CSaleBasketHelper::isSetParent($arItem)) { self::DoChangeProductQuantity( $arItem, $arItem["QUANTITY"], $isOrderReserved, $isOrderDeducted, $arItem["STORES"], array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId) ); } if ($FUSER_ID > 0) $arItem["FUSER_ID"] = $FUSER_ID; $arItem["ID"] = CSaleBasket::Add(array("ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem); //$arItem["ID"] = CSaleBasket::Add(array("CALLBACK_FUNC" => false, "ORDER_ID" => $orderId, "IGNORE_CALLBACK_FUNC" => "Y") + $arItem); } } } unset($arItem); if ($isOrderConverted != 'N' && !empty($orderBasketPool)) { /** @var Sale\Result $r */ $r = Sale\Compatible\BasketCompatibility::setBasketFields($orderBasketPool); if (!$r->isSuccess(true)) { foreach($r->getErrorMessages() as $error) { $APPLICATION->ThrowException($error); } return false; } } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Items left in the old basket:", array("arOldItems" => $arOldItems), "DSOB5"); // if some items left in the table which are not present in the updated basket, delete them $arSetParentsIDs = array(); foreach ($arOldItems as $key => $arOldItem) { $arOldItem["ID"] = $key; if (CSaleBasketHelper::isSetParent($arOldItem)) { $arSetParentsIDs[] = $arOldItem["ID"]; continue; } else { if ($isOrderConverted == 'N') { // the quantity is negative, so the product is canceled self::DoChangeProductQuantity( $arOldItem, -$arOldItem["QUANTITY"], $isOrderReserved, $isOrderDeducted, $arStoreBarcodeOrderFormData[$arOldItem["ID"]], array("ORDER_ID" => $orderId, "USER_ID" => $userId, "SITE_ID" => $siteId) ); } } CSaleBasket::Delete($key); } foreach ($arSetParentsIDs as $setParentID) CSaleBasket::Delete($setParentID); foreach(GetModuleEvents("sale", "OnDoBasketOrder", true) as $arEvent) ExecuteModuleEventEx($arEvent, array($orderId)); return true; } //************** ADD, UPDATE, DELETE ********************// public static function CheckFields($ACTION, &$arFields, $ID = 0) { global $APPLICATION; static $orderList = array(); $ACTION = mb_strtoupper($ACTION); if (array_key_exists('ID', $arFields)) unset($arFields['ID']); if ($ACTION != "ADD" && (int)$ID <=0) { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_ID_ABSENT'), "ID"); return false; } if ('ADD' == $ACTION) { if (!array_key_exists('CUSTOM_PRICE', $arFields)) $arFields['CUSTOM_PRICE'] = ''; } if (array_key_exists('CUSTOM_PRICE', $arFields) && 'Y' != $arFields['CUSTOM_PRICE']) $arFields['CUSTOM_PRICE'] = 'N'; if (is_set($arFields, "PRODUCT_ID")) $arFields["PRODUCT_ID"] = intval($arFields["PRODUCT_ID"]); if ((is_set($arFields, "PRODUCT_ID") || $ACTION=="ADD") && intval($arFields["PRODUCT_ID"])<=0) { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_PRODUCT_ID_ABSENT'), "PRODUCT_ID"); return false; } if (!array_key_exists('IGNORE_CALLBACK_FUNC', $arFields) || 'Y' != $arFields['IGNORE_CALLBACK_FUNC']) { if ((array_key_exists("CALLBACK_FUNC", $arFields) && !empty($arFields["CALLBACK_FUNC"])) || (array_key_exists("PRODUCT_PROVIDER_CLASS", $arFields) && !empty($arFields["PRODUCT_PROVIDER_CLASS"])) ) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider(array("MODULE" => $arFields["MODULE"], "PRODUCT_PROVIDER_CLASS" => $arFields["PRODUCT_PROVIDER_CLASS"]))) { if (array_key_exists("IBXSaleProductProvider", class_implements($productProvider))) { $providerParams = array( "PRODUCT_ID" => $arFields["PRODUCT_ID"], "QUANTITY" => $arFields["QUANTITY"], "RENEWAL" => $arFields["RENEWAL"], "USER_ID" => (isset($arFields["USER_ID"]) ? $arFields["USER_ID"] : 0), "SITE_ID" => (isset($arFields["LID"]) ? $arFields["LID"] : false), "BASKET_ID" => $ID ); if (isset($arFields['NOTES'])) $providerParams['NOTES'] = $arFields['NOTES']; $arPrice = $productProvider::GetProductData($providerParams); unset($providerParams); } elseif (get_parent_class($productProvider) == 'Bitrix\Sale\SaleProviderBase') { // $productProvider::getCatalogData(); // $productProvider::getProviderData(); // $productProvider::getProviderData(); } } else { $arPrice = CSaleBasket::ExecuteCallbackFunction( $arFields["CALLBACK_FUNC"], $arFields["MODULE"], $arFields["PRODUCT_ID"], $arFields["QUANTITY"], $arFields["RENEWAL"], $arFields["USER_ID"], $arFields["LID"] ); } if (!empty($arPrice) && is_array($arPrice)) { if (isset($arPrice['BASE_PRICE'])) $arPrice['BASE_PRICE'] = roundEx($arPrice['BASE_PRICE'], SALE_VALUE_PRECISION); if (isset($arPrice['DISCOUNT_PRICE'])) $arPrice['DISCOUNT_PRICE'] = roundEx($arPrice['DISCOUNT_PRICE'], SALE_VALUE_PRECISION); if (isset($arPrice['PRICE'])) $arPrice['PRICE'] = roundEx($arPrice['PRICE'], SALE_VALUE_PRECISION); $arFields["PRICE"] = $arPrice["PRICE"]; $arFields["CURRENCY"] = $arPrice["CURRENCY"]; $arFields["CAN_BUY"] = "Y"; $arFields["PRODUCT_PRICE_ID"] = $arPrice["PRODUCT_PRICE_ID"]; $arFields["NOTES"] = $arPrice["NOTES"]; if (!isset($arFields["NAME"])) $arFields["NAME"] = $arPrice["NAME"]; if (isset($arPrice['DISCOUNT_LIST'])) $arFields['DISCOUNT_LIST'] = $arPrice['DISCOUNT_LIST']; } else { if ($ACTION == 'ADD') return false; $arFields["CAN_BUY"] = "N"; } } } if (is_set($arFields, "PRICE") || $ACTION=="ADD") { $arFields["PRICE"] = str_replace(",", ".", $arFields["PRICE"]); $arFields["PRICE"] = floatval($arFields["PRICE"]); } if (is_set($arFields, "DISCOUNT_PRICE") || $ACTION=="ADD") { $arFields["DISCOUNT_PRICE"] = str_replace(",", ".", $arFields["DISCOUNT_PRICE"]); $arFields["DISCOUNT_PRICE"] = floatval($arFields["DISCOUNT_PRICE"]); } if (is_set($arFields, "VAT_RATE") || $ACTION=="ADD") { $arFields["VAT_RATE"] = str_replace(",", ".", $arFields["VAT_RATE"]); $arFields["VAT_RATE"] = floatval($arFields["VAT_RATE"]); } if ((is_set($arFields, "CURRENCY") || $ACTION=="ADD") && $arFields["CURRENCY"] == '') { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_CURRENCY_ABSENT'), "CURRENCY"); return false; } if ((is_set($arFields, "LID") || $ACTION=="ADD") && $arFields["LID"] == '') { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_SITE_ID_ABSENT'), "LID"); return false; } if (is_set($arFields, "ORDER_ID")) { if (!isset($orderList[$arFields["ORDER_ID"]])) { $rsOrders = CSaleOrder::GetList( array(), array('ID' => $arFields["ORDER_ID"]), false, false, array('ID') ); if ($arOrder = $rsOrders->Fetch()) { $orderList[$arFields["ORDER_ID"]] = true; } } if (!isset($orderList[$arFields["ORDER_ID"]])) { $APPLICATION->ThrowException(str_replace("#ID#", $arFields["ORDER_ID"], Loc::getMessage("SKGB_NO_ORDER")), "ORDER_ID"); return false; } } if (is_set($arFields, 'CURRENCY')) { $arFields['CURRENCY'] = (string)$arFields['CURRENCY']; if (empty($arFields['CURRENCY'])) { $APPLICATION->ThrowException(str_replace("#ID#", $arFields["CURRENCY"], Loc::getMessage("SKGB_NO_CURRENCY")), "CURRENCY"); return false; } else { if (empty(self::$currencyList)) { $currencyIterator = Currency\CurrencyTable::getList(array( 'select' => array('CURRENCY'), )); while ($currency = $currencyIterator->fetch()) self::$currencyList[$currency['CURRENCY']] = $currency['CURRENCY']; } if (!isset(self::$currencyList[$arFields['CURRENCY']])) { $APPLICATION->ThrowException(str_replace("#ID#", $arFields["CURRENCY"], Loc::getMessage("SKGB_NO_CURRENCY")), "CURRENCY"); return false; } } } if (is_set($arFields, "LID")) { $dbSite = CSite::GetByID($arFields["LID"]); if (!$dbSite->Fetch()) { $APPLICATION->ThrowException(str_replace("#ID#", $arFields["LID"], Loc::getMessage("SKGB_NO_SITE")), "LID"); return false; } } if ($ACTION != 'ADD') { $existPrice = array_key_exists('PRICE', $arFields); $existCurrency = array_key_exists('CURRENCY', $arFields) && (string)$arFields['CURRENCY'] != ''; if (!$existPrice || !$existCurrency) { $existSiteId = isset($arFields['LID']) && (string)$arFields['LID'] != ''; if (!$existSiteId) { $select = array('ID', 'LID'); if (!$existPrice) $select[] = 'PRICE'; if (!$existCurrency) $select[] = 'CURRENCY'; $basketIterator = CSaleBasket::GetList( array(), array('ID' => $ID), false, false, $select ); if ($basket = $basketIterator->Fetch()) { if (!$existSiteId) $arFields['LID'] = $basket['LID']; if (!$existPrice) $arFields['PRICE'] = $basket['PRICE']; if (!$existCurrency) $arFields['CURRENCY'] = $basket['CURRENCY']; } unset($basket, $basketIterator, $select); } unset($existSiteId); } unset($existCurrency, $existPrice); } if (!empty($arFields['LID']) && !empty($arFields['CURRENCY'])) { if (!isset(self::$currencySiteList[$arFields['LID']])) self::$currencySiteList[$arFields['LID']] = CSaleLang::GetLangCurrency($arFields['LID']); $siteCurrency = self::$currencySiteList[$arFields['LID']]; if ($siteCurrency != $arFields['CURRENCY']) { $arFields["PRICE"] = roundEx(CCurrencyRates::ConvertCurrency($arFields["PRICE"], $arFields["CURRENCY"], $siteCurrency), SALE_VALUE_PRECISION); if (is_set($arFields, "DISCOUNT_PRICE")) $arFields["DISCOUNT_PRICE"] = roundEx(CCurrencyRates::ConvertCurrency($arFields["DISCOUNT_PRICE"], $arFields["CURRENCY"], $siteCurrency), SALE_VALUE_PRECISION); $arFields["CURRENCY"] = $siteCurrency; } unset($siteCurrency); } // Changed by Sigurd, 2007-08-16 if (is_set($arFields, "QUANTITY")) $arFields["QUANTITY"] = floatval($arFields["QUANTITY"]); if ((is_set($arFields, "QUANTITY") || $ACTION=="ADD") && floatval($arFields["QUANTITY"]) <= 0) $arFields["QUANTITY"] = 1; if (is_set($arFields, "DELAY") && $arFields["DELAY"]!="Y") $arFields["DELAY"]="N"; if (is_set($arFields, "CAN_BUY") && $arFields["CAN_BUY"]!="Y") $arFields["CAN_BUY"]="N"; if ((is_set($arFields, "NAME") || $ACTION=="ADD") && $arFields["NAME"] == '') { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_NAME_ABSENT'), "NAME"); return false; } if ($ACTION=="ADD" && !is_set($arFields, "FUSER_ID")) $arFields["FUSER_ID"] = CSaleBasket::GetBasketUserID(false); if ((is_set($arFields, "FUSER_ID") || $ACTION=="ADD") && intval($arFields["FUSER_ID"])<=0) { $APPLICATION->ThrowException(Loc::getMessage('BT_MOD_SALE_BASKET_ERR_FUSER_ID_ABSENT'), "FUSER_ID"); return false; } if (array_key_exists("TYPE", $arFields)) { $arFields["TYPE"] = (int)$arFields["TYPE"]; if ($arFields["TYPE"] != CSaleBasket::TYPE_SET) unset($arFields["TYPE"]); } if (array_key_exists('~TYPE', $arFields)) { unset($arFields['~TYPE']); } if (array_key_exists('CATALOG_XML_ID', $arFields)) { $arFields['CATALOG_XML_ID'] = (string)$arFields['CATALOG_XML_ID']; if ($arFields['CATALOG_XML_ID'] === '') { unset($arFields['CATALOG_XML_ID']); if (array_key_exists('~CATALOG_XML_ID', $arFields)) { unset($arFields['~CATALOG_XML_ID']); } } } if (array_key_exists('PROPS', $arFields)) { if (empty($arFields['PROPS']) || !is_array($arFields['PROPS'])) { unset($arFields['PROPS']); } else { $clearPropList = array(); foreach ($arFields['PROPS'] as $basketProperty) { if (empty($basketProperty) || !is_array($basketProperty) || !isset($basketProperty['NAME'])) continue; $basketProperty['NAME'] = (string)$basketProperty['NAME']; if ($basketProperty['NAME'] == '') continue; $propCode = (isset($basketProperty['CODE']) ? (string)$basketProperty['CODE'] : ''); $propValue = (isset($basketProperty['VALUE']) ? (string)$basketProperty['VALUE'] : ''); $clearProp = array( 'NAME' => $basketProperty['NAME'], 'SORT' => (isset($basketProperty['SORT']) ? (int)$basketProperty['SORT'] : 100) ); if ($propCode != '') $clearProp['CODE'] = $propCode; if ($propValue != '') $clearProp['VALUE'] = $propValue; $clearPropList[] = $clearProp; unset($clearProp, $propValue, $propCode); } unset($basketProperty); if (!empty($clearPropList)) $arFields['PROPS'] = $clearPropList; else unset($arFields['PROPS']); unset($clearPropList); } } return true; } public static function _Update($ID, &$arFields) { global $DB; $ID = (int)$ID; //CSaleBasket::Init(); if (!CSaleBasket::CheckFields("UPDATE", $arFields, $ID)) return false; foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $arEvent) if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields))===false) return false; $arOldFields = false; $updateHistory = isset($arFields["ORDER_ID"]) && (int)$arFields["ORDER_ID"] > 0; $strUpdate = $DB->PrepareUpdate("b_sale_basket", $arFields); if (!empty($strUpdate)) { if ($updateHistory) { $oldOrderIterator = CSaleBasket::GetList( array(), array('ID' => $ID), false, false, array_keys($arFields) ); $arOldFields = $oldOrderIterator->Fetch(); } $strSql = "update b_sale_basket set ".$strUpdate.", DATE_UPDATE = ".$DB->GetNowFunction()." where ID = ".$ID; $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); } else { $updateHistory = false; } if (isset($arFields["PROPS"]) && !empty($arFields["PROPS"]) && is_array($arFields["PROPS"])) { $sql = "delete from b_sale_basket_props where BASKET_ID = ".$ID; $bProductXml = false; $bCatalogXml = false; foreach($arFields["PROPS"] as $prop) { if (!isset($prop['CODE'])) continue; if ($prop["CODE"] == "PRODUCT.XML_ID") $bProductXml = true; if ($prop["CODE"] == "CATALOG.XML_ID") $bCatalogXml = true; if ($bProductXml && $bCatalogXml) break; } if (!$bProductXml) $sql .= " and CODE <> 'PRODUCT.XML_ID'"; if (!$bCatalogXml) $sql .= " and CODE <> 'CATALOG.XML_ID'"; $DB->Query($sql, false, "File: ".__FILE__."<br>Line: ".__LINE__); if (!$bProductXml || !$bCatalogXml) { $sql = "delete from b_sale_basket_props where BASKET_ID = ".$ID." and CODE IS NULL"; $DB->Query($sql, false, "File: ".__FILE__."<br>Line: ".__LINE__); } foreach($arFields["PROPS"] as $prop) { if (!isset($prop["NAME"])) continue; $prop["NAME"] = (string)$prop["NAME"]; if($prop["NAME"] != '') { $arInsert = $DB->PrepareInsert("b_sale_basket_props", $prop); $strSql = "INSERT INTO b_sale_basket_props(BASKET_ID, ".$arInsert[0].") VALUES(".$ID.", ".$arInsert[1].")"; $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); } } } if ($updateHistory) CSaleOrderChange::AddRecordsByFields($arFields["ORDER_ID"], $arOldFields, $arFields, array('PROPS'), "BASKET"); foreach(GetModuleEvents("sale", "OnBasketUpdate", true) as $arEvent) ExecuteModuleEventEx($arEvent, Array($ID, $arFields)); return true; } public static function Update($ID, $arFields) { global $APPLICATION; $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); if (isset($arFields["ID"])) unset($arFields["ID"]); $ID = (int)$ID; CSaleBasket::Init(); if ($isOrderConverted == 'N') { foreach(GetModuleEvents("sale", "OnBeforeBasketUpdate", true) as $arEvent) if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields))===false) return false; } if (is_set($arFields, "QUANTITY") && floatval($arFields["QUANTITY"])<=0) { return CSaleBasket::Delete($ID); } else { if ($isOrderConverted != 'N') { foreach(GetModuleEvents("sale", "OnBeforeBasketUpdateAfterCheck", true) as $event) { if (ExecuteModuleEventEx($event, array($ID, &$arFields)) === false) { return false; } } /** @var \Bitrix\Sale\Result $r */ $r = \Bitrix\Sale\Compatible\BasketCompatibility::update($ID, $arFields); if (!$r->isSuccess()) { foreach($r->getErrorMessages() as $error) { $APPLICATION->ThrowException($error); } return false; } return true; } else { if (is_set($arFields, "QUANTITY")) // if quantity updated and is set parent item, update all set items' quantity { $arBasket = $arFields; $oldQuantity = false; if (!isset($arBasket['TYPE']) || !isset($arBasket['SET_PARENT_ID'])) { $basketIterator = CSaleBasket::GetList( array(), array('ID' => $ID), false, false, array('ID', 'TYPE', 'SET_PARENT_ID', 'QUANTITY') ); if (!($basket = $basketIterator->Fetch())) return false; $arBasket['TYPE'] = (int)$basket['TYPE']; $arBasket['SET_PARENT_ID'] = (int)$basket['SET_PARENT_ID']; $arBasket['QUANTITY'] = $basket['QUANTITY']; $oldQuantity = $basket['QUANTITY']; unset($basket, $basketIterator); } if (CSaleBasketHelper::isSetParent($arBasket)) { if ($oldQuantity === false) { $basketIterator = CSaleBasket::GetList( array(), array('ID' => $ID), false, false, array('ID', 'QUANTITY') ); if (!($basket = $basketIterator->Fetch())) return false; $arBasket['QUANTITY'] = $basket['QUANTITY']; $oldQuantity = $basket['QUANTITY']; unset($basket, $basketIterator); } if ($oldQuantity != $arFields['QUANTITY']) { $dbSetItems = CSaleBasket::GetList( array(), array("SET_PARENT_ID" => $ID, 'TYPE' => false), false, false, array('ID', 'QUANTITY', 'SET_PARENT_ID', 'TYPE') ); while ($arItem = $dbSetItems->Fetch()) { $newQuantity = $arItem['QUANTITY'] / $arBasket['QUANTITY'] * $arFields['QUANTITY']; CSaleBasket::Update( $arItem['ID'], array('QUANTITY' => $newQuantity, 'SET_PARENT_ID' => (int)$arItem['SET_PARENT_ID'], 'TYPE' => (int)$arItem['TYPE']) ); } unset($arItem, $dbSetItems); } } } return CSaleBasket::_Update($ID, $arFields); } } } //************** BASKET USER ********************// public static function Init($bVar = false, $bSkipFUserInit = false) { $bSkipFUserInit = ($bSkipFUserInit !== false); CSaleUser::UpdateSessionSaleUserID(); if(COption::GetOptionString("sale", "encode_fuser_id", "N") != "Y") $_SESSION["SALE_USER_ID"] = intval($_SESSION["SALE_USER_ID"]); if ($_SESSION["SALE_USER_ID"] == '' || $_SESSION["SALE_USER_ID"] === 0) { $ID = CSaleUser::GetID($bSkipFUserInit); $_SESSION["SALE_USER_ID"] = $ID; } } public static function GetBasketUserID($bSkipFUserInit = false) { $bSkipFUserInit = ($bSkipFUserInit !== false); if (!isset($_SESSION["SALE_USER_ID"])) $_SESSION["SALE_USER_ID"] = 0; CSaleBasket::Init(false, $bSkipFUserInit); CSaleUser::UpdateSessionSaleUserID(); $ID = $_SESSION["SALE_USER_ID"]; if ((int)$ID > 0) { return $ID; } else { if (!$bSkipFUserInit) { $GLOBALS["DB"]->StartUsingMasterOnly(); $ID = CSaleUser::Add(); $GLOBALS["DB"]->StopUsingMasterOnly(); $_SESSION["SALE_USER_ID"] = $ID; } } return $ID; } //************** SELECT ********************// public static function GetByID($ID) { global $DB; $ID = (int)$ID; if ($ID <= 0) return false; $strSql = "SELECT * FROM b_sale_basket WHERE ID = ".$ID; $dbBasket = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); if ($arBasket = $dbBasket->Fetch()) return $arBasket; return false; } //************** CALLBACK FUNCTIONS ********************// public static function ExecuteCallbackFunction($callbackFunc = "", $module = "", $productID = 0) { $callbackFunc = trim($callbackFunc); $module = trim($module); $productID = intval($productID); $result = False; if ($callbackFunc <> '') { if ($module <> '' && $module != "main") CModule::IncludeModule($module); $arArgs = array($productID); $numArgs = func_num_args(); if ($numArgs > 3) for ($i = 3; $i < $numArgs; $i++) $arArgs[] = func_get_arg($i); $result = call_user_func_array($callbackFunc, $arArgs); } return $result; /* $callbackFunc = trim($callbackFunc); $productID = IntVal($productID); $module = Trim($module); $quantity = IntVal($quantity); $result = False; if (strlen($callbackFunc) > 0) { if (strlen($module)>0 && $module != "main") CModule::IncludeModule($module); $result = $callbackFunc($PRODUCT_ID, $QUANTITY, $arParams); } return $result; */ } public static function ReReadPrice($callbackFunc = "", $module = "", $productID = 0, $quantity = 0, $renewal = "N", $productProvider = "") { if (CSaleBasket::GetProductProvider(array("MODULE" => $module, "PRODUCT_PROVIDER_CLASS" => $productProvider))) { return $productProvider::GetProductData(array( "PRODUCT_ID" => $productID, "QUANTITY" => $quantity, "RENEWAL" => $renewal )); } else return CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity, $renewal); } public static function OnOrderProduct($callbackFunc = "", $module = "", $productID = 0, $quantity = 0, $productProvider = "") { if (CSaleBasket::GetProductProvider(array("MODULE" => $module, "PRODUCT_PROVIDER_CLASS" => $productProvider))) { $productProvider::GetProductData(array( "PRODUCT_ID" => $productID, "QUANTITY" => $quantity )); } else CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity); return True; } public static function UpdatePrice($ID, $callbackFunc = '', $module = '', $productID = 0, $quantity = 0, $renewal = 'N', $productProvider = '', $notes = '') { $ID = (int)$ID; if ($ID <= 0) return; $callbackFunc = trim((string)$callbackFunc); $productID = (int)$productID; $module = trim((string)$module); $quantity = (float)$quantity; $renewal = ((string)$renewal == 'Y' ? 'Y' : 'N'); $productProvider = trim((string)$productProvider); $notes = trim((string)$notes); $getQuantity = false; $select = array(); if ($callbackFunc == '' && $productProvider == '') { $getQuantity = true; $select['CALLBACK_FUNC'] = true; $select['PRODUCT_PROVIDER_CLASS'] = true; } if ($productID <= 0) { $getQuantity = true; $select['PRODUCT_ID'] = true; } if ($notes == '') $select['NOTES'] = true; if ($getQuantity) { $select['QUANTITY'] = true; $select['MODULE'] = true; } unset($getQuantity); if (!empty($select)) { $basketIterator = CSaleBasket::GetList( array(), array('ID' => $ID), false, false, array_keys($select) ); $basket = $basketIterator->Fetch(); if (empty($basket)) return; if (isset($select['CALLBACK_FUNC'])) $callbackFunc = trim((string)$basket['CALLBACK_FUNC']); if (isset($select['PRODUCT_PROVIDER_CLASS'])) $productProvider = trim((string)$basket['PRODUCT_PROVIDER_CLASS']); if (isset($select['MODULE'])) $module = trim((string)$basket['MODULE']); if (isset($select['PRODUCT_ID'])) $productID = (int)$basket['PRODUCT_ID']; if (isset($select['QUANTITY'])) $quantity = (float)$basket['QUANTITY']; if (isset($select['NOTES'])) $notes = $basket['NOTES']; unset($basket, $basketIterator); } $providerName = CSaleBasket::GetProductProvider(array("MODULE" => $module, "PRODUCT_PROVIDER_CLASS" => $productProvider)); if ($providerName) { $arFields = $providerName::GetProductData(array( "PRODUCT_ID" => $productID, "QUANTITY" => $quantity, "RENEWAL" => $renewal, "BASKET_ID" => $ID, "NOTES" => $notes )); } else { $arFields = CSaleBasket::ExecuteCallbackFunction($callbackFunc, $module, $productID, $quantity, $renewal); } if (!empty($arFields) && is_array($arFields)) { $arFields["CAN_BUY"] = "Y"; CSaleBasket::Update($ID, $arFields); } else { $arFields = array( "CAN_BUY" => "N" ); CSaleBasket::Update($ID, $arFields); } } /** * @deprecated deprecated since sale 14.0.6 * @see CSaleBasket::DoSaveOrderBasket * * @param int $orderID * @param int $fuserID * @param mixed|string $strLang * @param bool $arDiscounts * @return bool * @throws \Bitrix\Main\ArgumentNullException */ public static function OrderBasket($orderID, $fuserID = 0, $strLang = SITE_ID, $arDiscounts = False) { $orderID = (int)$orderID; if ($orderID <= 0) return false; $fuserID = (int)$fuserID; if ($fuserID <= 0) $fuserID = (int)CSaleBasket::GetBasketUserID(true); if ($fuserID <= 0) return false; $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); $arOrder = array(); if (empty($arOrder)) { $rsOrders = CSaleOrder::GetList( array(), array('ID' => $orderID), false, false, array('ID', 'USER_ID', 'RECURRING_ID', 'LID', 'RESERVED') ); if (!($arOrder = $rsOrders->Fetch())) return false; $arOrder['RECURRING_ID'] = (int)$arOrder['RECURRING_ID']; } $boolRecurring = $arOrder['RECURRING_ID'] > 0; $found = false; $dbBasketList = CSaleBasket::GetList( array("PRICE" => "DESC"), array("FUSER_ID" => $fuserID, "LID" => $strLang, "ORDER_ID" => 0), false, false, array( 'ID', 'ORDER_ID', 'PRODUCT_ID', 'MODULE', 'CAN_BUY', 'DELAY', 'ORDER_CALLBACK_FUNC', 'PRODUCT_PROVIDER_CLASS', 'QUANTITY', 'CUSTOM_PRICE' ) ); while ($arBasket = $dbBasketList->Fetch()) { $arFields = array(); if ($arBasket["DELAY"] == "N" && $arBasket["CAN_BUY"] == "Y") { if (!empty($arBasket["ORDER_CALLBACK_FUNC"]) || !empty($arBasket["PRODUCT_PROVIDER_CLASS"])) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { $arQuery = array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY" => $arBasket["QUANTITY"], 'BASKET_ID' => $arBasket['ID'] ); if ($boolRecurring) { $arQuery['RENEWAL'] = 'Y'; $arQuery['USER_ID'] = $arOrder['USER_ID']; $arQuery['SITE_ID'] = $strLang; } $arFields = $productProvider::OrderProduct($arQuery); } else { if ($boolRecurring) { $arFields = CSaleBasket::ExecuteCallbackFunction( $arBasket["ORDER_CALLBACK_FUNC"], $arBasket["MODULE"], $arBasket["PRODUCT_ID"], $arBasket["QUANTITY"], 'Y', $arOrder['USER_ID'], $strLang ); } else { $arFields = CSaleBasket::ExecuteCallbackFunction( $arBasket["ORDER_CALLBACK_FUNC"], $arBasket["MODULE"], $arBasket["PRODUCT_ID"], $arBasket["QUANTITY"] ); } } if (!empty($arFields) && is_array($arFields)) { $arFields["CAN_BUY"] = "Y"; $arFields["ORDER_ID"] = $orderID; $arBasket['CUSTOM_PRICE'] = (string)$arBasket['CUSTOM_PRICE']; if ($arBasket['CUSTOM_PRICE'] == 'Y') { if (array_key_exists('PRICE', $arFields)) unset($arFields['PRICE']); if (array_key_exists('DISCOUNT_PRICE', $arFields)) unset($arFields['DISCOUNT_PRICE']); if (array_key_exists('CURRENCY', $arFields)) unset($arFields['CURRENCY']); if (array_key_exists('DISCOUNT_VALUE', $arFields)) unset($arFields['DISCOUNT_VALUE']); if (array_key_exists('DISCOUNT_NAME', $arFields)) unset($arFields['DISCOUNT_NAME']); if (array_key_exists('DISCOUNT_COUPON', $arFields)) unset($arFields['DISCOUNT_COUPON']); if (array_key_exists('DISCOUNT_LIST', $arFields)) unset($arFields['DISCOUNT_LIST']); if (array_key_exists('DISCOUNT', $arFields)) unset($arFields['DISCOUNT']); } } else { $arFields = array( 'CAN_BUY' => 'N' ); $removeCoupon = DiscountCouponsManager::deleteApplyByProduct(array( 'MODULE' => $arBasket['MODULE'], 'PRODUCT_ID' => $arBasket['PRODUCT_ID'], 'BASKET_ID' => $arBasket['ID'] )); } } else { $arFields["ORDER_ID"] = $orderID; } if (!empty($arFields)) { if ($isOrderConverted != 'N') { $found = true; if (!\Bitrix\Sale\Compatible\DiscountCompatibility::isInited()) \Bitrix\Sale\Compatible\DiscountCompatibility::init(); if (\Bitrix\Sale\Compatible\DiscountCompatibility::isInited()) \Bitrix\Sale\Compatible\DiscountCompatibility::setRepeatSave(true); } if (CSaleBasket::Update($arBasket["ID"], $arFields)) { $_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID]--; } } } }//end of while if ($_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID] < 0) $_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID] = 0; foreach(GetModuleEvents("sale", "OnBasketOrder", true) as $arEvent) { ExecuteModuleEventEx($arEvent, array($orderID, $fuserID, $strLang, $arDiscounts)); } if ($isOrderConverted != 'N' && $found) { $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER); /** @var Sale\Order $orderClass */ $orderClass = $registry->getOrderClassName(); if ($order = $orderClass::load($orderID)) { if (\Bitrix\Sale\Compatible\DiscountCompatibility::isInited()) \Bitrix\Sale\Compatible\DiscountCompatibility::setRepeatSave(false); $discounts = $order->getDiscount(); $discounts->save(); unset($discounts); } unset($order); } //reservation if ($arOrder['RESERVED'] != "Y" && COption::GetOptionString("sale", "product_reserve_condition") == "O") { if (!CSaleOrder::ReserveOrder($orderID, "Y")) return false; } return true; } public static function OrderPayment($orderID, $bPaid, $recurringID = 0) { CSaleBasket::OrderDelivery($orderID, $bPaid, $recurringID); } public static function OrderDelivery($orderID, $bPaid, $recurringID = 0) { global $DB, $APPLICATION; $orderID = intval($orderID); if ($orderID <= 0) return False; $bPaid = ($bPaid ? True : False); $recurringID = intval($recurringID); $arOrder = CSaleOrder::GetByID($orderID); if ($arOrder) { $dbBasketList = CSaleBasket::GetList( array("NAME" => "ASC"), array("ORDER_ID" => $orderID) ); while ($arBasket = $dbBasketList->Fetch()) { if ($arBasket["PAY_CALLBACK_FUNC"] <> '' || $arBasket["PRODUCT_PROVIDER_CLASS"] <> '') { if ($bPaid) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { $arFields = $productProvider::DeliverProduct(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "USER_ID" => $arOrder["USER_ID"], "PAID" => $bPaid, "ORDER_ID" => $orderID, 'BASKET_ID' => $arBasket['ID'] )); } else { $arFields = CSaleBasket::ExecuteCallbackFunction( $arBasket["PAY_CALLBACK_FUNC"], $arBasket["MODULE"], $arBasket["PRODUCT_ID"], $arOrder["USER_ID"], $bPaid, $orderID, $arBasket["QUANTITY"] ); } if ($arFields && is_array($arFields) && count($arFields) > 0) { $arFields["ORDER_ID"] = $orderID; $arFields["REMAINING_ATTEMPTS"] = (Defined("SALE_PROC_REC_ATTEMPTS") ? SALE_PROC_REC_ATTEMPTS : 3); $arFields["SUCCESS_PAYMENT"] = "Y"; if ($recurringID > 0) CSaleRecurring::Update($recurringID, $arFields); else CSaleRecurring::Add($arFields); } elseif ($recurringID > 0) { CSaleRecurring::Delete($recurringID); } } else { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { $productProvider::DeliverProduct(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "USER_ID" => $arOrder["USER_ID"], "PAID" => $bPaid, "ORDER_ID" => $orderID, 'BASKET_ID' => $arBasket['ID'] )); } else { CSaleBasket::ExecuteCallbackFunction( $arBasket["PAY_CALLBACK_FUNC"], $arBasket["MODULE"], $arBasket["PRODUCT_ID"], $arOrder["USER_ID"], $bPaid, $orderID, $arBasket["QUANTITY"] ); } $dbRecur = CSaleRecurring::GetList( array(), array( "USER_ID" => $arOrder["USER_ID"], "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "MODULE" => $arBasket["MODULE"] ) ); while ($arRecur = $dbRecur->Fetch()) { CSaleRecurring::Delete($arRecur["ID"]); } } } } } } public static function OrderCanceled($orderID, $bCancel) { global $DB; $orderID = intval($orderID); if ($orderID <= 0) return False; $bCancel = ($bCancel ? True : False); $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); if ($isOrderConverted != 'N') { \Bitrix\Sale\Compatible\OrderCompatibility::cancel($orderID, $bCancel?'Y':'N'); } else { $arOrder = CSaleOrder::GetByID($orderID); if ($arOrder) { $dbBasketList = CSaleBasket::GetList( array("NAME" => "ASC"), array("ORDER_ID" => $orderID) ); while ($arBasket = $dbBasketList->Fetch()) { if ($arBasket["CANCEL_CALLBACK_FUNC"] <> '' && $arBasket["PRODUCT_PROVIDER_CLASS"] == '') { $arFields = CSaleBasket::ExecuteCallbackFunction( $arBasket["CANCEL_CALLBACK_FUNC"], $arBasket["MODULE"], $arBasket["PRODUCT_ID"], $arBasket["QUANTITY"], $bCancel ); } } } } } /** * Method is called to reserve all products in the order basket * * @param int $orderID * @param bool $bUndoReservation * @return mixed array */ public static function OrderReservation($orderID, $bUndoReservation = false) { global $APPLICATION; if (defined("SALE_DEBUG") && SALE_DEBUG) { if ($bUndoReservation) CSaleHelper::WriteToLog("OrderReservation: undo started", array("orderId" => $orderID), "OR1"); else CSaleHelper::WriteToLog("OrderReservation: started", array("orderId" => $orderID), "OR1"); } $orderID = (int)$orderID; if ($orderID <= 0) return false; $arResult = array(); $arSetData = array(); $arOrder = CSaleOrder::GetByID($orderID); if ($arOrder) { $obStackExp = $APPLICATION->GetException(); if (is_object($obStackExp)) { $APPLICATION->ResetException(); } $dbBasketList = CSaleBasket::GetList( array(), array("ORDER_ID" => $orderID) ); while ($arBasket = $dbBasketList->Fetch()) { if ($bUndoReservation && $arBasket["RESERVED"] == "N" && COption::GetOptionString("catalog", "enable_reservation") != "N") continue; if (CSaleBasketHelper::isSetParent($arBasket)) continue; if (CSaleBasketHelper::isSetItem($arBasket)) $arSetData[$arBasket["PRODUCT_ID"]] = $arBasket["SET_PARENT_ID"]; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Reserving product #".$arBasket["PRODUCT_ID"], array(), "OR2"); /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveProduct", array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY_ADD" => $arBasket["QUANTITY"], "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N" ), "OR3" ); } if ($arOrder["DEDUCTED"] == "Y") // order already deducted, don't reserve it { $res = array("RESULT" => true, "QUANTITY_RESERVED" => 0); if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Order already deducted. Product won't be reserved.", array(), "OR5"); } else { $res = $productProvider::ReserveProduct(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY_ADD" => $arBasket["QUANTITY"], "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N", )); } if ($res["RESULT"]) { $arResult[$arBasket["PRODUCT_ID"]] = $res["QUANTITY_RESERVED"]; $arUpdateFields = array("RESERVED" => ($bUndoReservation) ? "N" : "Y"); if (!$bUndoReservation && isset($res["QUANTITY_NOT_RESERVED"])) $arUpdateFields["RESERVE_QUANTITY"] = $res["QUANTITY_NOT_RESERVED"]; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reserved successfully", array("arUpdateFields" => $arUpdateFields), "OR4"); if (!isset($res["QUANTITY_RESERVED"]) || (isset($res["QUANTITY_RESERVED"]) && $res["QUANTITY_RESERVED"] != 0)) CSaleBasket::Update($arBasket["ID"], $arUpdateFields); } else { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reservation error", array(), "OR4"); CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "N")); } if ($ex = $APPLICATION->GetException()) { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveProduct - Exception", array( "ID" => $arBasket["PRODUCT_ID"], "MESSAGE" => $ex->GetString(), "CODE" => $ex->GetID(), ), "OR4" ); } $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["ID"] = $arBasket["PRODUCT_ID"]; $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["MESSAGE"] = $ex->GetString(); $arResult["ERROR"][$arBasket["PRODUCT_ID"]]["CODE"] = $ex->GetID(); } } } if (is_object($obStackExp)) { $APPLICATION->ResetException(); $APPLICATION->ThrowException($obStackExp); } } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("OrderReservation result", array("arResult" => $arResult), "OR6"); return $arResult; } /** * Method is called to reserve one product in the basket * (it's a wrapper around product provider ReserveProduct method to use for the single product) * * @param int $basketID * @param float $deltaQuantity - quantity to reserve * @param bool $isOrderDeducted * @return mixed array */ public static function ReserveBasketProduct($basketID, $deltaQuantity, $isOrderDeducted = false) { global $APPLICATION; if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "ReserveBasketProduct: reserving product #".$basketID, array( "basketId" => $basketID, "deltaQuantity" => $deltaQuantity ), "RBP1" ); } $arResult = array(); $basketID = (int)$basketID; if ($basketID <= 0) { $arResult["RESULT"] = false; return $arResult; } $deltaQuantity = (float)$deltaQuantity; if ($deltaQuantity < 0) { $deltaQuantity = abs($deltaQuantity); $bUndoReservation = true; } else { $bUndoReservation = false; } $arBasket = CSaleBasket::GetByID($basketID); if ($arBasket) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::ReserveProduct", array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY_ADD" => $deltaQuantity, "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N", "ORDER_DEDUCTED" => ($isOrderDeducted) ? "Y" : "N" ), "RBP2" ); } $res = $productProvider::ReserveProduct(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY_ADD" => $deltaQuantity, "UNDO_RESERVATION" => ($bUndoReservation) ? "Y" : "N", "ORDER_DEDUCTED" => ($isOrderDeducted) ? "Y" : "N" )); $updateResult = true; $arResult["RESULT"] = $res["RESULT"]; if ($res["RESULT"]) { $arResult[$arBasket["ID"]] = $res["QUANTITY_RESERVED"]; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reserved successfully", array(), "RBP3"); if ($bUndoReservation) { $updateResult = CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "N")); } elseif (!isset($res["QUANTITY_RESERVED"]) || (isset($res["QUANTITY_RESERVED"]) && $res["QUANTITY_RESERVED"] != 0)) { $updateResult = CSaleBasket::Update($arBasket["ID"], array("RESERVED" => "Y")); } } else { $arResult["ERROR"]["PRODUCT_ID"] = $arBasket["PRODUCT_ID"]; $updateResult = false; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." reservation error", array(), "RBP3"); if (isset($res["QUANTITY_NOT_RESERVED"])) { CSaleBasket::Update($arBasket["ID"], array("RESERVE_QUANTITY" => $res["QUANTITY_NOT_RESERVED"])); } } if (!$updateResult && $ex = $APPLICATION->GetException()) { $arResult["ERROR"]["MESSAGE"] = $ex->GetString(); $arResult["ERROR"]["CODE"] = $ex->GetID(); } } } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("ReserveBasketProduct result", array("arResult" => $arResult), "RBP5"); return $arResult; } /** * Method is called to deduct one product in the basket * (it's a wrapper around product provider DeductProduct method to use for the single product) * * @param int $basketID * @param float $deltaQuantity - quantity to reserve * @param array $arStoreBarcodeData * @return mixed array */ public static function DeductBasketProduct($basketID, $deltaQuantity, $arStoreBarcodeData = array()) { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog("DeductBasketProduct", array( "basketId" => $basketID, "deltaQuantity" => $deltaQuantity, "storeBarcodeData" => $arStoreBarcodeData ), "DBP1" ); } global $APPLICATION; $arResult = array(); $basketID = (int)$basketID; if ($basketID <= 0) { $arResult["RESULT"] = false; return $arResult; } $deltaQuantity = (float)$deltaQuantity; if ($deltaQuantity < 0) { $deltaQuantity = abs($deltaQuantity); $bUndoDeduction = true; } else { $bUndoDeduction = false; } $arBasket = CSaleBasket::GetByID($basketID); if ($arBasket) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::DeductProduct", array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY" => (empty($arStoreBarcodeData)) ? $deltaQuantity : 0, "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N", "EMULATE" => "N", "PRODUCT_RESERVED" => $arBasket["RESERVED"], "STORE_DATA" => $arStoreBarcodeData ), "DBP2" ); } if ($bUndoDeduction) { $dbStoreBarcode = CSaleStoreBarcode::GetList( array(), array("BASKET_ID" => $arBasket["ID"]), false, false, array("ID", "BASKET_ID", "BARCODE", "QUANTITY", "STORE_ID") ); while ($arRes = $dbStoreBarcode->GetNext()) $arStoreBarcodeData[] = $arRes; } $res = $productProvider::DeductProduct(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "QUANTITY" => (empty($arStoreBarcodeData)) ? $deltaQuantity : 0, "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N", "EMULATE" => "N", "PRODUCT_RESERVED" => $arBasket["RESERVED"], "STORE_DATA" => $arStoreBarcodeData )); $arResult["RESULT"] = $res["RESULT"]; if ($res["RESULT"]) { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." deducted successfully", array(), "DBP3"); } else { $arResult["ERROR"]["PRODUCT_ID"] = $arBasket["PRODUCT_ID"]; if ($ex = $APPLICATION->GetException()) { $arResult["ERROR"]["MESSAGE"] = $ex->GetString(); $arResult["ERROR"]["CODE"] = $ex->GetID(); } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Product #".$arBasket["PRODUCT_ID"]." deduction error", array(), "DBP4"); } } } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DeductBasketProduct result", array("arResult" => $arResult), "DBP5"); return $arResult; } /** * Method is called to deduct all products of the order or undo deduction * * @param int $orderID * @param bool $bUndoDeduction * @param int $recurringID * @param bool $bAutoDeduction * @param array $arStoreBarcodeOrderFormData * @return mixed array */ public static function OrderDeduction($orderID, $bUndoDeduction = false, $recurringID = 0, $bAutoDeduction = true, $arStoreBarcodeOrderFormData = array()) { global $APPLICATION; static $storesCount = NULL; static $bAutoDeductionAllowed = NULL; $bRealDeductionAllowed = true; $defaultDeductionStore = 0; $arSavedStoreBarcodeData = array(); $arItems = array(); $arResult = array(); $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "OrderDeduction: started", array( "orderID" => $orderID, "bUndoDeduction" => intval($bUndoDeduction), "bAutoDeduction" => intval($bAutoDeduction), "arStoreBarcodeOrderFormData" => $arStoreBarcodeOrderFormData ), "OD1" ); } //TODO - recurringID - ? $orderID = intval($orderID); if ($orderID <= 0) { $arResult["RESULT"] = false; return $arResult; } if ($isOrderConverted != 'N') { $ship = !$bUndoDeduction; /** @var \Bitrix\Sale\Result $r */ $r = \Bitrix\Sale\Compatible\OrderCompatibility::shipment($orderID, $ship, $arStoreBarcodeOrderFormData); if (!$r->isSuccess(true)) { foreach($r->getErrorMessages() as $error) { // $APPLICATION->ThrowException($error); $arResult["ERROR"]["MESSAGE"] = $error; // $arResult["ERROR"]["CODE"] = $ex->GetID(); break; } $arResult["RESULT"] = false; return $arResult; } $arResult["RESULT"] = true; return $arResult; } $dbBasketList = CSaleBasket::GetList( array(), array("ORDER_ID" => $orderID), false, false, array('ID', 'LID', 'PRODUCT_ID', 'PRODUCT_PROVIDER_CLASS', 'MODULE', 'BARCODE_MULTI', 'QUANTITY', 'RESERVED', 'TYPE', 'SET_PARENT_ID') ); //check basket items and emulate deduction while ($arBasket = $dbBasketList->Fetch()) { if (CSaleBasketHelper::isSetParent($arBasket)) continue; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Deducting product #".$arBasket["PRODUCT_ID"], array(), "OD2"); /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arBasket)) { if (is_null($storesCount)) $storesCount = intval($productProvider::GetStoresCount(array("SITE_ID" => $arBasket["LID"]))); if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("stores count: ".$storesCount, array(), "OD3"); if (is_null($bAutoDeductionAllowed)) { $defaultDeductionStore = COption::GetOptionString("sale", "deduct_store_id", "", $arBasket["LID"]); if ($storesCount == 1 || $storesCount == -1 || intval($defaultDeductionStore) > 0) // if stores' count = 1 or stores aren't used or default deduction store is defined $bAutoDeductionAllowed = true; else $bAutoDeductionAllowed = false; } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("auto deduction allowed: ".intval($bAutoDeductionAllowed), array(), "OD4"); if ($bAutoDeduction && !$bAutoDeductionAllowed && !$bUndoDeduction) { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DDCT_AUTO_DEDUCT_WRONG_STORES_QUANTITY", array(), "OD5"); $APPLICATION->ThrowException(Loc::getMessage("DDCT_AUTO_DEDUCT_WRONG_STORES_QUANTITY"), "DDCT_WRONG_STORES_QUANTITY"); $bRealDeductionAllowed = false; } else if ($bAutoDeduction && $arBasket["BARCODE_MULTI"] == "Y" && !$bUndoDeduction) { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("DDCT_AUTO_DEDUCT_BARCODE_MULTI", array(), "OD6"); $APPLICATION->ThrowException(Loc::getMessage("DDCT_AUTO_DEDUCT_BARCODE_MULTI", array("#PRODUCT_ID#" => $arBasket["PRODUCT_ID"])), "DDCT_CANT_DEDUCT_BARCODE_MULTI"); $bRealDeductionAllowed = false; } else { //get saved store & barcode data if stores are used to know where to return products if ($bUndoDeduction && $storesCount > 0) { $dbStoreBarcode = CSaleStoreBarcode::GetList( array(), array("BASKET_ID" => $arBasket["ID"]), false, false, array("ID", "BASKET_ID", "BARCODE", "QUANTITY", "STORE_ID") ); while ($arStoreBarcode = $dbStoreBarcode->Fetch()) { $arSavedStoreBarcodeData[$arBasket["ID"]][] = $arStoreBarcode; } if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "OrderDeduction: CSaleStoreBarcode data (stores) to return products to", array( "arSavedStoreBarcodeData" => $arSavedStoreBarcodeData ), "OD7" ); } } $arFields = array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "EMULATE" => "Y", "PRODUCT_RESERVED" => $arBasket["RESERVED"], "UNDO_DEDUCTION" => ($bUndoDeduction) ? "Y" : "N" ); if ($bUndoDeduction) { if ($storesCount > 0) { $arFields["QUANTITY"] = 0; //won't be used during deduction $arFields["STORE_DATA"] = $arSavedStoreBarcodeData[$arBasket["ID"]]; } else { $arFields["QUANTITY"] = $arBasket["QUANTITY"]; $arFields["STORE_DATA"] = array(); } } else { if ($storesCount == 1) { $arFields["QUANTITY"] = 0; if ($bAutoDeduction) //get the only possible store to deduct from it { if ( $arProductStore = $productProvider::GetProductStores(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "SITE_ID" => $arBasket["LID"], 'BASKET_ID' => $arBasket['ID'] )) ) { $arFields["STORE_DATA"] = array( "0" => array( "STORE_ID" => $arProductStore[0]["STORE_ID"], "QUANTITY" => $arBasket["QUANTITY"], "AMOUNT" => $arProductStore[0]["AMOUNT"] ) ); } else { $arFields["STORE_DATA"] = array(); } } else { $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]]; } } else if (intval($defaultDeductionStore) > 0) // if default deduction store is defined { $arFields["QUANTITY"] = 0; if ($bAutoDeduction) { if ( $arProductStore = $productProvider::GetProductStores(array( "PRODUCT_ID" => $arBasket["PRODUCT_ID"], "SITE_ID" => $arBasket["LID"], 'BASKET_ID' => $arBasket['ID'] )) ) { foreach ($arProductStore as $storeData) { if ($storeData["STORE_ID"] == intval($defaultDeductionStore)) { $arFields["STORE_DATA"] = array( "0" => array( "STORE_ID" => $storeData["STORE_ID"], "QUANTITY" => $arBasket["QUANTITY"], "AMOUNT" => $storeData["AMOUNT"] ) ); break; } } } else { $arFields["STORE_DATA"] = array(); } } else { $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]]; } } else if ($storesCount > 1) { $arFields["QUANTITY"] = 0; //won't be used during deduction $arFields["STORE_DATA"] = $arStoreBarcodeOrderFormData[$arBasket["ID"]]; } else //store control not used { $arFields["QUANTITY"] = $arBasket["QUANTITY"]; $arFields["STORE_DATA"] = array(); } } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Emulating ::DeductProduct call", array("arFields" => $arFields), "OD7"); $eventParams = array( 'ORDER_ID' => $orderID, 'RECURRING_ID' => $recurringID, 'AUTO_DEDUCTION' => $bAutoDeduction, 'STORE_DATA' => $arStoreBarcodeOrderFormData ); foreach (GetModuleEvents('sale', 'OnBeforeBasketDeductProduct', true) as $event) { if (ExecuteModuleEventEx($event, array($eventParams, $arBasket, &$arFields)) === false) { if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Emulating ::DeductProduct call - error", array(), "OD7-1"); $arResult["RESULT"] = false; return $arResult; } } unset($eventParams); //emulate deduction $res = $productProvider::DeductProduct($arFields); if ($res["RESULT"]) { $arBasket["FIELDS"] = $arFields; $arItems[] = $arBasket; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Emulating ::DeductProduct call - success", array(), "OD8"); } else { $bRealDeductionAllowed = false; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Emulating ::DeductProduct call - error", array(), "OD9"); } } if ($ex = $APPLICATION->GetException()) { $arResult["ERROR"]["MESSAGE"] = $ex->GetString(); $arResult["ERROR"]["CODE"] = $ex->GetID(); } if (!$bRealDeductionAllowed) break; } } // real deduction if ($bRealDeductionAllowed) { $bProductsDeductedSuccessfully = true; $arDeductedItems = array(); foreach ($arItems as $arItem) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arItem)) { $arItem["FIELDS"]["EMULATE"] = "N"; if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Call ::DeductProduct", array("fields" => $arItem["FIELDS"]), "OD10"); // finally real deduction $res = $productProvider::DeductProduct($arItem["FIELDS"]); if ($res["RESULT"]) { $arDeductedItems[] = $arItem; if (!$bUndoDeduction && $storesCount > 0) { if ($bAutoDeduction) { $arStoreBarcodeFields = array( "BASKET_ID" => $arItem["ID"], "BARCODE" => "", "STORE_ID" => array_pop(array_keys($res["STORES"])), "QUANTITY" => $arItem["QUANTITY"], "CREATED_BY" => ((intval($GLOBALS["USER"]->GetID())>0) ? intval($GLOBALS["USER"]->GetID()) : ""), "MODIFIED_BY" => ((intval($GLOBALS["USER"]->GetID())>0) ? intval($GLOBALS["USER"]->GetID()) : ""), ); if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Call CSaleStoreBarcode::Add (auto deduction = true)", array("arStoreBarcodeFields" => $arStoreBarcodeFields), "OD11"); CSaleStoreBarcode::Add($arStoreBarcodeFields); } } if ($bUndoDeduction) { $dbStoreBarcode = CSaleStoreBarcode::GetList(array(), array("BASKET_ID" => $arItem["ID"]), false, false, array("ID", "BASKET_ID")); while ($arStoreBarcode = $dbStoreBarcode->GetNext()) CSaleStoreBarcode::Delete($arStoreBarcode["ID"]); } $tmpRes = ($bUndoDeduction) ? "N" : "Y"; CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => $tmpRes)); // set parent deducted status if ($bUndoDeduction) { if (CSaleBasketHelper::isSetItem($arItem)) CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "N")); } else { if (CSaleBasketHelper::isSetItem($arItem) && CSaleBasketHelper::isSetDeducted($arItem["SET_PARENT_ID"])) CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "Y")); } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Call ::DeductProduct - Success (DEDUCTED = ".$tmpRes.")", array(), "OD11"); } else { CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => "N")); $bProductsDeductedSuccessfully = false; if ($ex = $APPLICATION->GetException()) { $arResult["ERROR"]["MESSAGE"] = $ex->GetString(); $arResult["ERROR"]["CODE"] = $ex->GetID(); } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("Call ::DeductProduct - Error (DEDUCTED = N)", array(), "OD12"); break; } } } if ($bProductsDeductedSuccessfully) { $arResult["RESULT"] = true; } else //revert real deduction if error happened { $arFields = array(); foreach ($arDeductedItems as $arItem) { /** @var $productProvider IBXSaleProductProvider */ if ($productProvider = CSaleBasket::GetProductProvider($arItem)) { if ($storesCount > 0) { $arFields = array( "PRODUCT_ID" => $arItem["PRODUCT_ID"], "QUANTITY" => $arItem["QUANTITY"], "UNDO_DEDUCTION" => "Y", "EMULATE" => "N", "PRODUCT_RESERVED" => $arItem["FIELDS"]["PRODUCT_RESERVED"], "STORE_DATA" => $arItem["FIELDS"]["STORE_DATA"] //during auto deduction ); } else { $arFields = array( "PRODUCT_ID" => $arItem["PRODUCT_ID"], "QUANTITY" => $arItem["QUANTITY"], "UNDO_DEDUCTION" => "Y", "PRODUCT_RESERVED" => $arItem["FIELDS"]["PRODUCT_RESERVED"], "EMULATE" => "N", ); } if (defined("SALE_DEBUG") && SALE_DEBUG) { CSaleHelper::WriteToLog( "Call ::DeductProduct - Revert deduction", array( "storesCount" => $storesCount, "arFields" => $arFields ), "OD13" ); } $res = $productProvider::DeductProduct($arFields); if ($res["RESULT"]) { CSaleBasket::Update($arItem["ID"], array("DEDUCTED" => "N")); if (CSaleBasketHelper::isSetItem($arItem)) // todo - possibly not all the time, but once CSaleBasket::Update($arItem["SET_PARENT_ID"], array("DEDUCTED" => "N")); } } } $arResult["RESULT"] = false; } } else { $arResult["RESULT"] = false; } if (defined("SALE_DEBUG") && SALE_DEBUG) CSaleHelper::WriteToLog("OrderDeduction - result", array("arResult" => $arResult), "OD14"); return $arResult; } public static function TransferBasket($FROM_FUSER_ID, $TO_FUSER_ID) { $FROM_FUSER_ID = (int)$FROM_FUSER_ID; $TO_FUSER_ID = (int)$TO_FUSER_ID; if ($TO_FUSER_ID > 0 && $FROM_FUSER_ID > 0) { $_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID] = 0; $dbTmp = CSaleUser::GetList(array("ID" => $TO_FUSER_ID)); if (!empty($dbTmp)) { $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER); /** @var Sale\Basket $basketClass */ $basketClass = $registry->getBasketClassName(); $basketToFUser = $basketClass::loadItemsForFUser($TO_FUSER_ID, SITE_ID); $basketFromFUser = $basketClass::loadItemsForFUser($FROM_FUSER_ID, SITE_ID); if ($basketFromFUser->count() > 0) { $_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID] = $basketToFUser->count(); /** @var Sale\BasketItem $basketItemFrom */ foreach ($basketFromFUser as $basketItemFrom) { /** @var Sale\BasketItem $basketItem */ $basketItem = $basketToFUser->getExistsItemByItem($basketItemFrom); if ($basketItem) { $basketItem->setField('QUANTITY', $basketItem->getQuantity() + $basketItemFrom->getQuantity()); $basketItemFrom->delete(); } else { $basketItemFrom->setFieldNoDemand('FUSER_ID', $TO_FUSER_ID); $_SESSION["SALE_BASKET_NUM_PRODUCTS"][SITE_ID]++; } } $basketToFUser->save(); $basketFromFUser->save(); } Sale\BasketComponentHelper::updateFUserBasket($TO_FUSER_ID, SITE_ID); Sale\BasketComponentHelper::updateFUserBasket($FROM_FUSER_ID, SITE_ID); Sale\Discount\RuntimeCache\FuserCache::getInstance()->clean(); return true; } } return false; } public static function UpdateBasketPrices($fuserID, $siteID, array $options = array()) { $fuserID = (int)$fuserID; if ($fuserID <= 0) return false; $siteID = (string)$siteID; if ($siteID == '') $siteID = SITE_ID; $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); if ($isOrderConverted != 'N') { self::refreshFUserBasket($fuserID, $siteID, $options); } else { $dbBasketItems = CSaleBasket::GetList( array("ALL_PRICE" => "DESC"), array( "FUSER_ID" => $fuserID, "LID" => $siteID, "ORDER_ID" => "NULL", "SUBSCRIBE" => "N" ), false, false, array( "ID", "MODULE", "PRODUCT_ID", "QUANTITY", "CALLBACK_FUNC", "PRODUCT_PROVIDER_CLASS", "CAN_BUY", "DELAY", "NOTES", "TYPE", "SET_PARENT_ID" ) ); while ($arItem = $dbBasketItems->Fetch()) { $basketItems[] = $arItem; } if (!empty($basketItems) && is_array($basketItems)) { $basketItems = getRatio($basketItems); foreach ($basketItems as $basketItem) { $fields = array(); $basketItem['CALLBACK_FUNC'] = (string)$basketItem['CALLBACK_FUNC']; $basketItem['PRODUCT_PROVIDER_CLASS'] = (string)$basketItem['PRODUCT_PROVIDER_CLASS']; if (strval(trim($basketItem['PRODUCT_PROVIDER_CLASS'])) !== '' || strval(trim($basketItem['CALLBACK_FUNC'])) !== '') { $basketItem['MODULE'] = (string)$basketItem['MODULE']; $basketItem['PRODUCT_ID'] = (int)$basketItem['PRODUCT_ID']; $basketItem['QUANTITY'] = (float)$basketItem['QUANTITY']; if ($productProvider = CSaleBasket::GetProductProvider($basketItem)) { $fields = $productProvider::GetProductData(array( "PRODUCT_ID" => $basketItem["PRODUCT_ID"], "QUANTITY" => $basketItem["QUANTITY"], "RENEWAL" => "N", "CHECK_COUPONS" => ('Y' == $basketItem['CAN_BUY'] && 'N' == $basketItem['DELAY'] ? 'Y' : 'N'), "CHECK_DISCOUNT" => (CSaleBasketHelper::isSetItem($basketItem) ? 'N' : 'Y'), "BASKET_ID" => $basketItem["ID"], "NOTES" => $basketItem["NOTES"] )); } else { $fields = CSaleBasket::ExecuteCallbackFunction( $basketItem["CALLBACK_FUNC"], $basketItem["MODULE"], $basketItem["PRODUCT_ID"], $basketItem["QUANTITY"], "N" ); } if (!empty($fields) && is_array($fields)) { if ($isOrderConverted != 'N' && $basketItem['DELAY'] == 'N') { if (!Sale\Compatible\DiscountCompatibility::isInited()) Sale\Compatible\DiscountCompatibility::init(); if (Sale\Compatible\DiscountCompatibility::usedByClient()) Sale\Compatible\DiscountCompatibility::setBasketItemData($basketItem['ID'], $fields); } $fields['CAN_BUY'] = 'Y'; $fields['TYPE'] = (int)$basketItem['TYPE']; $fields['SET_PARENT_ID'] = (int)$basketItem['SET_PARENT_ID']; } else { $fields = array('CAN_BUY' => 'N'); } } if (array_key_exists('MEASURE_RATIO', $basketItem)) { $basketItemQuantity = floatval($basketItem['QUANTITY']); $basketItemRatio = floatval($basketItem['MEASURE_RATIO']); $mod = roundEx(($basketItemQuantity / $basketItemRatio - round($basketItemQuantity / $basketItemRatio)), 6); if ($mod != 0) { $fields['QUANTITY'] = floor(ceil($basketItemQuantity) / $basketItemRatio) * $basketItemRatio; } } if (!empty($fields) && is_array($fields)) { CSaleBasket::Update($basketItem['ID'], $fields); } } } } return true; } /** * @internal * @param $fuserID * @param $siteID * @param array $options * * @return Sale\Result */ public static function refreshFUserBasket($fuserID, $siteID, array $options = array()) { $result = new Sale\Result(); $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER); /** @var Sale\Basket $basketClass */ $basketClass = $registry->getBasketClassName(); /** @var Sale\Basket $basket */ $basket = $basketClass::loadItemsForFUser($fuserID, $siteID); if ($basket->count() > 0) { if (!Sale\Compatible\DiscountCompatibility::isInited()) Sale\Compatible\DiscountCompatibility::init(); $select = array("PRICE", 'QUANTITY', "COUPONS"); $basket->refreshData($select); $warnings = array(); if (!empty($options) && array_key_exists('CORRECT_RATIO', $options) && $options['CORRECT_RATIO'] === 'Y') { $r = Sale\BasketComponentHelper::correctQuantityRatio($basket); if (!$r->isSuccess()) { foreach ($r->getErrors() as $error) { if ($error instanceof Sale\ResultWarning) { $warnings[] = $error; } elseif ($error instanceof Sale\ResultError) { $result->addError($error); } } } } if ($result->isSuccess()) { $r = $basket->save(); if (!$r->isSuccess()) { $result->addErrors($r->getErrors()); } } $basketList = array(); /** @var Sale\BasketItem $basketItem */ foreach ($basket as $basketItem) { $basketList[$basketItem->getId()] = $basketItem->getFieldValues(); } $result->addData(array('BASKET_LIST' => $basketList)); if (!empty($warnings)) { $result->addWarnings($warnings); } } return $result; } /** * @param array $newProperties * @param array $oldProperties * @return bool|null */ public static function compareBasketProps($newProperties, $oldProperties) { $result = null; if (!is_array($newProperties) || !is_array($oldProperties)) return $result; $result = true; if (empty($newProperties) && empty($oldProperties)) return $result; $compareNew = array(); $compareOld = array(); foreach ($newProperties as &$property) { if (!isset($property['VALUE'])) continue; $property['VALUE'] = (string)$property['VALUE']; if ($property['VALUE'] == '') continue; $propertyID = ''; if (isset($property['CODE'])) { $property['CODE'] = (string)$property['CODE']; if ($property['CODE'] != '') $propertyID = $property['CODE']; } if ($propertyID == '' && isset($property['NAME'])) { $property['NAME'] = (string)$property['NAME']; if ($property['NAME'] != '') $propertyID = $property['NAME']; } if ($propertyID == '') continue; $compareNew[$propertyID] = $property['VALUE']; } unset($property); foreach ($oldProperties as &$property) { if (!isset($property['VALUE'])) continue; $property['VALUE'] = (string)$property['VALUE']; if ($property['VALUE'] == '') continue; $propertyID = ''; if (isset($property['CODE'])) { $property['CODE'] = (string)$property['CODE']; if ($property['CODE'] != '') $propertyID = $property['CODE']; } if ($propertyID == '' && isset($property['NAME'])) { $property['NAME'] = (string)$property['NAME']; if ($property['NAME'] != '') $propertyID = $property['NAME']; } if ($propertyID == '') continue; $compareOld[$propertyID] = $property['VALUE']; } unset($property); $result = false; if (count($compareNew) == count($compareOld)) { $result = true; foreach($compareNew as $key => $val) { if (!isset($compareOld[$key]) || $compareOld[$key] != $val) { $result = false; break; } } } unset($compareOld, $compareNew); return $result; } /** * @internal * @return array */ public static function getRoundFields() { $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'Y'); if ($isOrderConverted != 'N') { $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER); /** @var Sale\BasketItemBase $basketItemClassName */ $basketItemClassName = $registry->getBasketItemClassName(); return $basketItemClassName::getRoundFields(); } return array( 'DISCOUNT_PRICE', 'DISCOUNT_PRICE_PERCENT', ); } } class CAllSaleUser { /** * Creates new anonymous user with e-mail 'anonymous_some_number@example.com' and returns his ID * Used mainly in CRM * * @return int - new user ID or ID of already existing anonymous user, 0 if error */ public static function GetAnonymousUserID() { $bUserExists = false; $anonUserID = intval(COption::GetOptionInt("sale", "anonymous_user_id", 0)); if ($anonUserID > 0) { $dbUser = CUser::GetList('id', 'asc', array("ID_EQUAL_EXACT"=>$anonUserID), array("FIELDS"=>array("ID"))); if ($arUser = $dbUser->Fetch()) $bUserExists = true; } if (!$bUserExists) { $anonUserEmail = "anonymous_".randString(9)."@example.com"; $arErrors = array(); $anonUserID = CSaleUser::DoAutoRegisterUser( $anonUserEmail, array("NAME" => Loc::getMessage("SU_ANONYMOUS_USER_NAME")), SITE_ID, $arErrors, array( 'ACTIVE' => 'N', 'EXTERNAL_AUTH_ID' => 'saleanonymous', ) ); if ($anonUserID > 0) { COption::SetOptionInt("sale", "anonymous_user_id", $anonUserID); } else { $errorMessage = ""; if (!empty($arErrors)) { $errorMessage = " "; foreach ($arErrors as $value) { $errorMessage .= $value["TEXT"]."<br>"; } } $GLOBALS["APPLICATION"]->ThrowException(Loc::getMessage("SU_ANONYMOUS_USER_CREATE", array("#ERROR#" => $errorMessage)), "ANONYMOUS_USER_CREATE_ERROR"); return 0; } } return $anonUserID; } public static function DoAutoRegisterUser($autoEmail, $payerName, $siteId, &$arErrors, $arOtherFields = null) { if ($siteId == null) $siteId = SITE_ID; $autoEmail = trim($autoEmail); $autoName = ""; $autoLastName = ""; $autoSecondName = ""; if (!is_array($payerName) && ($payerName <> '')) { $arNames = explode(" ", $payerName); $autoName = $arNames[1]; $autoLastName = $arNames[0]; $autoSecondName = (!empty($arNames[2]) ? trim($arNames[2]) : false); } elseif (is_array($payerName)) { $autoName = $payerName["NAME"]; $autoLastName = $payerName["LAST_NAME"]; $autoSecondName = $payerName["SECOND_NAME"]; } if (!empty($autoEmail)) { $autoLogin = $autoEmail; $pos = mb_strpos($autoLogin, "@"); if ($pos !== false) $autoLogin = mb_substr($autoLogin, 0, $pos); if (mb_strlen($autoLogin) > 47) $autoLogin = mb_substr($autoLogin, 0, 47); while (mb_strlen($autoLogin) < 3) $autoLogin .= "_"; } else { $autoLogin = "buyer"; } $idx = 0; $loginTmp = $autoLogin; $dbUserLogin = CUser::GetByLogin($autoLogin); while ($arUserLogin = $dbUserLogin->Fetch()) { $idx++; if ($idx <= 10) $autoLogin = $loginTmp.$idx; else $autoLogin = "buyer".time().GetRandomCode(2); $dbUserLogin = CUser::GetByLogin($autoLogin); } $groups = []; if (\Bitrix\Main\ModuleManager::isModuleInstalled('intranet') && \Bitrix\Main\Loader::includeModule('crm')) { $groups = \Bitrix\Crm\Order\BuyerGroup::getDefaultGroups(); } else { $defaultGroup = COption::GetOptionString("main", "new_user_registration_def_group", ""); if (!empty($defaultGroup)) { $groups = explode(",", $defaultGroup); } } $autoPassword = \CUser::GeneratePasswordByPolicy($groups); $arFields = array( "LOGIN" => $autoLogin, "PASSWORD" => $autoPassword, "PASSWORD_CONFIRM" => $autoPassword, "GROUP_ID" => $groups, "LID" => $siteId, // reset department for intranet 'UF_DEPARTMENT' => [] ); if($autoName <> '') $arFields["NAME"] = $autoName; if($autoLastName <> '') $arFields["LAST_NAME"] = $autoLastName; if($autoSecondName <> '') $arFields["SECOND_NAME"] = $autoSecondName; if($autoEmail <> '') $arFields["EMAIL"] = $autoEmail; $arFields["ACTIVE"] = (isset($arOtherFields["ACTIVE"]) && $arOtherFields["ACTIVE"] == "N") ? "N" : "Y"; if (isset($arOtherFields["ACTIVE"])) unset($arOtherFields["ACTIVE"]); if (is_array($arOtherFields)) { foreach ($arOtherFields as $key => $value) { if (!array_key_exists($key, $arFields)) $arFields[$key] = $value; } } $user = new CUser; $userId = $user->Add($arFields); if (intval($userId) <= 0) { $arErrors[] = array("TEXT" => Loc::getMessage("STOF_ERROR_REG").(($user->LAST_ERROR <> '') ? ": ".$user->LAST_ERROR : "")); return 0; } return $userId; } public static function CheckFields($ACTION, &$arFields, $ID = 0) { return true; } public static function GetID($bSkipFUserInit = false) { global $USER; $bSkipFUserInit = ($bSkipFUserInit !== false); $cookie_name = COption::GetOptionString("main", "cookie_name", "BITRIX_SM"); $ID = null; $filter = array(); if (isset($_SESSION["SALE_USER_ID"]) && intval($_SESSION["SALE_USER_ID"]) > 0) { $ID = intval($_SESSION["SALE_USER_ID"]); } if (intval($ID) <= 0 && isset($_COOKIE[$cookie_name."_SALE_UID"])) { $CODE = (string)$_COOKIE[$cookie_name."_SALE_UID"]; if (COption::GetOptionString("sale", "encode_fuser_id", "N") == "Y") { $filter = (array("CODE" => $CODE)); } else { $filter = (array("ID" => intval($CODE))); } } if (intval($ID) <= 0) { if (!empty($filter)) { $arRes = CSaleUser::GetList($filter); if(!empty($arRes)) { $ID = $arRes["ID"]; CSaleUser::Update($ID); } else { if ($USER && $USER->IsAuthorized()) { $ID = CSaleUser::getFUserCode(); } if (intval($ID) <= 0 && !$bSkipFUserInit) { $ID = CSaleUser::Add(); } } } elseif (!$bSkipFUserInit) { $ID = CSaleUser::Add(); } } return (int)$ID; } public static function Update($ID, $allowUpdate = true) { global $DB, $USER; if (!is_object($USER)) $USER = new CUser; $ID = intval($ID); $cookie_name = COption::GetOptionString("main", "cookie_name", "BITRIX_SM"); $arFields = array( "=DATE_UPDATE" => $DB->GetNowFunction(), ); if ($USER->IsAuthorized()) $arFields["USER_ID"] = intval($USER->GetID()); if ($allowUpdate) { CSaleUser::_Update($ID, $arFields); } $secure = false; if(COption::GetOptionString("sale", "use_secure_cookies", "N") == "Y" && CMain::IsHTTPS()) $secure=1; $_COOKIE[$cookie_name."_SALE_UID"] = $ID; if(COption::GetOptionString("sale", "encode_fuser_id", "N") == "Y") { $arRes = CSaleUser::GetList(array("ID" => $ID)); if(!empty($arRes)) { if(strval($arRes["CODE"]) == "") { $arRes["CODE"] = md5(time().randString(10)); if ($allowUpdate) { CSaleUser::_Update($arRes["ID"], array("CODE" => $arRes["CODE"])); } } $GLOBALS["APPLICATION"]->set_cookie("SALE_UID", $arRes["CODE"], false, "/", false, $secure, "Y", false); $_COOKIE[$cookie_name."_SALE_UID"] = $arRes["CODE"]; } } else { $GLOBALS["APPLICATION"]->set_cookie("SALE_UID", $ID, false, "/", false, $secure, "Y", false); } return true; } public static function _Update($ID, $arFields) { global $DB; $DB->StartUsingMasterOnly(); $ID = intval($ID); if ($ID <= 0) return False; $arFields1 = array(); foreach ($arFields as $key => $value) { if (mb_substr($key, 0, 1) == "=") { $arFields1[mb_substr($key, 1)] = $value; unset($arFields[$key]); } } if (!CSaleUser::CheckFields("UPDATE", $arFields, $ID)) return false; $strUpdate = $DB->PrepareUpdate("b_sale_fuser", $arFields); foreach ($arFields1 as $key => $value) { if ($strUpdate <> '') $strUpdate .= ", "; $strUpdate .= $key."=".$value." "; } $strSql = "UPDATE b_sale_fuser SET ".$strUpdate." WHERE ID = ".$ID." "; $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); $DB->StopUsingMasterOnly(); return $ID; } public static function GetList($arFilter) { global $DB; $arSqlSearch = Array(); if (!is_array($arFilter)) $filter_keys = Array(); else $filter_keys = array_keys($arFilter); $countarFilter = count($filter_keys); for ($i=0; $i < $countarFilter; $i++) { $val = $DB->ForSql($arFilter[$filter_keys[$i]]); $key = $filter_keys[$i]; if ($key[0]=="!") { $key = mb_substr($key, 1); $bInvert = true; } else $bInvert = false; if (strval($val) == "") $val = 0; switch(ToUpper($key)) { case "ID": $arSqlSearch[] = "ID ".($bInvert?"<>":"=")." ".intval($val)." "; break; case "USER_ID": $arSqlSearch[] = "USER_ID ".($bInvert?"<>":"=")." ".intval($val)." "; break; case "CODE": $arSqlSearch[] = "CODE ".($bInvert?"<>":"=")." '".$DB->ForSql($val)."' "; break; } } $strSqlSearch = ""; $countSqlSearch = count($arSqlSearch); for($i=0; $i < $countSqlSearch; $i++) { $strSqlSearch .= " AND "; $strSqlSearch .= " (".$arSqlSearch[$i].") "; } $strSql = "SELECT ID, DATE_INSERT, DATE_UPDATE, USER_ID, CODE FROM b_sale_fuser WHERE 1 = 1 ".$strSqlSearch." ORDER BY ID DESC"; $db_res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); return $db_res->Fetch(); } public static function Delete($ID) { global $DB; $ID = intval($ID); foreach(GetModuleEvents("sale", "OnSaleUserDelete", true) as $arEvent) ExecuteModuleEventEx($arEvent, Array($ID)); $DB->Query("DELETE FROM b_sale_fuser WHERE ID = ".$ID." ", true); return true; } public static function OnUserLogin($new_user_id, array $params = array()) { $cookie_name = COption::GetOptionString("main", "cookie_name", "BITRIX_SM"); $allowUpdate = !array_key_exists('update', $params) || $params['update'] === true; CSaleUser::UpdateSessionSaleUserID(); $ID = $_SESSION["SALE_USER_ID"] ?? 0; if(COption::GetOptionString("sale", "encode_fuser_id", "N") != "Y") { $ID = intval($ID); } if (intval($ID) <= 0 && isset($_COOKIE[$cookie_name."_SALE_UID"])) { $CODE = (string)$_COOKIE[$cookie_name."_SALE_UID"]; if (COption::GetOptionString("sale", "encode_fuser_id", "N") == "Y" && strval($CODE) != "") { $arRes = CSaleUser::GetList(array("CODE" => $CODE)); if(!empty($arRes)) { $ID = $arRes["ID"]; } } elseif (intval($CODE) > 0) { $ID = intval($CODE); } } $res = CSaleUser::GetList(array("!ID" => intval($ID), "USER_ID" => intval($new_user_id))); if (!empty($res)) { if ($ID > 0) { if (CSaleBasket::TransferBasket($ID, $res["ID"])) { CSaleUser::Delete($ID); } } $ID = intval($res["ID"]); } CSaleUser::Update($ID, $allowUpdate); $_SESSION["SALE_USER_ID"] = $ID; $_SESSION["SALE_BASKET_NUM_PRODUCTS"] = Array(); return true; } public static function UpdateSessionSaleUserID() { global $USER; if (isset($_SESSION["SALE_USER_ID"]) && (string)$_SESSION["SALE_USER_ID"] !== "" && intval($_SESSION["SALE_USER_ID"])."|" != $_SESSION["SALE_USER_ID"]."|") { $arRes = CSaleUser::GetList(array("CODE" => $_SESSION["SALE_USER_ID"])); if(!empty($arRes)) { $_SESSION["SALE_USER_ID"] = $arRes['ID']; return $arRes['ID']; } else { if ($USER && $USER->IsAuthorized()) { $ID = CSaleUser::getFUserCode(); return $ID; } } } return 0; } public static function getFUserCode() { global $USER; $arRes = CSaleUser::GetList(array("USER_ID" => (int)$USER->GetID())); if (!empty($arRes)) { $_SESSION["SALE_USER_ID"] = $arRes['ID']; $arRes["CODE"] = md5(time().randString(10)); $GLOBALS["DB"]->StartUsingMasterOnly(); CSaleUser::_Update($arRes["ID"], array("CODE" => $arRes["CODE"])); CSaleUser::Update($arRes["ID"]); $GLOBALS["DB"]->StopUsingMasterOnly(); return $arRes["ID"]; } return 0; } public static function OnUserLogout($userID) { global $APPLICATION; unset($_SESSION["SALE_USER_ID"]); $_SESSION["SALE_BASKET_NUM_PRODUCTS"] = Array(); $_SESSION["SALE_BASKET_PRICE"] = Array(); $secure = false; if(COption::GetOptionString("sale", "use_secure_cookies", "N") == "Y" && CMain::IsHTTPS()) { $secure=1; } $APPLICATION->set_cookie("SALE_UID", 0, -1, "/", false, $secure, "Y", false); $cookie_name = COption::GetOptionString("main", "cookie_name", "BITRIX_SM"); unset($_COOKIE[$cookie_name."_SALE_UID"]); } public static function DeleteOldAgent($nDays, $speed = 0) { $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER); /** @var Sale\Basket $basketClass */ $basketClass = $registry->getBasketClassName(); return $basketClass::deleteOldAgent($nDays, $speed); } public static function OnUserDelete($userID) { if($userID<=0) return false; $arSUser = CSaleUser::GetList(array("USER_ID" => $userID)); if(!empty($arSUser)) { if(!(CSaleBasket::DeleteAll($arSUser["ID"]))) return false; if(!(CSaleUser::Delete($arSUser["ID"]))) return false; } return true; } }