Розробка системи запису на послуги на 1С-Бітрікс
Стандартний модуль «Інтернет-магазин» Бітрікс заточений під товари з негайною оплатою, а не під послуги з часовими слотами. Спроба записати клієнта на стрижку, консультацію або заняття, використовуючи лише стандартний функціонал кошика та замовлень — призводить до нагромадження милиць: товар з нульовим залишком = «зайнято», XML-поле = «час», листи замість реального розкладу. Повноцінна система запису вимагає окремої архітектури.
Модель даних: розклад і слоти
Ядро системи — інфоблок розкладу. Оптимальна структура:
Інфоблок «Послуги» (SERVICES_IBLOCK_ID):
- Стандартні поля: NAME, PREVIEW_TEXT, DETAIL_TEXT
- Властивості:
DURATION(тривалість у хвилинах),PRICE,MAX_CAPACITY(групові заняття),SPECIALIST_ID(прив'язка до спеціаліста)
Інфоблок «Розклад» (SCHEDULE_IBLOCK_ID):
-
SERVICE_ID— прив'язка до послуги -
SPECIALIST_ID— виконавець -
DATE_FROM,DATE_TO— початок і кінець слоту (властивості типу «Дата/час») -
STATUS—free/booked/blocked -
BOOKING_ID— ID запису (після бронювання)
Таблиця бронювань (кастомна або через highload-блок):
CREATE TABLE bookings (
ID INT AUTO_INCREMENT PRIMARY KEY,
SLOT_ID INT NOT NULL, -- ID елемента розкладу
USER_ID INT, -- ID користувача (NULL для незареєстрованих)
CLIENT_NAME VARCHAR(255),
CLIENT_PHONE VARCHAR(20),
CLIENT_EMAIL VARCHAR(255),
STATUS ENUM('pending','confirmed','cancelled','completed') DEFAULT 'pending',
COMMENT TEXT,
CREATED_AT DATETIME,
UPDATED_AT DATETIME,
INDEX (SLOT_ID),
INDEX (STATUS)
);
Генерація слотів розкладу
Слоти генеруються на основі шаблонів робочого часу. Підхід: зберігати шаблони тижневого розкладу спеціаліста і автоматично створювати слоти на N тижнів уперед.
class SlotGenerator
{
public function generateForSpecialist(int $specialistId, \DateTime $from, \DateTime $to): void
{
$schedule = $this->getWeeklySchedule($specialistId); // [0=>[], 1=>['09:00','13:00',...]]
$serviceDuration = $this->getServiceDuration($specialistId); // хвилини
$current = clone $from;
while ($current <= $to) {
$dayOfWeek = (int)$current->format('N'); // 1=пн, 7=нд
$daySlots = $schedule[$dayOfWeek] ?? [];
foreach ($daySlots as $timeRange) {
[$start, $end] = explode('-', $timeRange); // '09:00-13:00'
$this->createSlotsBetween($specialistId, $current, $start, $end, $serviceDuration);
}
$current->modify('+1 day');
}
}
}
Слоти створюються як елементи інфоблоку зі статусом free. При бронюванні — статус змінюється на booked, при скасуванні — назад на free.
Віджет вибору часу: логіка на фронті
Користувач обирає послугу → спеціаліста → дату → час. Кожен крок — AJAX-запит до кастомного контролера:
// /local/ajax/booking.php
class BookingController extends \CBitrixComponent
{
public function getAvailableSlots(int $specialistId, string $date): array
{
$dateFrom = new \Bitrix\Main\Type\DateTime($date . ' 00:00:00');
$dateTo = new \Bitrix\Main\Type\DateTime($date . ' 23:59:59');
$result = \Bitrix\Iblock\ElementTable::getList([
'filter' => [
'IBLOCK_ID' => SCHEDULE_IBLOCK_ID,
'=PROPERTY_SPECIALIST_ID' => $specialistId,
'>=PROPERTY_DATE_FROM' => $dateFrom,
'<=PROPERTY_DATE_FROM' => $dateTo,
'=PROPERTY_STATUS' => 'free',
'=ACTIVE' => 'Y',
],
'select' => ['ID', 'PROPERTY_DATE_FROM', 'PROPERTY_DATE_TO'],
'order' => ['PROPERTY_DATE_FROM' => 'ASC'],
]);
// ...
}
}
На фронті — календар (наприклад, FullCalendar або кастомний на React) з підсвічуванням доступних днів і часових слотів.
Обробка гонки умов при бронюванні
Якщо два користувачі одночасно обрали один слот, потрібно гарантувати, що лише один отримає бронювання. Рішення через оптимістичне блокування на рівні БД:
public function bookSlot(int $slotId, array $clientData): BookingResult
{
// Транзакція + блокування рядка
$connection = \Bitrix\Main\Application::getConnection();
$connection->startTransaction();
try {
// SELECT FOR UPDATE — блокуємо рядок
$slot = $connection->query(
"SELECT * FROM b_iblock_element_property
WHERE IBLOCK_ELEMENT_ID = {$slotId} AND IBLOCK_PROPERTY_ID = " . STATUS_PROP_ID . "
FOR UPDATE"
)->fetch();
if ($slot['VALUE'] !== 'free') {
$connection->rollbackTransaction();
return BookingResult::slotTaken();
}
// Оновлюємо статус слоту
$this->updateSlotStatus($slotId, 'booked');
// Створюємо бронювання
$bookingId = $this->createBooking($slotId, $clientData);
$connection->commitTransaction();
return BookingResult::success($bookingId);
} catch (\Exception $e) {
$connection->rollbackTransaction();
throw $e;
}
}
Сповіщення та нагадування
Після бронювання — негайне сповіщення клієнту та спеціалісту. За 24 години та за 2 години — нагадування. Реалізація через агенти Бітрікс:
// Створюємо агент-нагадування при бронюванні
\CAgent::AddAgent(
'\BookingModule\ReminderAgent::send(' . $bookingId . ');',
'my_booking_module',
'N', // не періодичний
0,
'',
'Y',
ConvertTimeStamp($bookingDateTs - 86400, 'FULL') // за 24 години
);
Канал сповіщень: email (через модуль main), SMS (через зовнішній шлюз), Telegram-бот. Шаблони сповіщень — через стандартні поштові події Бітрікс (CEvent::Send).
Інтеграція з оплатою
Якщо запис вимагає передоплати — створюємо замовлення в інтернет-магазині Бітрікс:
$order = \Bitrix\Sale\Order::create(SITE_ID, $userId);
$order->setPersonTypeId(1);
$basket = $order->getBasket();
$item = \Bitrix\Sale\BasketItem::create($basket, 'catalog', $serviceElementId);
$item->setFields(['QUANTITY' => 1, 'PRICE' => $servicePrice, 'NAME' => $serviceName]);
$basket->addItem($item);
$order->save();
// Перенаправляємо на сторінку оплати
Зв'язок бронювання із замовленням зберігається в таблиці через поле ORDER_ID. При оплаті замовлення — вебхук або обробник події OnSaleOrderPaid підтверджує бронювання.
Адміністративний інтерфейс
Для адміністраторів і спеціалістів — сторінка в розділі /bitrix/admin/ з:
- Переглядом усіх бронювань на дату (calendar view)
- Можливістю блокувати слоти (відпустка, обід)
- Ручним підтвердженням/скасуванням із надсиланням сповіщення клієнту
- Вивантаженням у CSV за період
Етапи розробки
| Етап | Зміст | Термін |
|---|---|---|
| Проектування | Модель даних, сценарії використання | 3–5 днів |
| Інфоблоки та генератор слотів | Створення структури, генерація розкладу | 1 тиждень |
| AJAX-контролери | API вибору слоту, бронювання | 1 тиждень |
| Фронтенд-віджет | Календар, вибір спеціаліста і часу | 1–2 тижні |
| Сповіщення | Email, SMS, нагадування через агенти | 3–5 днів |
| Адміністративний інтерфейс | Управління розкладом, перегляд бронювань | 1 тиждень |
| Інтеграція з оплатою (опціонально) | Передоплата через замовлення | 1 тиждень |
Загалом: 6–10 тижнів залежно від набору функцій.







