Поиск элементов не входящих в указанный интервал дат в 1С-Битрикс

Недавно встала задача реализовать на 1С Битрикс поиск по элементам, которые были бы свободны на указанный пользователем интервал дат. Это может быть всё что угодно начиная от брони услуг, которые могут быть забронированы только 1 человеком, либо аренда автомобиля, аренда номера в отеле или апартаментов.

Недолго думая, было принято решение реализовывать это на Highload-блоках. Итак, есть у нас определённая форма фильтра. Вы можете сделать её сами, указав только 2 поля с датами — дата начала брони и дата конца, либо модифицировать один из шаблонов фильтра по элементам или умного фильтра. Но сводится к тому, что нам необходимо иметь 2 input поля:

<form action="/my-filter/" method="GET" name="MY_FILTER">
    Дата начала брони: <input name="DATE_BEGIN" type="date" />
    Дата окончания брони: <input name="DATE_END" type="date" />
    <input type="submit" value="Найти!" />
</form>

Создадим наш HL блок под названием BOOKING, в нём нам нужны столбцы: ID, UF_PROP_ID, UF_DATE_BEGIN, UF_DATA_END.
Первый столбец, как вы понимаете AUTO_INCREMENT, во втором будем хранить id элемента из инфоблока, третий и четвертый — даты брони. Запомним ID созданного нами HL-блока, он нам пригодится дальше.

Далее нам необходимо, либо отредактировать стандартный компонент catalog.section, либо написать свой компонент основываясь на CIBlockElement::GetList(); Я писал свой компонент под мои задачи, здесь не буду приводить его код, а напишу, что нам необходимо для модификации стандартного компонента.

Создадим папку custom в папке /local/components/ и скопируем в неё папку catalog.section из /bitrix/components/bitrix/. Идём в скопированную папку и модифицируем файл component.php.

Нам необходимо исключить пересечение диапазонов дат.
[BeginDate1 — EndDate1] — первый диапазон
[BeginDate2 — EndDate2] — второй диапазон
Диапазоны не пересекаются, если BeginDate2 > EndDate1 или EndDate2 < BeginDate1. Используйте отрицание и получите условие пересечения.

Примерно на 772 строке перед кодом:

//EXECUTE
$rsElements = CIBlockElement::GetList($arSort, array_merge($arrFilter, $arFilter), false, $arNavParams, $arSelect);
$rsElements->SetUrlTemplates($arParams["DETAIL_URL"]);

Вставляем такой код:

if(!empty($_REQUEST["DATE_BEGIN"]))
    $dateBegin = $_REQUEST["DATE_BEGIN"];
    $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_BEGIN"] = $dateBegin;
if(!empty($_REQUEST["DATE_END"]))
    $dateEnd = $_REQUEST["DATE_END"];
    $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_END"] = $dateEnd;
// Тут хорошо бы сделать валидацию на входящие данные
 
/* 
   Если формат даты во входящих данных 
   отличается от MM.DD.YYYY используйте 
   $DB->FormatDate() для конвертации.
*/
 
// Подключим HL блоки
if (CModule::IncludeModule('highloadblock')) {
    $HLBlockId = 1; // Это ID созданного нами HL-блока
    $arHLBlock = Bitrix\Highloadblock\HighloadBlockTable::getById($HLBlockId)->fetch();
    $obEntity = Bitrix\Highloadblock\HighloadBlockTable::compileEntity($arHLBlock);
    $strEntityDataClass = $obEntity->getDataClass(); // Эта строчка необходима нам для работы с датой
 
    // Зададим логику фильтра по диапазону
    $resIDfree = $strEntityDataClass::getList(array(
	'select' => array('UF_PROP_ID'),
	'filter' => array(
	    'LOGIC' => 'OR',
	    array(
		'>UF_DATE_BEGIN' => $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_BEGIN"],
		'<=UF_DATE_BEGIN' => $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_END"]
	    ),
	    array(
		'<=UF_DATE_BEGIN' => $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_BEGIN"],
		'>=UF_DATA_END' => $arResult["FILTER_PARAMS"]["NO_FORMAT"]["DATE_BEGIN"]
	    )
	),
	'group' => array('UF_PROP_ID')
    ));
 
    while ($arID = $resIDfree->Fetch()) {
	$arIds[] = $arID["UF_PROP_ID"];
    }
 
    $arResult["NOT_IDs"] = $arIds;
    $arFilter["!ID"] = $arIds;
}

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

//EXECUTE
$rsElements = CIBlockElement::GetList($arSort, array_merge($arrFilter, $arFilter), false, $arNavParams, $arSelect);

Далее нам необходимо вывести этот компонент в index.php папки my-filter на сайте. Имя компонента будет custom:catalog.section. С настройками компонента, я думаю, вы справитесь сами.

В следующей статье рассмотрим пример внесения данных в созданный HL-блок по отслеживанию события OnSalePayOrder. Другими словами, забронируем нашу услугу только после оплаты.

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *