undefined use Bitrix\Main\Loader; use Bitrix\Main\Localization\Loc; use Bitrix\Main\Config\Option; use Bitrix\Sale; use Bitrix\Iblock\PropertyIndex; use Bitrix\Iblock; use Bitrix\Iblock\PropertyTable; use Bitrix\Main\UI\Filter\Actions; use Bitrix\Main\EventManager; Loc::loadMessages(__FILE__); global $APPLICATION; undefined if (!Loader::includeModule("iblock")) { $APPLICATION->ThrowException(Loc::getMessage('SCODER_ERROR_IBLOCK_NOT_INSTALLED')); return false; } if (!Loader::includeModule("catalog")) { $APPLICATION->ThrowException(Loc::getMessage('SCODER_ERROR_CATALOG_NOT_INSTALLED')); return false; } if (!Loader::includeModule("sale")) { $APPLICATION->ThrowException(Loc::getMessage('SCODER_ERROR_SALE_NOT_INSTALLED')); return false; } if (!Loader::includeModule("scoder.phpcondition")) { $APPLICATION->ThrowException(Loc::getMessage('SCODER_ERROR_SCODER_PHPCONDITION_NOT_INSTALLED')); return false; } CModule::AddAutoloadClasses( "scoder.buymore", array( "CScoderBuymore" => "classes/general/main.php", "CScoderBuymoreAgents" => "classes/general/agents.php", ) ); class CScoderBuymoreEvents { const MODULE_ID = 'scoder.buymore'; public static function OnBeforePrologHandler() { $btrue = false; $request = Bitrix\Main\Application::getInstance()->getContext()->getRequest(); $arPostList = $request->getPostList()->toArray(); if (is_array($arPostList) && count($arPostList) >0 && is_array($arPostList['params']) && count($arPostList['params']) >0 && !empty($arPostList['params']['GRID_ID']) && !empty($arPostList['params']['FILTER_ID']) ) { $grid_id = $arPostList['params']['GRID_ID']; $filter_id = $arPostList['params']['FILTER_ID']; $btrue = true; } //если изменяется форма фильтра / сохранение фильтра if ($btrue) { if (strpos($filter_id,"SB_PROFILE_FILTER_")===0) { $str = str_replace("SB_PROFILE_FILTER_","",$filter_id); //ид настроеннного инфоблока if ($str!="") { $ar_exp = explode("_",$str); if (isset($ar_exp[0])) $iblock_id = $ar_exp[0]; if (isset($ar_exp[1])) $profile_id = $ar_exp[1]; } } if ($iblock_id>0 && $profile_id>0) { foreach ($arPostList as $key => $val) { if (!is_array($val)) $arPostList[$key] = mb_convert_encoding($val, LANG_CHARSET, "UTF-8"); elseif (is_array($val)) { foreach ($val as $k => $v) { if (!is_array($v)) $arPostList[$key][$k] = mb_convert_encoding($v, LANG_CHARSET, "UTF-8"); elseif (is_array($v)) { foreach ($v as $j3 => $v3) { if (!is_array($v3)) $arPostList[$key][$k][$j3] = mb_convert_encoding($v3, LANG_CHARSET, "UTF-8"); elseif (is_array($v3)) { foreach ($v3 as $j4 => $v4) { $arPostList[$key][$k][$j3][$j4] = mb_convert_encoding($v4, LANG_CHARSET, "UTF-8"); } } } } } } } if (is_array($arPostList['fields'])) { foreach ($arPostList['fields'] as $key => $value) { if (!is_array($value) && $value=='') unset($arPostList['fields'][$key]); } } $profile_iblock_id = Option::get(self::MODULE_ID, "scoder_buymore_profiles"); if ($profile_iblock_id>0) { $values = array(); $res = CIBlockElement::GetProperty($profile_iblock_id, $profile_id, array(), Array("CODE"=>"FILTERS")); $ii = 0; $kk = 0; $btrue = false; while ($ob = $res->GetNext()) { if ($ob["DESCRIPTION"] == $iblock_id) { $kk = $ii; $btrue = true; } $values[] = array('VALUE' => $ob["~VALUE"], 'DESCRIPTION' => $ob["DESCRIPTION"]); $ii ++; } if ($btrue) $values[$kk] = array('VALUE' => serialize($arPostList), 'DESCRIPTION' => $iblock_id); else $values[] = array('VALUE' => serialize($arPostList), 'DESCRIPTION' => $iblock_id); //сохранить фильтр $prop = array( 'FILTERS' => $values, ); CIBlockElement::SetPropertyValuesEx($profile_id, false, $prop); } } } } public static function BasketEditDiscount() { if (Loader::includeSharewareModule("scoder.buymore") != Loader::MODULE_DEMO_EXPIRED && $GLOBALS["SCODER_BUYMORE_IS_CHECK"]!="Y") { $active = Option::get(self::MODULE_ID, "ACTIVE"); if ($active=='' || $active=='Y') { global $APPLICATION, $USER; if (!is_object($USER)) $USER = new CUser; $profile_iblock_id = Option::get(self::MODULE_ID, "scoder_buymore_profiles"); //ИД инфоблока, где хранятся порфили $fuser = Sale\Fuser::getId(); if ($fuser>0 && $profile_iblock_id>0) { $filter = array( "ACTIVE" => "Y", "ACTIVE_DATE"=>"Y", "IBLOCK_ID" => $profile_iblock_id, "PROPERTY_SITE_ID" => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, "PROPERTY_USER_GROUPS" => $USER->GetUserGroupArray(), ); $rsData = CIBlockElement::GetList( array("SORT" => "ASC","ID" => "ASC"), $filter, false, false, Array("ID","NAME","ACTIVE","IBLOCK_ID","SORT","PROPERTY_*") ); while ($ob_profile = $rsData->GetNextElement()) { file_put_contents($_SERVER["DOCUMENT_ROOT"]."/log/salersData.txt", json_encode($ob_profile->GetFields(), JSON_UNESCAPED_UNICODE)); $arElement = $ob_profile->GetFields(); $arElement["PROPERTIES"] = $ob_profile->GetProperties(); if (is_array($arElement["PROPERTIES"])) { foreach ($arElement["PROPERTIES"] as $property_code => $ar_property) { $arElement[$property_code] = $arElement["PROPERTIES"][$property_code]["~VALUE"]; $arElement[$property_code . "_DESCRIPTION"] = $arElement["PROPERTIES"][$property_code]["~DESCRIPTION"]; } } //-----------------ГЕНЕРАЦИЯ--------------------- //Правила назначения скидок $ar_values = $arElement["CONDITIONS_VALUE"]; //Правила назначения скидок $ar_quantity = $arElement["CONDITIONS_QUANTITY"]; //Количество, на которое применять $ar_max = $arElement["MAX_COUNT"]; //Максимальное количество товаров в корзине, при котором применять $ar_min = $arElement["MIN_COUNT"]; //Минимальное количество товаров в корзине, при котором применять $ar_type = $arElement["TYPE"]; //Тип скидки $ar_set_price = $arElement["SET_PRICE"]; //Установить цену на товар $element_values = array(); $check_elements = false; file_put_contents($_SERVER["DOCUMENT_ROOT"]."/log/salersDataElement.txt", json_encode($arElement, JSON_UNESCAPED_UNICODE)); if (is_array($arElement['PRODUCTS'])) //ИД товаров, на которые применять акцию { $ii = 1; foreach ($arElement['PRODUCTS'] as $element_id) { if ($element_id>0) { $element_values[$ii] = $element_id; $check_elements = true; $ii++; } } } $element_values_unset = array(); $check_elements_unset = false; if (is_array($arElement['PRODUCTS_UNSET'])) //ИД товаров, на которые применять акцию { $ii = 1; foreach ($arElement['PRODUCTS_UNSET'] as $element_id) { if ($element_id>0) { $element_values_unset[$ii] = $element_id; $check_elements_unset = true; $ii++; } } } $bIblockTrue = false; if (is_array($arElement['IBLOCKS']) && count($arElement['IBLOCKS'])>0) //Инфоблоки, на товары которых распространяются скидки $bIblockTrue = true; // $bPaysystemsTrue = false; // if (is_array($arElement['PAYSYSTEMS']) && count($arElement['PAYSYSTEMS'])>0) // $bPaysystemsTrue = true; $sort_field = "PRICE"; //если "По убыванию цены" или "Минимизировать скидки" if ($arElement['PRICE_SORT'] == "desc" || $arElement['PRICE_SORT'] == "min" || $arElement['PRICE_SORT'] == "id_desc") $sort = "desc"; else $sort = "asc"; if ($arElement['PRICE_SORT'] == "id_desc" || $arElement['PRICE_SORT'] == "id_asc") $sort_field = "ID"; if ($arElement['IS_FILTER'] =="Y") { //сбор данный для определения типа инфоблока $res = CIBlock::GetList( Array("SORT" => "ASC"), Array(), false ); while($ar_res = $res->Fetch()) { if ($ar_res["ID"]!=$set_iblock_id) { $ar_iblocks[$ar_res["ID"]] = $ar_res["NAME"]; $ar_iblocks_info[$ar_res["ID"]] = $ar_res; } } } $dbBasketItems = Sale\Internals\BasketTable::getList(array( 'filter' => array( 'FUSER_ID' => $fuser, 'ORDER_ID' => null, 'LID' => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, 'CAN_BUY' => 'Y', "DELAY" => "N", ), 'select' =>array("ID","PRODUCT_ID", "QUANTITY","PRICE","DISCOUNT_COUPON","PRICE_TYPE_ID", //"DISCOUNT_NAME", "DISCOUNT_VALUE", ), 'order' => array($sort_field => $sort) )); $ar_children = $arOfferParents = $ar_elements = array(); $bcheckpricetype = false; if (isset($arElement['PRICE_TYPES']) && is_array($arElement['PRICE_TYPES']) && count($arElement['PRICE_TYPES'])>0) $bcheckpricetype = true; $btrue = false; $count = 0; $arItems = $arItemsID = $arElementToIblock = $ar_basket_iblocks = array(); while ($arItem = $dbBasketItems->Fetch()) { // типы цен, которые не участвуют в акции if ($bcheckpricetype && in_array($arItem["PRICE_TYPE_ID"],$arElement['PRICE_TYPES'])) continue; $arItems[] = $arItem; $arItemsID[] = $arItem["PRODUCT_ID"]; $ar_basket_iblocks[] = CIBlockElement::GetIBlockByID($arItem["PRODUCT_ID"]); $count++; } unset($arItem); $boffer = false; //если указаны "ИД товаров, на которые применять акцию" ИЛИ "ИД товаров, которые не должны участвовать в подсчете на скидку" ИЛИ "инфоблоки, на товары которых распространяются скидки" ИЛИ Включены фильтр if (($check_elements || $check_elements_unset || $bIblockTrue || $arElement['IS_FILTER'] == "Y") && count($arItemsID)>0 ) { $res = CIBlockElement::GetList( Array("IBLOCK_ID"=>"ASC"), array( "ID"=>$arItemsID, "IBLOCK_ID"=>$ar_basket_iblocks ), false, false, Array("ID", "IBLOCK_ID") ); while($ob = $res->GetNextElement()) { $arProduct = $ob->GetFields(); $arProduct["PROPERTIES"] = $ob->GetProperties(); $arElementToIblock[$arProduct["ID"]] = $arProduct["IBLOCK_ID"]; //соотношение ИД товара к инфоблоку //если торговое предложение if ($arProduct["PROPERTIES"]["CML2_LINK"]["~VALUE"] > 0) { $arOfferParents[$arProduct["ID"]] = $arProduct["PROPERTIES"]["CML2_LINK"]["~VALUE"]; //ставим в соотношение предложению его родительский товар $boffer = true; } $ar_elements[] = $arProduct; } } if (is_array($arItems)) { $arBaskets = array(); foreach ($arItems as $arItem) { //если включены фильтры if ($arElement['IS_FILTER'] == "Y") { unset($filter); //--------------------ФИЛЬТР---------- $iblock_id = $arElementToIblock[$arItem["PRODUCT_ID"]]; if (is_array($arElement["FILTERS_DESCRIPTION"])) { foreach ($arElement["FILTERS_DESCRIPTION"] as $kk => $ib) { if ($ib == $iblock_id) { $filter = $arElement["FILTERS"][$kk]; } } } $arParams = array( "IBLOCK_ID" => $iblock_id, "IBLOCK_TYPE" => $ar_iblocks_info[$iblock_id]["IBLOCK_TYPE_ID"], ); $filterFields = CScoderBuymore::__get_filters($arParams); $ar_str = unserialize($filter); unset($filter); $fields = array(); if (isset($ar_str['fields'])) $fields = $ar_str['fields']; elseif (isset($ar_str['data']['fields'])) $fields = $ar_str['data']['fields']; $arCollectionFilter = array(); CScoderBuymore::CreateFilter($filterFields, $arCollectionFilter, $fields); //преобразуем фильтр в нормальный вид $real_filter = $arCollectionFilter; $real_filter["IBLOCK_ID"] = $iblock_id; $real_filter["ID"] = $arItem["PRODUCT_ID"]; $bfind = true; foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnBeforeCheckFilter", true) as $arEvent) ExecuteModuleEventEx($arEvent, array(&$real_filter, $arItem, $arElement)); //просто проверяем вернет ли товар по указанному фильтру $rs = CIBlockElement::GetList( array("ID" => "ASC"), $real_filter, false, array("nTopCount" => 1), array("ID") ); if (!$ob = $rs->GetNextElement()) { $bfind = false; //пропускаем товар, если не подходит фильтру } //если элемент найден и включен "Учитывать фильтр родительского элемента для торговых предложений" if ($bfind && $arElement['IS_FILTER_PARENT'] =="Y") { $mxResult = CCatalogSku::GetProductInfo($arItem["PRODUCT_ID"]); if (is_array($mxResult)) { $parent_id = $mxResult['ID']; $parent_iblock_id = $mxResult['IBLOCK_ID']; //-----ФИЛЬТР РОДИТЕЛЯ if ($parent_id>0 && $parent_iblock_id >0) { if (is_array($arElement["FILTERS_DESCRIPTION"])) { foreach ($arElement["FILTERS_DESCRIPTION"] as $kk => $ib) { if ($ib == $parent_iblock_id) { $filter = $arElement["FILTERS"][$kk]; } } } $arParams = array( "IBLOCK_ID" => $parent_iblock_id, "IBLOCK_TYPE" => $ar_iblocks_info[$parent_iblock_id]["IBLOCK_TYPE_ID"], ); $filterFields = CScoderBuymore::__get_filters($arParams); $ar_str = unserialize($filter); unset($filter); $fields = array(); if (isset($ar_str['fields'])) $fields = $ar_str['fields']; elseif (isset($ar_str['data']['fields'])) $fields = $ar_str['data']['fields']; $arCollectionFilter = array(); CScoderBuymore::CreateFilter($filterFields, $arCollectionFilter, $fields); //преобразуем фильтр в нормальный вид $real_filter = $arCollectionFilter; $real_filter["IBLOCK_ID"] = $parent_iblock_id; $real_filter["ID"] = $parent_id; foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnBeforeCheckParentFilter", true) as $arEvent) ExecuteModuleEventEx($arEvent, array(&$real_filter, $arItem, $arElement)); //просто проверяем вернет ли товар по указанному фильтру $rs = CIBlockElement::GetList( array("ID" => "ASC"), $real_filter, false, array("nTopCount" => 1), array("ID") ); if (!$ob = $rs->GetNextElement()) { $bfind = false; //пропускаем товар, если не подходит фильтру } } } } if (!$bfind) continue; //--------------------END. ФИЛЬТР------------------- } //если указаны "Инфоблоки, на товары которых распростраяются скидки", но товар не принадлежит нужным инфоблокам if ($bIblockTrue && isset($arElementToIblock[$arItem["PRODUCT_ID"]]) && is_array($arElement['IBLOCKS']) && !in_array($arElementToIblock[$arItem["PRODUCT_ID"]],$arElement['IBLOCKS'])) continue; //если указаны "ИД товаров, которые не должны участвовать в подсчете на скидку" и это такой товар, от пропускаем его if ($check_elements_unset && is_array($element_values_unset) && (in_array($arItem["PRODUCT_ID"],$element_values_unset) || ($boffer && $arOfferParents[$arItem["PRODUCT_ID"]]>0 && in_array($arOfferParents[$arItem["PRODUCT_ID"]],$element_values_unset))) ) continue; //если не указаны ИД товаров, на которые применять акцию ИЛИ (указаны и товар пристутствует) if (!$check_elements || ($check_elements && (in_array($arItem["PRODUCT_ID"],$element_values) || ($boffer && $arOfferParents[$arItem["PRODUCT_ID"]]>0 && in_array($arOfferParents[$arItem["PRODUCT_ID"]],$element_values)))) ) { $arBaskets[] = $arItem; } } unset($arItem); $count = count($arBaskets); if ($count>0) { $lkey = count($ar_values) - 1; for ($j=0; $j<$count; $j++) { if (!isset($ar_values[$j])) { $ar_values[$j] = (float) $ar_values[$lkey]; $ar_type[$j] = $ar_type[$lkey]; $ar_quantity[$j] = $ar_quantity[$lkey]; $ar_max[$j] = $ar_max[$lkey]; $ar_min[$j] = $ar_min[$lkey]; $ar_set_price[$j] = $ar_set_price[$lkey]; } } } //Если минимизировать скидки if ($arElement['PRICE_SORT'] == "min" || $arElement['PRICE_SORT'] == "max") { file_put_contents($_SERVER["DOCUMENT_ROOT"]."/log/salersDataElementmin.txt", json_encode($arElement, JSON_UNESCAPED_UNICODE)); if ($count>0) { //сортировка $counter = $count - 1; for ($ii = 0; $ii < $counter; $ii++) { for ($jj = $ii; $jj < $count; $jj++) { if ($ar_values[$ii] <= $ar_values[$jj]) { //Величина скидки $x = $ar_values[$ii]; $ar_values[$ii] = $ar_values[$jj]; $ar_values[$jj] = $x; //Тип скидки $x = $ar_type[$ii]; $ar_type[$ii] = $ar_type[$jj]; $ar_type[$jj] = $x; //Количество, на которое применять $x = $ar_quantity[$ii]; $ar_quantity[$ii] = $ar_quantity[$jj]; $ar_quantity[$jj] = $x; //Максимальное количество товаров в корзине, при котором применять скидку на эту позицию $x = $ar_max[$ii]; $ar_max[$ii] = $ar_max[$jj]; $ar_max[$jj] = $x; //Минимальное количество товаров в корзине, при котором применять скидку на эту позицию $x = $ar_min[$ii]; $ar_min[$ii] = $ar_min[$jj]; $ar_min[$jj] = $x; $x = $ar_set_price[$ii]; $ar_set_price[$ii] = $ar_set_price[$jj]; $ar_set_price[$jj] = $x; } } } $arBaskets = array_reverse($arBaskets); //массив в обратном порядке } } $i = 0; //file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/scoder-log.txt', date("d.m.Y H:i:s -- ") . '$ar_values: ' . var_export($ar_values, true) . "\n", FILE_APPEND); //перебираем только оставшиеся нужные элементы foreach ($arBaskets as $cc => $arItem) { $bmaxmin = false; $val = 0; //Максимальное количество товаров в корзине, при котором применять скидку на эту позицию if ($ar_max[$i]=="N" || ($ar_max[$i]>0 && $ar_max[$i]>=$count)) { $val = (float) $ar_values[$i]; } elseif ($ar_max[$i]>0) { $val = 0; $bmaxmin = true; } //если не попало под ограничение по МАКСИМУМУ if (!$bmaxmin) { //Минимальное количество товаров в корзине, при котором применять скидку на эту позицию //Если не указано или (указано И всего товаров в корзине больше или равно указанному), то применяем скидку if ($ar_min[$i]=="N" || ($ar_min[$i]>0 && $count >= $ar_min[$i])) { $val = (float) $ar_values[$i]; } elseif ($ar_min[$i]>0) { $val = 0; $bmaxmin = true; } } $unit = $ar_type[$i]; $Max = 0; if ($ar_quantity[$i]>0) { if ($unit=="F") { $Max = $val*floatval($ar_quantity[$i])/floatval($arItem["QUANTITY"]); } else { $Max = ((floatval($arItem["PRICE"])*($val/100))*floatval($ar_quantity[$i]))/floatval($arItem["QUANTITY"]); } } //если "Установить цену на товар" if ($ar_set_price[$i] == "Y") { if ($unit=="F") //если Фиксированная сумма { $val = floatval($arItem["PRICE"]) - $val; } else //если % { $val = 100-$val; } } $ar_child = array(); $ar_child[] = array ( 'CLASS_ID' => 'CondIBElement', 'DATA' => array ( 'logic' => 'Equal', 'value' => array ( 0 => $arItem['PRODUCT_ID'], ), ), ); //Учитывать количество одного и того же товара if ($arElement['CONSIDER_QUANTITY']=="Y") { $db_res = CSaleBasket::GetPropsList( array( "ID" => "DESC", ), array( "BASKET_ID" => $arItem["ID"], "CODE" => 'SCODER_BUYMORE_PROPERTY', ) ); if ($ar_res = $db_res->Fetch()) { $ar_child[] = array( 'CLASS_ID' => 'BX:CondBsktProp', 'DATA' => array ( 'Entity' => 'CODE', 'Name' => 'SCODER_BUYMORE_PROPERTY', 'Logic' => '0', 'Value' => $ar_res['VALUE'], ), ); } } //если отмечено "Применять акцию, если только применены купоны Скидок на товар", и купон не применен if ($arElement['ONLY_COUPONS']=='Y' && (is_null($arItem["DISCOUNT_COUPON"]) || $arItem["DISCOUNT_COUPON"]=='')) continue; if ($arElement['CHECK_COUPON']!="Y" || ($arElement['CHECK_COUPON']=="Y" && (is_null($arItem["DISCOUNT_COUPON"]) || $arItem["DISCOUNT_COUPON"]=='')) ) { $btrue = true; $ar_children[] = array ( 'CLASS_ID' => 'ActSaleBsktGrp', 'DATA' => array ( 'Type' => 'Discount', 'Value' => $val, //Значение 'Unit' => ($unit=='F'?'CurEach':'Perc'), 'Max' => $Max, 'All' => 'AND', 'True' => 'True', ), 'CHILDREN' => $ar_child, ); $i++; } } } $db_res = CSaleDiscount::GetList( array("SORT" => "ASC"), array( "LID" => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, 'XML_ID' => 'scoder_buymore_' . $arElement['ID'] . "_" . $fuser, ), false, false, array("ID") ); if ($ar_res = $db_res->Fetch()) { $discountID = (int) $ar_res["ID"]; } if (!$btrue) { $ar_children_conditions = array(); $ar_children_conditions[] = array ( 'CLASS_ID' => 'CondSaleCmnAdvPHPExp', 'DATA' => array ( 'logic' => 'Equal', 'value' => 'CModule::IncludeModule("scoder.buymore") && CScoderBuymore::__check_conditions('.$fuser.','. (int) $arElement["ID"].')', ), ); // if ($bPaysystemsTrue) // { // $ar_children_conditions[] = array ( // 'CLASS_ID' => 'CondSalePaySystem', // 'DATA' => // array ( // 'logic' => 'Equal', // 'value' => $arElement['PAYSYSTEMS'], // ), // ); // } if ($arElement['CONDITIONS']!="") { $ar = unserialize($arElement['CONDITIONS']); if (is_array($ar['CHILDREN']) && count($ar['CHILDREN'])>0) { $ar_children_conditions[] = $ar; } } $name = Loc::getMessage('SCODER_BUYMORE_DISCOUNT_NAME',array("#FUSER_ID#"=>$fuser)); //если "Шаблон для названий генерируемых правил" ну пустое if ($arElement["CONDITIONS_NAME"] !="") { $name = $arElement["CONDITIONS_NAME"]; $name = str_replace("#FUSER_ID#",$fuser,$name); foreach ($arElement as $code => $v) { if (!is_array($code) && !is_array($v)) { $code = "#".$code."#"; $name = str_replace($code, $v, $name); } } } $ar_load = array ( 'LID' => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, 'NAME' => $name, 'ACTIVE_FROM' => '', 'ACTIVE_TO' => '', 'ACTIVE' => 'Y', 'SORT' => $arElement['SORT_2'], 'PRIORITY' => $arElement['PRIORITY'], 'LAST_DISCOUNT' => ($arElement['LAST_DISCOUNT']=='Y'?'Y':"N"), 'LAST_LEVEL_DISCOUNT' => ($arElement['LAST_LEVEL_DISCOUNT']=='Y'?'Y':"N"), 'XML_ID' => 'scoder_buymore_' . $arElement['ID'] . "_" . $fuser, 'CONDITIONS' => array ( 'CLASS_ID' => 'CondGroup', 'DATA' => array ( 'All' => 'AND', 'True' => 'True', ), 'CHILDREN' => $ar_children_conditions, ), 'ACTIONS' => array ( 'CLASS_ID' => 'CondGroup', 'DATA' => array ( 'All' => 'AND', ), 'CHILDREN' => $ar_children, ), 'USER_GROUPS' => (is_array($arElement['USER_GROUPS'])?$arElement['USER_GROUPS']:array(2)), //группы пользователей ); foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnBeforeSaleDiscountGenerate", true) as $arEvent) { $bEventRes = ExecuteModuleEventEx($arEvent, array($discountID, &$ar_load, $arElement, $fuser)); if($bEventRes===false) { if($err = $APPLICATION->GetException()) $this->LAST_ERROR .= $err->GetString()." "; else { $APPLICATION->ThrowException("Unknown error"); $this->LAST_ERROR .= "Unknown error. "; } $GLOBALS["SCODER_BUYMORE_IS_CHECK"] = 'Y'; return false; } } if ($discountID>0) { if (CSaleDiscount::Update($discountID, $ar_load)){} } else { $ar_load["ADD"] = "ADD"; $discountID = (int)CSaleDiscount::Add($ar_load); } foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnAfterSaleDiscountGenerate", true) as $arEvent) { $bEventRes = ExecuteModuleEventEx($arEvent, array($discountID, &$ar_load, $arElement, $fuser)); if($bEventRes===false) { break; } } } elseif ($discountID>0) { $obDiscount = new CSaleDiscount(); $obDiscount->Delete($discountID); } unset($discountID); //-----------------КОНЕЦ. ГЕНЕРАЦИИ-------------- } } } } $GLOBALS["SCODER_BUYMORE_IS_CHECK"] = 'Y'; //уже проверено return true; } public static function OnBasketAddHandler($ID, $arFields) { $arFields["ID"] = $ID; //if ($GLOBALS["SC_PROCESSOR_WORKED_OUT"]!="Y") $obDiscount = new CSaleDiscount(); $aa = $obDiscount->Add($arFields); CSaleDiscount::Add($arFields); self::BasketEditDiscount(); } public static function OnBasketUpdateHandler($ID, $arFields) { $arFields["ID"] = $ID; //if ($GLOBALS["SC_PROCESSOR_WORKED_OUT"]!="Y") //self::AfterBasketEdit($arFields,false); self::BasketEditDiscount(); } public static function OnBasketDeleteHandler($ID) { self::BasketEditDiscount(); } public static function OnGetDiscountResultHandler() { self::BasketEditDiscount(); } public static function OnBeforeBasketAddHandler(&$arFields) { return self::BeforeBasketEdit($arFields,true); } public static function OnBeforeBasketUpdateHandler($ID,&$arFields) { //$arFields["ID"] = $ID; //self::BeforeBasketEdit($arFields,false); } //вспомогательная функция (УСТАРЕЛО, НЕ ИСПОЛЬЗУЕТСЯ) public static function AfterBasketEdit($arFields,$is_new) { } //вспомогательная функция: делает количество равным едининице (УСТАРЕЛО, НЕ ИСПОЛЬЗУЕТСЯ) public static function BeforeBasketEdit(&$arFields,$is_new = false) { } //до удаления FUSER_ID, метод CSaleUser::Delete public static function OnSaleUserDeleteHandler($ID) { $IS_DELETE_DISCOUNTS = Option::get(CScoderBuymoreEvents::MODULE_ID, 'IS_DELETE_DISCOUNTS'); if ($IS_DELETE_DISCOUNTS != "N") { global $USER; if (!is_object($USER)) $USER = new CUser; $profile_iblock_id = Option::get(self::MODULE_ID, "scoder_buymore_profiles"); //ИД инфоблока, где хранятся порфили if ($profile_iblock_id>0) { $filter = array( "ACTIVE" => "Y", "ACTIVE_DATE"=>"Y", "IBLOCK_ID" => $profile_iblock_id, "PROPERTY_SITE_ID" => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, "PROPERTY_USER_GROUPS" => $USER->GetUserGroupArray(), ); $rsData = CIBlockElement::GetList( array("SORT" => "ASC","ID" => "ASC"), $filter, false, false, Array("ID") ); $obDiscount = new CSaleDiscount(); while ($ob = $rsData->GetNextElement()) { $arElement = $ob->GetFields(); //удаляем скидку при удалении FUSER_ID $db_res = CSaleDiscount::GetList( array("SORT" => "ASC"), array( 'XML_ID' => 'scoder_buymore_'. $arElement['ID'] . "_" . $ID, ), false, false, array("ID") ); if ($ar_res = $db_res->Fetch()) { $obDiscount->Delete($ar_res["ID"]); } } } } } //срабатывает только на изменение элемента корзины (вроде аналог OnBasketUpdate) public static function OnSaleBasketItemEntitySavedHandler(\Bitrix\Main\Event $event) { if ($GLOBALS["SC_PROCESSOR_WORKED_OUT"]!="Y") { $GLOBALS["SC_PROCESSOR_WORKED_OUT"] = "Y"; $active = Option::get(self::MODULE_ID, "ACTIVE"); //Если модуль активен в целом if ($active == '' || $active == 'Y') { $profiles_iblock_id = Option::get(self::MODULE_ID, "scoder_buymore_profiles"); //ИД инфоблока, где хранятся порфили if ($profiles_iblock_id>0) { global $USER; if (!is_object($USER)) $USER = new CUser; //запрос всех профилей $profiles = array(); $bprofiles = false; $filter_profiles = array( "ACTIVE" => "Y", "ACTIVE_DATE"=>"Y", "IBLOCK_ID" => $profiles_iblock_id, "PROPERTY_SITE_ID" => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, "PROPERTY_USER_GROUPS" => $USER->GetUserGroupArray(), ); $rsData = CIBlockElement::GetList( array("SORT" => "ASC","ID" => "ASC"), $filter_profiles, false, false, Array("ID","NAME","ACTIVE","IBLOCK_ID","SORT","PROPERTY_*") ); while ($ob = $rsData->GetNextElement()) { $profile = $ob->GetFields(); $profile["PROPERTIES"] = $ob->GetProperties(); $profiles[] = $profile; $bprofiles = true; } //если найден хотя бы один профиль if ($bprofiles) { $quantities = array(); $fuser = Sale\Fuser::getId(); $dbBasketItems = Sale\Internals\BasketTable::getList(array( "filter" => array( "FUSER_ID" => $fuser, "ORDER_ID" => null, "LID" => $_REQUEST["siteId"] ? $_REQUEST["siteId"] : SITE_ID, "CAN_BUY" => "Y", "DELAY" => "N", ), 'select' =>array("ID","PRODUCT_ID", "QUANTITY"), 'order' => array("ID" => "DESC") )); $items = array(); while ($item = $dbBasketItems->Fetch()) { $quantities[$item["PRODUCT_ID"]] += $item["QUANTITY"]; //собираем все количество по какому то одному продукту $items[] = $item; } //перебираем корзину foreach ($items as $item) { //если товаров в одной позции больше 1 ИЛИ позиций по этому товару уже несколько if ($item["QUANTITY"]>1 || $quantities[$item["PRODUCT_ID"]] > 1 ) { $base_double = false; //нужно ли дублировать товар //ПЕРЕБОР ПРОФИЛЕЙ foreach ($profiles as $profile) { //приводим массиы свойств в нужный вид if (is_array($profile["PROPERTIES"])) { foreach ($profile["PROPERTIES"] as $property_code => $ar_property) { $profile[$property_code] = $profile["PROPERTIES"][$property_code]["~VALUE"]; $profile[$property_code . "_DESCRIPTION"] = $profile["PROPERTIES"][$property_code]["~DESCRIPTION"]; } } $double = false; //по умолчанию, НЕ дублировать //---------------------Учитывать количество одного и того же товара if ($profile["CONSIDER_QUANTITY"]=="Y") { $double = true; //по умолчанию, дублировать, если отмечено //-------------------------------------------- //Группы пользователей, на которые распространяются скидки $ar_groups = (is_array($profile['USER_GROUPS'])?$profile['USER_GROUPS']:array(2)); $arUserGroups = $USER->GetUserGroupArray(); //ID групп которым принадлежит текущий авторизованный пользователь //совпадения массивов $intersect = array_intersect($ar_groups, $arUserGroups); //если совпадений нет, то не дублировать if (count($intersect)<=0) $double = false; //Инфоблоки, на товары которых распространяются скидки $bIblockTrue = false; if (is_array($profile['IBLOCKS']) && count($profile['IBLOCKS'])>0) $bIblockTrue = true; $element_values = array(); $check_elements = false; if (is_array($profile['PRODUCTS'])) //ИД товаров, на которые применять акцию { $ii = 1; foreach ($profile['PRODUCTS'] as $element_id) { if ($element_id>0) { $element_values[$ii] = $element_id; $check_elements = true; $ii++; } } } $element_values_unset = array(); $check_elements_unset = false; if (is_array($profile['PRODUCTS_UNSET'])) //ИД товаров, на которые применять акцию { $ii = 1; foreach ($profile['PRODUCTS_UNSET'] as $element_id) { if ($element_id>0) { $element_values_unset[$ii] = $element_id; $check_elements_unset = true; $ii++; } } } //-------------------------------------------- $arElementToIblock = $arOfferParents = array(); $filter = array( "ID" => $item["PRODUCT_ID"] ); $filter["IBLOCK_ID"] = CIBlockElement::GetIBlockByID($item["PRODUCT_ID"]); $boffer = false; //если указаны "ИД товаров, на которые применять акцию" ИЛИ "ИД товаров, которые не должны участвовать в подсчете на скидку" ИЛИ "инфоблоки, на товары которых распространяются скидки" if ($check_elements || $check_elements_unset || $bIblockTrue ) { $res = CIBlockElement::GetList( Array("IBLOCK_ID"=>"ASC"), $filter, false, false, Array("ID", "IBLOCK_ID") ); while($ob = $res->GetNextElement()) { $arProduct = $ob->GetFields(); $arProduct["PROPERTIES"] = $ob->GetProperties(); $arElementToIblock[$arProduct["ID"]] = $arProduct["IBLOCK_ID"]; //соотношение ИД товара к инфоблоку //если торговое предложение if ($arProduct["PROPERTIES"]["CML2_LINK"]["~VALUE"] > 0) { $arOfferParents[$arProduct["ID"]] = $arProduct["PROPERTIES"]["CML2_LINK"]["~VALUE"]; //ставим в соотношение предложению его родительский товар $boffer = true; } } } //если указаны "Инфоблоки, на товары которых распростраяются скидки", но товар не принадлежит нужным инфоблокам if ($bIblockTrue && isset($arElementToIblock[$item["PRODUCT_ID"]]) && is_array($profile['IBLOCKS']) && !in_array($arElementToIblock[$item["PRODUCT_ID"]],$profile['IBLOCKS'])) $double = false; //если указаны "ИД товаров, которые не должны участвовать в подсчете на скидку" и это такой товар, от пропускаем его if ($check_elements_unset && is_array($element_values_unset) && (in_array($item["PRODUCT_ID"],$element_values_unset) || ($boffer && $arOfferParents[$item["PRODUCT_ID"]]>0 && in_array($arOfferParents[$item["PRODUCT_ID"]],$element_values_unset))) ) $double = false; //если не указаны ИД товаров, на которые применять акцию ИЛИ (указаны и товар пристутствует) if (!$check_elements || ($check_elements && (in_array($item["PRODUCT_ID"],$element_values) || ($boffer && $arOfferParents[$item["PRODUCT_ID"]]>0 && in_array($arOfferParents[$item["PRODUCT_ID"]],$element_values)))) ) { } else $double = false; //если включены фильтры if ($profile['IS_FILTER'] == "Y") { //сбор данных для определения типа инфоблока $res = CIBlock::GetList( Array("SORT" => "ASC"), Array(), false ); while($ar_res = $res->Fetch()) { if ($ar_res["ID"]!=$set_iblock_id) { $ar_iblocks[$ar_res["ID"]] = $ar_res["NAME"]; $ar_iblocks_info[$ar_res["ID"]] = $ar_res; } } unset($filter); //--------------------ФИЛЬТР---------- $iblock_id = $arElementToIblock[$item["PRODUCT_ID"]]; if (is_array($profile["FILTERS_DESCRIPTION"])) { foreach ($profile["FILTERS_DESCRIPTION"] as $kk => $ib) { if ($ib == $iblock_id) { $filter = $profile["FILTERS"][$kk]; } } } $arParams = array( "IBLOCK_ID" => $iblock_id, "IBLOCK_TYPE" => $ar_iblocks_info[$iblock_id]["IBLOCK_TYPE_ID"], ); $filterFields = CScoderBuymore::__get_filters($arParams); $ar_str = unserialize($filter); $fields = array(); if (isset($ar_str['fields'])) $fields = $ar_str['fields']; elseif (isset($ar_str['data']['fields'])) $fields = $ar_str['data']['fields']; $arCollectionFilter = array(); CScoderBuymore::CreateFilter($filterFields, $arCollectionFilter, $fields); //преобразуем фильтр в нормальный вид $real_filter = $arCollectionFilter; $real_filter["IBLOCK_ID"] = $iblock_id; $real_filter["ID"] = $item["PRODUCT_ID"]; foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnBeforeCheckIsDoubleFilter", true) as $arEvent) ExecuteModuleEventEx($arEvent, array(&$real_filter, $item, $profile)); //просто проверяем вернет ли товар по указанному фильтру $rs_filter = CIBlockElement::GetList( array("ID" => "ASC"), $real_filter, false, array("nTopCount" => 1), array("ID") ); if (!$ob_filter = $rs_filter->GetNextElement()) { $double = false; } //если элемент найден и включен "Учитывать фильтр родительского элемента для торговых предложений" if ($double && $profile['IS_FILTER_PARENT'] =="Y") { $mxResult = CCatalogSku::GetProductInfo($item["PRODUCT_ID"]); if (is_array($mxResult)) { $parent_id = $mxResult['ID']; $parent_iblock_id = $mxResult['IBLOCK_ID']; //-----ФИЛЬТР РОДИТЕЛЯ if ($parent_id>0 && $parent_iblock_id >0) { if (is_array($profile["FILTERS_DESCRIPTION"])) { foreach ($profile["FILTERS_DESCRIPTION"] as $kk => $ib) { if ($ib == $parent_iblock_id) { $filter = $profile["FILTERS"][$kk]; } } } $arParams = array( "IBLOCK_ID" => $parent_iblock_id, "IBLOCK_TYPE" => $ar_iblocks_info[$parent_iblock_id]["IBLOCK_TYPE_ID"], ); $filterFields = CScoderBuymore::__get_filters($arParams); $ar_str = unserialize($filter); unset($filter); $fields = array(); if (isset($ar_str['fields'])) $fields = $ar_str['fields']; elseif (isset($ar_str['data']['fields'])) $fields = $ar_str['data']['fields']; $arCollectionFilter = array(); CScoderBuymore::CreateFilter($filterFields, $arCollectionFilter, $fields); //преобразуем фильтр в нормальный вид $real_filter = $arCollectionFilter; $real_filter["IBLOCK_ID"] = $parent_iblock_id; $real_filter["ID"] = $parent_id; foreach (GetModuleEvents(CScoderBuymoreEvents::MODULE_ID, "OnBeforeCheckIsDoubleParentFilter", true) as $arEvent) ExecuteModuleEventEx($arEvent, array(&$real_filter, $item, $profile)); //просто проверяем вернет ли товар по указанному фильтру $rs_filter = CIBlockElement::GetList( array("ID" => "ASC"), $real_filter, false, array("nTopCount" => 1), array("ID") ); if (!$ob_filter = $rs_filter->GetNextElement()) { $double = false; //пропускаем товар, если не подходит фильтру } } } } unset($filter); //--------------------END. ФИЛЬТР------------------- } //если хотя бы в одном профиле нужно дублировать, о дублируем if ($double) { $base_double = true; break; } } } //КОНЕЦ ПЕРЕБОРА ПРОФИЛЕЙ //если хотя бы в одном профиле нужно дублировать, о дублируем if ($base_double) { $props = array(); //смотрим имеющиеся свойства корзины $db_res = CSaleBasket::GetPropsList( array( "ID" => "DESC", ), array( "BASKET_ID" => $item["ID"], ), false, array("nTopCount"=>100) ); while ($item_prop = $db_res->Fetch()) { if ($item_prop["CODE"] != "SCODER_BUYMORE_PROPERTY") { unset($item_prop["ID"]); unset($item_prop["BASKET_ID"]); $props[] = $item_prop; } } $base_props = $props; $base_props[] = array( "NAME" => "scoder_buymore_property", "CODE" => "SCODER_BUYMORE_PROPERTY", "VALUE" => uniqid() ); $load = array( "PROPS" => $base_props, "QUANTITY" => 1, ); CSaleBasket::Update($item["ID"], $load); //изменяем текучую позицию //добавляем как новые позиции for ($i = 2; $i <= $item["QUANTITY"]; $i++) { $props[] = array("NAME" => "scoder_buymore_property", "CODE" => "SCODER_BUYMORE_PROPERTY", "VALUE" => uniqid()); Add2BasketByProductID( $item["PRODUCT_ID"], 1, array(), $props ); } } } } } } } } } //срабатывает на каждый элемент корзины public static function onSaleBasketItemRefreshDataHandler(\Bitrix\Main\Event $event) { } } ?>