Настройка выбора времени самовывоза 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Настройка выбора времени самовывоза 1С-Битрикс
Простая
~1 рабочий день
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    745
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Настройка выбора времени самовывоза 1С-Битрикс

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

Хранение временных слотов

Слоты хранятся в пользовательском хранилище: либо в b_user_field_* как настройки службы доставки, либо в отдельной таблице. Для гибкости — отдельная таблица:

CREATE TABLE b_pickup_slot (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    STORE_ID INT NOT NULL,
    SLOT_DATE DATE NOT NULL,
    SLOT_TIME_FROM TIME NOT NULL,
    SLOT_TIME_TO TIME NOT NULL,
    CAPACITY INT NOT NULL DEFAULT 10,      -- максимум заказов в слоте
    BOOKED INT NOT NULL DEFAULT 0,         -- уже забронировано
    ACTIVE CHAR(1) DEFAULT 'Y',
    INDEX idx_store_date (STORE_ID, SLOT_DATE),
    INDEX idx_active (ACTIVE)
);

Заполнение слотов на неделю вперёд — через агент Битрикс, который генерирует слоты по расписанию работы каждой точки.

Получение доступных слотов через AJAX

// /ajax/pickup-slots.php
\Bitrix\Main\Loader::includeModule('main');

$storeId = (int)($_GET['store_id'] ?? 0);
$date    = $_GET['date'] ?? date('Y-m-d');

if (!$storeId) {
    echo json_encode(['error' => 'store_id required']);
    exit;
}

$connection = \Bitrix\Main\Application::getConnection();
$slots = $connection->query("
    SELECT
        ID,
        DATE_FORMAT(SLOT_TIME_FROM, '%H:%i') as TIME_FROM,
        DATE_FORMAT(SLOT_TIME_TO, '%H:%i') as TIME_TO,
        CAPACITY - BOOKED as AVAILABLE
    FROM b_pickup_slot
    WHERE STORE_ID = ? AND SLOT_DATE = ? AND ACTIVE = 'Y'
      AND BOOKED < CAPACITY
    ORDER BY SLOT_TIME_FROM
", [$storeId, $date])->fetchAll();

header('Content-Type: application/json');
echo json_encode(['slots' => $slots]);

Свойства заказа для хранения слота

Магазин → Настройки → Свойства заказа → Добавить:

  • PICKUP_SLOT_ID — тип «Число», ID выбранного слота
  • PICKUP_DATE — тип «Строка», дата в формате ДД.ММ.ГГГГ
  • PICKUP_TIME — тип «Строка», интервал «10:00–11:00»

Компонент выбора слота в форме заказа

// В шаблоне компонента оформления заказа
document.addEventListener('DOMContentLoaded', function() {
    const storeSelect = document.getElementById('pickup-store');
    const dateInput   = document.getElementById('pickup-date');
    const slotList    = document.getElementById('slot-list');

    function loadSlots() {
        const storeId = storeSelect.value;
        const date    = dateInput.value;
        if (!storeId || !date) return;

        slotList.innerHTML = '<li>Загрузка...</li>';

        fetch('/ajax/pickup-slots/?store_id=' + storeId + '&date=' + date)
            .then(r => r.json())
            .then(data => {
                slotList.innerHTML = '';
                if (!data.slots || !data.slots.length) {
                    slotList.innerHTML = '<li>Нет доступных слотов</li>';
                    return;
                }
                data.slots.forEach(slot => {
                    const li = document.createElement('li');
                    li.className = 'slot-option';
                    li.dataset.slotId = slot.ID;
                    li.innerHTML =
                        slot.TIME_FROM + '–' + slot.TIME_TO +
                        ' <span class="available">(' + slot.AVAILABLE + ' мест)</span>';
                    li.addEventListener('click', () => selectSlot(slot));
                    slotList.appendChild(li);
                });
            });
    }

    function selectSlot(slot) {
        document.querySelectorAll('.slot-option').forEach(el => el.classList.remove('active'));
        document.querySelector('[data-slot-id="' + slot.ID + '"]').classList.add('active');

        // Заполняем скрытые поля свойств заказа
        document.querySelector('[name="PICKUP_SLOT_ID"]').value = slot.ID;
        document.querySelector('[name="PICKUP_TIME"]').value =
            slot.TIME_FROM + '–' + slot.TIME_TO;
    }

    storeSelect.addEventListener('change', loadSlots);
    dateInput.addEventListener('change', loadSlots);
});

Бронирование слота при оформлении заказа

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale', 'OnSaleOrderSaved',
    function (\Bitrix\Main\Event $event) {
        $order = $event->getParameter('ENTITY');
        if (!$order->isNew()) {
            return;
        }

        $slotIdProp = $order->getPropertyCollection()
            ->getItemByOrderPropertyCode('PICKUP_SLOT_ID');
        $slotId = $slotIdProp ? (int)$slotIdProp->getValue() : 0;

        if (!$slotId) {
            return;
        }

        // Атомарное увеличение BOOKED с проверкой CAPACITY
        $connection = \Bitrix\Main\Application::getConnection();
        $affected = $connection->queryExecute("
            UPDATE b_pickup_slot
            SET BOOKED = BOOKED + 1
            WHERE ID = ? AND BOOKED < CAPACITY
        ", [$slotId]);

        if ($connection->getAffectedRowsCount() === 0) {
            // Слот переполнен — уведомляем менеджера
            // В production нужно вернуть ошибку до сохранения заказа
        }
    }
);

При отмене заказа — декрементируем BOOKED:

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale', 'OnSaleOrderCanceled',
    function (\Bitrix\Main\Event $event) {
        $order = $event->getParameter('ENTITY');
        $slotIdProp = $order->getPropertyCollection()
            ->getItemByOrderPropertyCode('PICKUP_SLOT_ID');
        $slotId = $slotIdProp ? (int)$slotIdProp->getValue() : 0;

        if ($slotId) {
            $connection = \Bitrix\Main\Application::getConnection();
            $connection->queryExecute(
                "UPDATE b_pickup_slot SET BOOKED = GREATEST(0, BOOKED - 1) WHERE ID = ?",
                [$slotId]
            );
        }
    }
);

Сроки настройки

Таблица слотов, агент генерации расписания, AJAX-эндпоинт, JS-компонент выбора, сохранение в свойства заказа с атомарным бронированием — 2–3 рабочих дня.