Налаштування вибору часу самовивозу 1С-Бітрікс
Покупець хоче приїхати у конкретний час — магазин хоче рівномірно розподілити потік. Без слотового самовивозу всі приїжджають в обід, створюючи чергу. Стандартна форма замовлення в 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)
);
Заповнення слотів на тиждень вперед — через агент 1С-Бітрікс, який генерує слоти за розкладом роботи кожної точки.
Отримання доступних слотів через 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 робочі дні.







