/ Bitrix - создание страницы с товарами со скидкой

Bitrix - создание страницы с товарами со скидкой

4 Окт 2018
Дмитрий М.
4615

При разработке интернет магазина потребовалось создать страницу, на которой бы отображались товары со скидками. Скидки в системе устанавливаются через Маркетинговые Предложения по средствам Правил работы с корзиной.

По сути задача сводится к созданию страницы /sale/ на которой необходимо разместить компонент bitrix:catalog.section и настроить у него выборку по товарам, на которые действует скидка.

Как создать страницу товаров со скидками?

Для примера создадим такую страницу на базе стандартного шаблона Интернет Магазина Bitrix. Для начала необходимо создать страницу /sale/ и добавить её в меню для вывода.

Screenshot_1.png

На странице /sale/ необходимо разместить компонент элементы раздела - bitrix:catalog.section, в настройках обязательно выбрать "Показывать все элементы, если не указан раздел".

Теперь настроим массив со значениями фильтра для фильтрации элементов (arrFilter). Для этого создадим класс, который формирует массив с ID товаров у которых есть действующая скидка в данный момент и для данного пользователя:

use Bitrix\Main\Loader;
use Bitrix\Main\SystemException;
 
class AllProductDiscount{
    /**
     * @return XML_ID|array
     * @throws SystemException
     * @throws \Bitrix\Main\LoaderException
     */
    public static function getFull($arrFilter = array(), $arSelect = array()){
        if(!Loader::includeModule('sale')) throw new SystemException('Не подключен модуль Sale');
 
	//Все товары со скидкой!!!
    // Группы пользователей
    global $USER;
    $arUserGroups = $USER->GetUserGroupArray();
    if (!is_array($arUserGroups)) $arUserGroups = array($arUserGroups);
    // Достаем старым методом только ID скидок привязанных к группам пользователей по ограничениям
    $actionsNotTemp = \CSaleDiscount::GetList(array("ID" => "ASC"),array("USER_GROUPS" => $arUserGroups),false,false,array("ID"));
    while($actionNot = $actionsNotTemp->fetch()){
      $actionIds[] = $actionNot['ID'];
    }
    $actionIds=array_unique($actionIds); sort($actionIds);
    // Подготавливаем необходимые переменные для разборчивости кода
    global $DB;
    $conditionLogic = array('Equal'=>'=','Not'=>'!','Great'=>'>','Less'=>'<','EqGr'=>'>=','EqLs'=>'<=');
    $arSelect = array_merge(array("ID","IBLOCK_ID","XML_ID"),$arSelect);
    $city='MSK';
    // Теперь достаем новым методом скидки с условиями. P.S. Старым методом этого делать не нужно из-за очень высокой нагрузки (уже тестировал)
    $actions = \Bitrix\Sale\Internals\DiscountTable::getList(array(
      'select' => array("ID","ACTIONS_LIST"),
      'filter' => array("ACTIVE"=>"Y","USE_COUPONS"=>"N","DISCOUNT_TYPE"=>"P","LID"=>SITE_ID,
      "ID"=>$actionIds,
      array(
        "LOGIC" => "OR",
        array(
          "<=ACTIVE_FROM"=>$DB->FormatDate(date("Y-m-d H:i:s"),"YYYY-MM-DD HH:MI:SS",\CSite::GetDateFormat("FULL")),
          ">=ACTIVE_TO"=>$DB->FormatDate(date("Y-m-d H:i:s"),"YYYY-MM-DD HH:MI:SS",\CSite::GetDateFormat("FULL"))
        ),
        array(
          "=ACTIVE_FROM"=>false,
          ">=ACTIVE_TO"=>$DB->FormatDate(date("Y-m-d H:i:s"),"YYYY-MM-DD HH:MI:SS",\CSite::GetDateFormat("FULL"))
        ),
        array(
          "<=ACTIVE_FROM"=>$DB->FormatDate(date("Y-m-d H:i:s"),"YYYY-MM-DD HH:MI:SS",\CSite::GetDateFormat("FULL")),
          "=ACTIVE_TO"=>false
        ),
        array(
          "=ACTIVE_FROM"=>false,
          "=ACTIVE_TO"=>false
        ),
      ))
    ));
    // Перебираем каждую скидку и подготавливаем условия фильтрации для CIBlockElement::GetList
    while($arrAction = $actions->fetch()){
      $arrActions[$arrAction['ID']] = $arrAction;
    }
    foreach($arrActions as $actionId => $action){
      $arPredFilter = array_merge(array("ACTIVE_DATE"=>"Y", "CAN_BUY"=>"Y"),$arrFilter); //Набор предустановленных параметров
      $arFilter = $arPredFilter; //Основной фильтр
      $dopArFilter = $arPredFilter; //Фильтр для доп. запроса
      $dopArFilter["=XML_ID"] = array(); //Пустое значения для первой отработки array_merge
      //Магия генерации фильтра
      foreach($action['ACTIONS_LIST']['CHILDREN'] as $condition){
        foreach($condition['CHILDREN'] as $keyConditionSub=>$conditionSub){
          $cs=$conditionSub['DATA']['value']; //Значение условия
          $cls=$conditionLogic[$conditionSub['DATA']['logic']]; //Оператор условия
          //$arFilter["LOGIC"]=$conditionSub['DATA']['All']?:'AND';
          $CLASS_ID = explode(':',$conditionSub['CLASS_ID']);
 
          if($CLASS_ID[0]=='ActSaleSubGrp') {
            foreach($conditionSub['CHILDREN'] as $keyConditionSubElem=>$conditionSubElem){
              $cse=$conditionSubElem['DATA']['value']; //Значение условия
              $clse=$conditionLogic[$conditionSubElem['DATA']['logic']]; //Оператор условия
              //$arFilter["LOGIC"]=$conditionSubElem['DATA']['All']?:'AND';
              $CLASS_ID_EL = explode(':',$conditionSubElem['CLASS_ID']);
 
              if($CLASS_ID_EL[0]=='CondIBProp') {
                $arFilter["IBLOCK_ID"]=$CLASS_ID_EL[1];
                $arFilter[$clse."PROPERTY_".$CLASS_ID_EL[2]]=array_merge((array)$arFilter[$clse."PROPERTY_".$CLASS_ID_EL[2]],(array)$cse);
                $arFilter[$clse."PROPERTY_".$CLASS_ID_EL[2]]=array_unique($arFilter[$clse."PROPERTY_".$CLASS_ID_EL[2]]);
              }elseif($CLASS_ID_EL[0]=='CondIBName') {
                $arFilter[$clse."NAME"]=array_merge((array)$arFilter[$clse."NAME"],(array)$cse);
                $arFilter[$clse."NAME"]=array_unique($arFilter[$clse."NAME"]);
              }elseif($CLASS_ID_EL[0]=='CondIBElement') {
                $arFilter[$clse."ID"]=array_merge((array)$arFilter[$clse."ID"],(array)$cse);
                $arFilter[$clse."ID"]=array_unique($arFilter[$clse."ID"]);
              }elseif($CLASS_ID_EL[0]=='CondIBTags') {
                $arFilter[$clse."TAGS"]=array_merge((array)$arFilter[$clse."TAGS"],(array)$cse);
                $arFilter[$clse."TAGS"]=array_unique($arFilter[$clse."TAGS"]);
              }elseif($CLASS_ID_EL[0]=='CondIBSection') {
                $arFilter[$clse."SECTION_ID"]=array_merge((array)$arFilter[$clse."SECTION_ID"],(array)$cse);
                $arFilter[$clse."SECTION_ID"]=array_unique($arFilter[$clse."SECTION_ID"]);
              }elseif($CLASS_ID_EL[0]=='CondIBXmlID') {
                $arFilter[$clse."XML_ID"]=array_merge((array)$arFilter[$clse."XML_ID"],(array)$cse);
                $arFilter[$clse."XML_ID"]=array_unique($arFilter[$clse."XML_ID"]);
              }elseif($CLASS_ID_EL[0]=='CondBsktAppliedDiscount') { //Условие: Были применены скидки (Y/N)
                foreach($arrActions as $tempAction){
                  if(($tempAction['SORT']<$action['SORT']&&$tempAction['PRIORITY']>$action['PRIORITY']&&$cse=='N')||($tempAction['SORT']>$action['SORT']&&$tempAction['PRIORITY']<$action['PRIORITY']&&$cse=='Y')){
                    $arFilter=false;
                    break 4;
                  }
                }
              }
            }
          }elseif($CLASS_ID[0]=='CondIBProp') {
            $arFilter["IBLOCK_ID"]=$CLASS_ID[1];
            $arFilter[$cls."PROPERTY_".$CLASS_ID[2]]=array_merge((array)$arFilter[$cls."PROPERTY_".$CLASS_ID[2]],(array)$cs);
            $arFilter[$cls."PROPERTY_".$CLASS_ID[2]]=array_unique($arFilter[$cls."PROPERTY_".$CLASS_ID[2]]);
          }elseif($CLASS_ID[0]=='CondIBName') {
            $arFilter[$cls."NAME"]=array_merge((array)$arFilter[$cls."NAME"],(array)$cs);
            $arFilter[$cls."NAME"]=array_unique($arFilter[$cls."NAME"]);
          }elseif($CLASS_ID[0]=='CondIBElement') {
            $arFilter[$cls."ID"]=array_merge((array)$arFilter[$cls."ID"],(array)$cs);
            $arFilter[$cls."ID"]=array_unique($arFilter[$cls."ID"]);
          }elseif($CLASS_ID[0]=='CondIBTags') {
            $arFilter[$cls."TAGS"]=array_merge((array)$arFilter[$cls."TAGS"],(array)$cs);
            $arFilter[$cls."TAGS"]=array_unique($arFilter[$cls."TAGS"]);
          }elseif($CLASS_ID[0]=='CondIBSection') {
            $arFilter[$cls."SECTION_ID"]=array_merge((array)$arFilter[$cls."SECTION_ID"],(array)$cs);
            $arFilter[$cls."SECTION_ID"]=array_unique($arFilter[$cls."SECTION_ID"]);
          }elseif($CLASS_ID[0]=='CondIBXmlID') {
            $arFilter[$cls."XML_ID"]=array_merge((array)$arFilter[$cls."XML_ID"],(array)$cs);
            $arFilter[$cls."XML_ID"]=array_unique($arFilter[$cls."XML_ID"]);
          }elseif($CLASS_ID[0]=='CondBsktAppliedDiscount') { //Условие: Были применены скидки (Y/N)
            foreach($arrActions as $tempAction){
              if(($tempAction['SORT']<$action['SORT']&&$tempAction['PRIORITY']>$action['PRIORITY']&&$cs=='N')||($tempAction['SORT']>$action['SORT']&&$tempAction['PRIORITY']<$action['PRIORITY']&&$cs=='Y')){
                $arFilter=false;
                break 3;
              }
            }
          }
        }
      }
      if($arFilter!==false&&$arFilter!=$arPredFilter){
        if(!isset($arFilter['=XML_ID'])){
          //Делаем запрос по каждому из фильтров, т.к. один фильтр не получится сделать из-за противоречий условий каждой скидки
          $res = \CIBlockElement::GetList(array(), $arFilter, false, false, $arSelect);
          while($ob = $res->GetNextElement()){
            $arFields = $ob->GetFields();
            $poductsArray['IDS'][] = $arFields["ID"];
          }
        }elseif(!empty($arFilter['=XML_ID'])){
          //Подготавливаем массив для отдельного запроса
          $dopArFilter['=XML_ID'] = array_unique(array_merge($arFilter['=XML_ID'],$dopArFilter['=XML_ID']));
        }
      }
    }
 
    if(isset($dopArFilter)&&!empty($dopArFilter['=XML_ID'])){
      //Делаем отдельный запрос по конкретным XML_ID
      $res = \CIBlockElement::GetList(array(), $dopArFilter, false, array("nTopCount"=>count($dopArFilter['=XML_ID'])), $arSelect);
      while($ob = $res->GetNextElement()){
        $arFields = $ob->GetFields();
        $poductsArray['IDS'][] = $arFields["ID"];
      }
    }
    $poductsArray['ids']=array_unique($poductsArray['ids']);
 
        return $poductsArray;
    }
}

