Наличие на складах в умном фильтре 1С-Битрикс, с автоматическим обновлением

Просмотров: 5529

Задача: добавить возможность фильтрации товаров по складам в умном фильтре. Данные должны обновляться автоматически, при импорте товаров из 1С.

Отбор по складам в умном фильтре 1С-Битрикс

Для начала создадим свойство в инфоблоке каталога, тип множественный список. В качестве элементов списка названия складов, по которым хотим сделать фильтрацию. В моем случае, свойство имеет код "ATT_NAL_STORE"

Отбор по складам в умном фильтре 1С-Битрикс
Названия складов, для фильтра, можно задать произвольно. Не обязательно один в один, как названия заданы в модуле магазина.

Связываем склады со свойством инфоблока

Теперь, нужно создать пользовательское поле у складов, тип число. Я задал код, этого, UF_ поля: "UF_ATT_NAL_STORE"

У каждого склада вписываем, в это поле, ID значения соответствующего ему элемента свойства инфоблока.

Отбор по складам в умном фильтре 1С-Битрикс

Таким образом мы связали каждый склад со свойством инфоблока.

Консольный скрипт для обновления свойства инфоблока

Cоздадим консольный скрипт который будет заполнять свойство инфоблока по crontab расписанию.

Если текучка товаров не большая, данный скрипт можно повесить на crontab задание, что бы выполнялся в фоне с заданной периодичностью, например, раз в 12 часов.

$_SERVER['DOCUMENT_ROOT'] = realpath(dirname(__FILE__) . '/../..');
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];

define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_NO_ACCELERATOR_RESET', true);

require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');

@set_time_limit(0);
@ignore_user_abort(true);

use \Bitrix\Main\Loader;

Loader::includeModule("iblock");

$IBLOCK_ID = 13;
$dbGoods = CIBlockElement::GetList(
    array('ID' => 'ASC'),
    array(
        'IBLOCK_ID' => $IBLOCK_ID,
    ),
    false,
    false,
    array(
        'ID'
    )
);
while ($arGood = $dbGoods->Fetch()) {
// Очищаем свойство от предыдущих значений
    CIBlockElement::SetPropertyValuesEx(
        $arGood['ID'],
        $IBLOCK_ID,
        array(
            'ATT_NAL_STORE' => ''
        )
    );

// Собираем инфу о складе
    $arStores = array();
    $dbStores = CCatalogStore::GetList(
        array(),
        array(
            'PRODUCT_ID' => array($arGood['ID']),
            'ACTIVE' => 'Y',
        ),
        false,
        false,
        array(
            'ID',
            'PRODUCT_AMOUNT',
            'UF_ATT_NAL_STORE'
        )
    );
    while ($arStore = $dbStores->Fetch()) {
        $arStores[] = $arStore;
    }


// Готовим свойство значение склад = ID свойства
    $PROPERTY_VALUES = array('VALUE' => '');
    foreach ($arStores as $arStore) {
        if ($arStore['PRODUCT_AMOUNT'] > 0) {
            $PROPERTY_VALUES[] = array(
                'VALUE' => $arStore['UF_ATT_NAL_STORE']
            );
        }
    }

// Устанавливаем значение свойства
    CIBlockElement::SetPropertyValuesEx(
        $arGood['ID'],
        $IBLOCK_ID,
        array(
            'ATT_NAL_STORE' => $PROPERTY_VALUES
        )
    );

// Обновляем индекс
    \Bitrix\Iblock\PropertyIndex\Manager::updateElementIndex(
        $IBLOCK_ID,
        $arGood['ID']
    );
}
  • С помощью CIBlockElement::GetList проходимся по всем элементам инфоблока (в моем случае $IBLOCK_ID = 13). Нам нужен только ID товара.
  • Внутри цикла очищаем значения свойства "ATT_NAL_STORE", установленные ранее, с помощью CIBlockElement::SetPropertyValuesEx
  • Далее, собираем массив $arStores с помощью CCatalogStore::GetList, в котором собрано наличие данного товара на складе и пользовательское поле склада "UF_ATT_NAL_STORE", связываюшее его со значением свойства "ATT_NAL_STORE"
  • Если на конкретном складе есть данный товар/элемент, наполняем массив $PROPERTY_VALUES в котором передаем ID элемента списка, свойства "ATT_NAL_STORE"
  • Из этого массива устанавливаем значение свойства методом CIBlockElement::SetPropertyValuesEx
  • Обновляем связанную с элементом инфомацию с помощью \Bitrix\Iblock\PropertyIndex\Manager::updateElementIndex

