Настройка информации о режиме работы магазинов 1С-Битрикс
Пользователь видит кнопку «Самовывоз» и переходит к списку точек. Рядом с каждым адресом — ничего о часах работы, или хуже: статичный текст «Пн-Пт 9:00-18:00», который актуален ровно до первого изменения, но никто не знает, в каком файле его менять. Задача — хранить режим работы в структурированном виде и показывать актуальный статус «открыто/закрыто» в реальном времени.
Структура хранения расписания
Стандартная таблица b_sale_store содержит поле SCHEDULE типа TEXT — произвольная строка без структуры. Для машинной обработки это не подходит.
Правильный подход: хранить расписание в JSON. Либо добавить пользовательское поле к торговой точке (через CUserTypeEntity с ENTITY_ID = 'SALE_STORE'), либо создать отдельную таблицу:
CREATE TABLE bl_store_schedule (
id SERIAL PRIMARY KEY,
store_id INT NOT NULL REFERENCES b_sale_store(ID) ON DELETE CASCADE,
day_of_week SMALLINT NOT NULL, -- 1=Пн, 7=Вс
open_time TIME, -- NULL = закрыто в этот день
close_time TIME,
is_closed BOOLEAN DEFAULT FALSE,
UNIQUE (store_id, day_of_week)
);
Такая структура позволяет хранить разное расписание на каждый день недели и явно помечать выходные дни через is_closed = TRUE.
Исключения: праздники и временные изменения
Помимо стандартного расписания нужна таблица исключений:
CREATE TABLE bl_store_schedule_exception (
id SERIAL PRIMARY KEY,
store_id INT NOT NULL,
date DATE NOT NULL,
open_time TIME,
close_time TIME,
is_closed BOOLEAN DEFAULT FALSE,
note VARCHAR(255),
UNIQUE (store_id, date)
);
При расчёте статуса «открыто/закрыто» сначала проверяем bl_store_schedule_exception на текущую дату, и только при отсутствии исключения берём данные из bl_store_schedule по номеру дня недели.
Расчёт текущего статуса
function getStoreStatus(int $storeId): array
{
$connection = \Bitrix\Main\Application::getConnection();
$now = new \DateTime('now', new \DateTimeZone('Europe/Minsk'));
$date = $now->format('Y-m-d');
$time = $now->format('H:i:s');
$dow = (int)$now->format('N'); // 1=Пн, 7=Вс
// Сначала проверяем исключение на сегодня
$exception = $connection->query(
"SELECT * FROM bl_store_schedule_exception
WHERE store_id = {$storeId} AND date = '{$date}'"
)->fetch();
$schedule = $exception ?: $connection->query(
"SELECT * FROM bl_store_schedule
WHERE store_id = {$storeId} AND day_of_week = {$dow}"
)->fetch();
if (!$schedule || $schedule['is_closed']) {
return ['status' => 'closed', 'label' => 'Закрыто'];
}
$isOpen = $time >= $schedule['open_time'] && $time < $schedule['close_time'];
return [
'status' => $isOpen ? 'open' : 'closed',
'label' => $isOpen
? 'Открыто до ' . substr($schedule['close_time'], 0, 5)
: 'Откроется в ' . substr($schedule['open_time'], 0, 5),
'open' => $schedule['open_time'],
'close' => $schedule['close_time'],
];
}
Часовые пояса при сети магазинов
Если сеть охватывает несколько часовых поясов — добавляем поле timezone в b_sale_store (пользовательское поле или расширение). При расчёте статуса создаём DateTime с правильным DateTimeZone для каждого магазина. Хранить расписание в UTC и конвертировать при отображении — распространённая ошибка, которая ломается при переходе на летнее/зимнее время.
Отображение в компоненте и кеширование
Компонент торговых точек bitrix:sale.store.list расширяется через result_modifier.php. В нём вызываем getStoreStatus() для каждой точки и добавляем данные в $arResult. Кеширование: статус «открыто/закрыто» меняется дважды в день (открытие и закрытие), поэтому TTL кеша — не более 30 минут. Можно использовать теговый кеш с тегом store_{$storeId}_schedule и инвалидировать его при обновлении расписания в административной части.
Что настраиваем
- Таблицы
bl_store_scheduleиbl_store_schedule_exception - Административный интерфейс для редактирования расписания (агент обновления или форма в административном разделе)
- Функцию расчёта статуса с поддержкой часовых поясов
- Расширение компонента
bitrix:sale.store.listчерезresult_modifier.php - Кеширование с TTL 30 минут и инвалидацией при изменении расписания







