В принципе, если вы прочитаете следующую статью и скачаете исходники кистомизации скидок в битриксе , моё читать не надо. Но я , сделаю дополнительную реализацию на HiloadBlock.
Мы здесь будем разрабатывать кастомизированное правило работы с корзиной в битриксе . Вернее нет. Использовать и дополнять.
Читаем эту статью, в конце заполняем форму и скачиваем файлики для битрикса.
https://www.intervolga.ru/blog/projects/personalnye-tseny-i-skidki-v-internet-magazine-na-1c-bitriks/
Инструкция для кастомизированного правила работы скорзиной (от интерволга)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Для создания кастомизированного правила работы с корзиной на сайт необходимо: 1. Скопировать файл saleactiondiscountfromdirectory.php в папку сайта рядом с init.php (либо в /local/php_interface/init.php либо /bitrix/php_interface/init.php либо /bitrix/php_interface/ID сайта/init.php). 2. Подключить файл saleactiondiscountfromdirectory.php в init.php: include "saleactiondiscountfromdirectory.php"; 3. Создать Highload блок. Импортировать файл discount_hlb.xml со структурой hl-блока на странице ваш-сайт/bitrix/admin/highloadblock_import.php 4. Создать записи в hl-блоке. 5. Создать правило работы с корзиной. На странице ваш-сайт/bitrix/admin/sale_discount.php нажать на кнопку "добавить правило". В настройках правила на вкладке "Общие параметры" указать Сайт, Название (например, "Персональная скидка") и Активность. На вкладке "Действия и условия" добавить действие "Применить скидку из справочника" и выбрать в выпадающем списке созданный hl-блок со скидками. Сохранить правило. 6. Результат работы правила можно увидеть в корзине, положив в нее товары указанные в hl-блоке для текущего пользователя. |
содержимое файлика saleactiondiscountfromdirectory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
<? use \Bitrix\Main\Loader, \Bitrix\Highloadblock\HighloadBlockTable as HLB, \Bitrix\Highloadblock\HighloadBlockLangTable; if(Loader::includeModule('sale')) { $eventManager = \Bitrix\Main\EventManager::getInstance(); $eventManager->addEventHandlerCompatible("sale", "OnCondSaleActionsControlBuildList", [ "SaleActionDiscountFromDirectory", "GetControlDescr" ]); class SaleActionDiscountFromDirectory extends \CSaleActionCtrlBasketGroup { public static function GetClassName() { return __CLASS__; } public static function GetControlID() { return "DiscountFromDirectory"; } public static function GetControlDescr() { return parent::GetControlDescr(); } public static function GetAtoms() { return static::GetAtomsEx(false, false); } public static function GetControlShow($arParams) { $arAtoms = static::GetAtomsEx(false, false); $arResult = [ "controlId" => static::GetControlID(), "group" => false, "label" => "Применить скидку из справочника", "defaultText" => "", "showIn" => static::GetShowIn($arParams["SHOW_IN_GROUPS"]), "control" => [ "Применить скидку из HighLoad блока", $arAtoms["HLB"] ] ]; return $arResult; } public static function GetAtomsEx($strControlID = false, $boolEx = false) { $boolEx = (true === $boolEx ? true : false); $hlbList = []; if (\Bitrix\Main\Loader::includeModule('highloadblock')) { $dbRes = HLB::GetList([]); while ($el = $dbRes->fetch()) { $hlbList[$el['ID']] = $el['NAME']; } $res = HighloadBlockLangTable::GetList(['filter' => ['=LID' => LANGUAGE_ID]]); while ($el = $res->fetch()) { if ($hlbList[$el['ID']]) $hlbList[$el['ID']] = $el['NAME'] . " [" . $hlbList[$el['ID']] . "]"; } } $arAtomList = [ "HLB" => [ "JS" => [ "id" => "HLB", "name" => "extra", "type" => "select", "values" => $hlbList, "defaultText" => "...", "defaultValue" => "", "first_option" => "..." ], "ATOM" => [ "ID" => "HLB", "FIELD_TYPE" => "string", "FIELD_LENGTH" => 255, "MULTIPLE" => "N", "VALIDATE" => "list" ] ], ]; if (!$boolEx) { foreach ($arAtomList as &$arOneAtom) { $arOneAtom = $arOneAtom["JS"]; } if (isset($arOneAtom)) { unset($arOneAtom); } } return $arAtomList; } public static function Generate($arOneCondition, $arParams, $arControl, $arSubs = false) { $mxResult = __CLASS__ . "::applyProductDiscount(" . $arParams["ORDER"] . ", " . "\"" . $arOneCondition["HLB"] . "\"" . ");"; return $mxResult; } /** * Применяет скидку из справочника к товарам из корзины * @param $arOrder * @param $hlb - Highload block */ public static function applyProductDiscount(&$arOrder, $hlb) { $userId = $arOrder['USER_ID']; if ($userId && \Bitrix\Main\Loader::includeModule('highloadblock')) { $productIds = []; foreach ($arOrder['BASKET_ITEMS'] as &$product) { $productIds[] = $product['PRODUCT_ID']; } unset($product); $hlblock = HLB::getById($hlb)->fetch(); if(!$hlblock) { return; } $entity = HLB::compileEntity($hlblock); $entityClass = $entity->getDataClass(); //Находим записи в справочнике с нужными параметрами - товар/пользователь $dbRes = $entityClass::getList([ 'filter' => [ '=UF_PRODUCT' => $productIds, '=UF_USER' => $userId ], 'order' => [ 'ID' => 'DESC' ] ]); $discounts = []; while ($el = $dbRes->fetch()) { if (!$discounts[$el['UF_PRODUCT']]) { $discounts[$el['UF_PRODUCT']] = $el; } } //Применяем скидку foreach ($arOrder['BASKET_ITEMS'] as &$product) { $productId = $product['PRODUCT_ID']; if ($discounts[$productId]) { $product['DISCOUNT_PRICE'] = $product['BASE_PRICE'] * $discounts[$productId]['UF_DISCOUNT'] / 100; $product['PRICE'] = $product['BASE_PRICE'] - $product['DISCOUNT_PRICE']; } } unset($product); } } } } |
файлик hiload блока discount_hlb.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
<?xml version="1.0" encoding="UTF-8"?> <hiblock> <hiblock> <id>3</id> <name>DISCOUNT</name> <table_name>discount</table_name> </hiblock> <langs> </langs> <fields> <field> <id>56</id> <entity_id>HLBLOCK_3</entity_id> <field_name>UF_PRODUCT</field_name> <user_type_id>string</user_type_id> <xml_id /> <sort>100</sort> <multiple>N</multiple> <mandatory>N</mandatory> <show_filter>N</show_filter> <show_in_list>Y</show_in_list> <edit_in_list>Y</edit_in_list> <is_searchable>N</is_searchable> <settings> <size>20</size> <rows>1</rows> <regexp /> <min_length>0</min_length> <max_length>0</max_length> <default_value /> </settings> <edit_form_label> <en /> <ru>ID товара</ru> </edit_form_label> <list_column_label> <en /> <ru>ID товара</ru> </list_column_label> <list_filter_label> <en /> <ru /> </list_filter_label> <error_message> <en /> <ru /> </error_message> <help_message> <en /> <ru /> </help_message> <base_type>string</base_type> </field> <field> <id>58</id> <entity_id>HLBLOCK_3</entity_id> <field_name>UF_DISCOUNT</field_name> <user_type_id>string</user_type_id> <xml_id /> <sort>100</sort> <multiple>N</multiple> <mandatory>N</mandatory> <show_filter>N</show_filter> <show_in_list>Y</show_in_list> <edit_in_list>Y</edit_in_list> <is_searchable>N</is_searchable> <settings> <size>20</size> <rows>1</rows> <regexp /> <min_length>0</min_length> <max_length>0</max_length> <default_value /> </settings> <edit_form_label> <en>Discount (%)</en> <ru>Размер скидки (%)</ru> </edit_form_label> <list_column_label> <en>Discount (%)</en> <ru>Размер скидки (%)</ru> </list_column_label> <list_filter_label> <en /> <ru /> </list_filter_label> <error_message> <en /> <ru /> </error_message> <help_message> <en>Скидка на товар в процентах</en> <ru>Скидка на товар в процентах</ru> </help_message> <base_type>string</base_type> </field> <field> <id>59</id> <entity_id>HLBLOCK_3</entity_id> <field_name>UF_USER</field_name> <user_type_id>string</user_type_id> <xml_id /> <sort>100</sort> <multiple>N</multiple> <mandatory>N</mandatory> <show_filter>N</show_filter> <show_in_list>Y</show_in_list> <edit_in_list>Y</edit_in_list> <is_searchable>N</is_searchable> <settings> <size>20</size> <rows>1</rows> <regexp /> <min_length>0</min_length> <max_length>0</max_length> <default_value /> </settings> <edit_form_label> <en>User id</en> <ru>ID Пользователя</ru> </edit_form_label> <list_column_label> <en>User id</en> <ru>ID Пользователя</ru> </list_column_label> <list_filter_label> <en>User id</en> <ru>ID Пользователя</ru> </list_filter_label> <error_message> <en /> <ru /> </error_message> <help_message> <en /> <ru /> </help_message> <base_type>string</base_type> </field> </fields> </hiblock> |
Теперь вы подключили по инструкции провайдер цен и можете управлять скидками, создавая значения в инфоблоке
теперь , как использовать
Эти события я вешаю на обработчики добавления в корзину (в php init). Там же подключаю провайдер цен.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
AddEventHandler("sale", "OnBasketAdd", "HandlerAddCart"); AddEventHandler("sale", "OnBasketUpdate", "HandlerUpdateCart"); AddEventHandler("sale", "OnBasketDelete", "deleteInCart"); //подключаем провайдер цен , новый include "saleactiondiscountfromdirectory.php"; function HandlerAddCart(&$arFields){ DiscountP::reCalculateCart(); } function HandlerUpdateCart($ID,&$arFields) { DiscountP::reCalculateCart(); } function deleteInCart($ID) { DiscountP::reCalculateCart(); } |
Теперь сам класс discount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
<?php use Bitrix\Sale; class DiscountP { static function reCalculateCart(){ //очищаем все скидки, делаем их заново при каждом обращении DiscountP::ClearDiscount(); $massSetkaNabora=array( 'nabor'=>array(), '2'=>array(), // '11'=>array(), // '12' =>array(), // ); foreach ($massSetkaNabora as $key=>$value){ $massSetkaNabora[$key]['QUANTITY']=0; // настоящее колиечество товара $massSetkaNabora[$key]['PRODUCT_ID']=0; $massSetkaNabora[$key]['DISCOUNT']=15;//значение скидки по умолчанию, мы это значение изменим } $basketRes = Sale\Internals\BasketTable::getList(array( 'filter' => array( 'FUSER_ID' => Sale\Fuser::getId(), 'ORDER_ID' => 'ID', 'LID' => SITE_ID, 'CAN_BUY' => 'Y', ), 'order' => array( 'SORT' => 'ASC', 'ID' => 'ASC' ) )); //собираем все id в корзине, выставляем сразу while ($item = $basketRes->fetch()) { if($discount_cat=DiscountP::isTovarInNabor($item['PRODUCT_ID'], $item['NAME'])){ // debug($discount_cat); //мы заполняем только первые элементы в наборе, остальные пропускаем if($massSetkaNabora[$discount_cat]['PRODUCT_ID']==0){ $massSetkaNabora[$discount_cat]['PRODUCT_ID']=$item['PRODUCT_ID']; $massSetkaNabora[$discount_cat]['QUANTITY']=round($item['QUANTITY']); } } } // поиск минимума в количестве // что бы усечь лишние $MIN_QUANTITY = PHP_INT_MAX; //минимальное количество $min_key = null; foreach($massSetkaNabora as $key => $val) { if ($val['QUANTITY'] < $MIN_QUANTITY) { $MIN_QUANTITY = $val['QUANTITY']; $min_key = $key; } } //debug('минимум:'); //debug($MIN_QUANTITY); if($MIN_QUANTITY==0){ // echo 'Скидки не применяем, очистка скидок'; DiscountP::ClearDiscount(); }else{ //вычисляем //и изменяем процент скидки foreach($massSetkaNabora as $key => $val) { if($MIN_QUANTITY==$val['QUANTITY']){ // заносим 15 % // echo 'Заносим 15 %; '; DiscountP::addDiscountTovary($val['PRODUCT_ID'],15); }else{ //вычисляем // echo 'Вычисляем , по формуле'; $discount_new=round($MIN_QUANTITY*15/$val['QUANTITY'],2); // echo $discount_new.' '; DiscountP::addDiscountTovary($val['PRODUCT_ID'],$discount_new); } } // echo 'Скидки применяем'; } } //если есть 1 товар из набора в корзине, то показываю уведомление // это нужно для показа уведомления // в корзине static function isInCart1TovarIzNabora() { $flag=false; $basketRes = Sale\Internals\BasketTable::getList(array( 'filter' => array( 'FUSER_ID' => Sale\Fuser::getId(), 'ORDER_ID' => null, 'LID' => SITE_ID, 'CAN_BUY' => 'Y', ) )); //собираем все id в корзине, выставляем сразу while ($item = $basketRes->fetch()) { if(DiscountP::isTovarInNabor($item['PRODUCT_ID'], $item['NAME'])){ $flag=true; } } return $flag; } //проверка товара , в списке набора ли // принадлежит ли нескольким категориям и и набор //определяем по id товара и имени. //возвращает false или же id категории или же набор static function isTovarInNabor($tovar_id, $name_tovar) { $inNabor=false; $mass_cat=array( '2'=>false, //категория 1 '11'=>false , //категория 1 '12'=>false, //кат 2 ); if (strpos($name_tovar,'имятовара') !== false) { $inNabor='nabor'; } $id_for_search_cat=$tovar_id; // id для поиска категорий (у некоторых товаров торговые предложения) $mxResult = CCatalogSku::GetProductInfo( $tovar_id ); if (is_array($mxResult)) { $id_for_search_cat=$mxResult['ID']; } //получаем все группы, к которым принадлежит товар $arSelect2 = Array("ID","NAME", "CODE"); $res = CIBlockElement::GetElementGroups($id_for_search_cat, true , $arSelect2); while($ob = $res->Fetch()) { if (array_key_exists($ob['ID'], $mass_cat)) { $inNabor=$ob['ID']; } } return $inNabor; } //получаем скидки текущего пользователя, весь список static function GetListDiscountUser(){ global $USER; $arFilter = array( "UF_USER"=>$USER->GetID(), ); $entity_data_class = HLBData::GetEntityDataClass(DISCOUNT_HL_BLOCK_ID); $rsData = $entity_data_class::getList(array( 'select' => array('*'), "filter" => $arFilter, )); // $ret=array(); while($elIntesity = $rsData->fetch()){ $ret[]=$elIntesity; } return $ret; } //получаем скидку по id njdfhf static function GetDiscountByIdTovar($id_tovar){ global $USER; $arFilter = array( "UF_USER"=>$USER->GetID(), "UF_PRODUCT"=>$id_tovar, ); $entity_data_class = HLBData::GetEntityDataClass(DISCOUNT_HL_BLOCK_ID); $rsData = $entity_data_class::getList(array( 'select' => array('*'), "filter" => $arFilter, )); $ret=false; if($elIntesity = $rsData->fetch()){ $ret=$elIntesity; } return $ret; } //изменяем скидку по id hiload id товару и значение скидки static function updateDiscount($ID,$id_tovar,$discount){ $arData=array( "UF_PRODUCT"=>$id_tovar, "UF_DISCOUNT"=>round($discount,2), ); HLBData::updateHLBData (DISCOUNT_HL_BLOCK_ID, $ID, $arData); } //добавляем скидку (использовать нельзя , есть другая функция) static function addDiscount($id_tovar,$discount){ global $USER; $arData=array( "UF_USER"=>$USER->GetID(), "UF_PRODUCT"=>$id_tovar, "UF_DISCOUNT"=>round($discount,2), ); $result_add = HLBData::addHLBData (DISCOUNT_HL_BLOCK_ID, $arData); } //вычищаем все скидки пользователя static function ClearDiscount(){ $arDiscount=DiscountP::GetListDiscountUser(); foreach ($arDiscount as $item){ HLBData::deleteHLBData (DISCOUNT_HL_BLOCK_ID, $item['ID']) ; } } //добавляем скидку товару (если есть такой товар, то обновляем) static function addDiscountTovary($id_tovar,$discount){ $data_message=DiscountP::GetDiscountByIdTovar($id_tovar); if(empty($data_message)){ DiscountP::addDiscount($id_tovar,$discount); }else{ //уже вставляем id DiscountP::updateDiscount($data_message['ID'] ,$id_tovar,$discount); } } } |
Не пугайтесь функции reCalculateCart(), т.к это мой код.
В ней важное
1 DiscountP::ClearDiscount(); — очистка скидок
2 $basketRes = Sale\Internals\BasketTable::getList — цикл прохода по элементам корзины
3 выставление продукту товара по его айди скидки в 15 процентов DiscountP::addDiscountTovary($val[‘PRODUCT_ID’],15);
или же по правилу нужного значения.
эту функцию можно переписать на этих 3-х строках. У меня же сложный набор по правилу.
подключение классов
1 2 3 4 5 |
\Bitrix\Main\Loader::registerAutoLoadClasses(null, [ 'HLBData' => '/local/php_interface/include/HLBData.php',//класс hiload блоков 'DiscountP' => '/local/php_interface/include/DiscountP.php', // управление скидками ]); |
На всякий случай код класса hiload block
http://ftask.ru/highload…
сам файлик интерволги :intervolga.personal_discount.zip
в нем есть Провайдер цен и пример OnGetOptimalPrice , для изменения цен
HIGHLOAD граматей 🙂
Все верно) Рад что этот толмут кто-то прочитал так внимательно) Видимо полезный.
Скидка будет видна только в корзине?
да