Обновление свойства при обмене с 1С

Если текучка товаров большая и необходима постоянная, актуальная информация о складах в умном фильтре. Можно добавить обработчик со скриптом в /local/php_interface/init.php, который будет срабатывать при каждом обновлении элемента каталога.

AddEventHandler("iblock", "OnAfterIBlockElementUpdate", array("UpdateStoreProp", "OnAfterIBlockElementUpdateHandler"));
class UpdateStoreProp
{
    function OnAfterIBlockElementUpdateHandler(&$arFields)
    {
        if ($arFields["RESULT"]) {
           ... ...
           Здесь скрипт приведенный выше
           В CIBlockElement::GetList добавляем
           фильтрацию 'ID' => $arFields['ID']
           ... ...
        }
    }
}
AddEventHandler("iblock", "OnAfterIBlockElementAdd", array("UpdateStoreProp2", "OnAfterIBlockElementAddHandler"));
class UpdateStoreProp2
{
    function OnAfterIBlockElementAddHandler(&$arFields)
    {
        if ($arFields["RESULT"]) {
           ... ...
           Здесь скрипт приведенный выше
           В CIBlockElement::GetList добавляем
           фильтрацию 'ID' => $arFields['ID']
           ... ...
        }
    }
}

Пример работы, с использованием данной заметки Магазин товаров для активного отдыха. Вопросы прошу писать в комментариях.

Михаил Базаров 20.12.2022
Дополнение для товаров со SKU.
Смысл в том, что если у товара есть SKU пробегаемся по ним и обновляем свойство у основного (родителя) элемента.

SKU товара получаем методом CCatalogSKU::getOffersList

Скрытый текст
AlexeyS 22.11.2023
По обновлению складов, возможно стоит привязываться к событиям каталога:
OnStoreProductAdd и OnStoreProductUpdate
Гость 27.11.2023
А как учесть тип товара ( с sku или без) например продублировать для свойства sku. При заполнении свойства наличия на складе учитывать тип товара. Если простой заполняем свойство товара , если с sku не заполняем, а заполняем свойство для sku. Какой фильтр должен быть на входе catalog.section чтобы получить объединённый массив элементов. По аналогии с getList “logic” “or” не работает. Никто не копал в эту сторону?

Блог-note: заметки разработчика

Denwer c PHP 7.1.8 и MYSQL 5.7 оптимизированный для Битрикс

В последнее время, все чаще приходиться работать на Windows, хотя и не люблю эту ОС- с точки зрения разработчика сайтов...

Определить местоположение пользователя и показать на карте

Задача определить местоположение текущего пользователя и показать его на карте, с меткой. Сделать можно с помощью класса...

Регистрация пользователя в определенную группу сайта на Битрикс

Достаточно часто требуется регистрировать пользователя в определенную группу, в зависимости от того какую форму регистра...

Показать пользователей онлайн на странице сайта

Задача: показать на странице сайта пользователей которые сейчас находятся на сайте. Используется штатный модуль "Ве...

Проверка на наличие элементов, текущего пользователя, в заданном инфоблоке.

Если стоит задача, определить наличие элементов созданных пользователем на сайте. Можно воспользоваться API: CUser и CIB...

Ajax форма обратной связи, реализация в битрикс

Иногда, на сайте требуется создать форму обратной связи, которая будет писать все данные в инфоблок. Способов реализации...

Получение списка Highload блоков с помощью API Битрикс

1С-Битрикс предоставляет мощный инструментарий для обеспечения эффективной работы ваших проектов. Одним из способов упра...

Основные функции вывода в шаблонах Битрикс

Знаю, что все их знают. Но иногда не бывает лишним собрать все самое используемое в одну кучку. Ведь у каждого бывают мо...

Создание агента в 1С-Битрикс, на реальном примере

Задача: Каждый час нужно обновлять свойство элементов/товаров с типом строка "В наличии", вписывать в него либ...