Этот код нужно разместить в файле init.php ( /bitrix/php_interface/init.php ), после этого можем использовать класс AllProductDiscount. Преимущество данного класса заключается в быстрой обработки большого количества товаров со скидками.

Откроем файл /sale/index.php, перед вызовом компонента bitrix:catalog.section разместим код:

<?
	$res = AllProductDiscount::getFull(
	array("ACTIVE" => "Y", "SITE_ID" => SITE_ID),
	array()
	);
	foreach($res['IDS'] as $ID) {
    	$sale_id[] = $ID;
	}
	$GLOBALS['arrFilter'] = array("ID"=>$sale_id);
?>

Внимание! Не забываем, чтобы имя массива со значениями фильтра для фильтрации элементов в настройках компонента bitrix:catalog.section было arrFilter.

Статья была полезна? Поблагодарите автора.

Самые читаемые
#1С Битрикс, #Bitrix CMS, #.htaccess, #настройка редиректов
4 Авг 2019
#Хлебные крошки, #1С Битрикс, #Bitrix CMS, #bitrix:breadcrumbs, #component_epilog, #кэширование
1 Окт 2018
#ресайз изображений, #1С Битрикс, #Bitrix CMS
3 Мар 2019
#bitrix, #robots.txt, #sitemap.xml, #поддомены, #мультисайтовость
16 Окт 2018
#bitrix, #bitrix:catalog.section, #скидки, #товары со скидкой, #страница скидок, #страница со скидками
4 Окт 2018
#Bitrix CMS, #breadcrumb, #bitrix:breadcrumbs, #хлебные крошки, #настройка
13 Фев 2019
#bitrix, #пользовательские свойства, #тип свойств, #привязка к элементам
27 Ноя 2019
#bitrix, #свойства элементов, #обработчик событий, #OnBeforeIBlockElementUpdate, #OnIBlockElementSetPropertyValues
21 Июл 2020
#bitrix:news, #сортировка, #фильтрация, #bitrix:catalog, #catalog.section, #news.list
16 Дек 2020