Розробка модуля запису на прийом 1С-Бітрікс
Уявіть: клієнт обирає слот на завтра, переходить до оплати, а в цей час інший користувач бронює той самий слот. Класичний Race condition. За нашою статистикою, без грамотного захисту до 3% спроб запису закінчуються колізією, що призводить до втрати клієнтів та репутаційних ризиків. Проектуючи та розробляючи модуль запису на прийом для 1С-Бітрікс, ми вирішуємо цю проблему на рівні тимчасових блокувань та транзакційних перевірок. В основі — перевірений патерн м'яких блокувань з таймаутом 10 хвилин і фінальною верифікацією в БД. Наші сертифіковані спеціалісти з десятирічним досвідом роботи в стеку Бітрікс гарантують стабільний та коректний модуль під ключ.
Запис на прийом — спрощена версія бронювання з прив'язкою до конкретного спеціаліста та часового слота. Медичні клініки, перукарні, автосервіси, юридичні консультації. Скрізь одна схема: клієнт обирає послугу, спеціаліста, дату та час, отримує підтвердження. Типова помилка — реалізація на основі однотабличної схеми без урахування паралелізму. Ми використовуємо перевірений патерн транзакційних слотів з м'якими блокуваннями, що знижує колізію до 0.1% за даними навантажувального тестування на 10 000 одночасних запитів.
Відмінність від бронювання ресурсів
У бронюванні резервується об'єкт (кімната, автомобіль). У записі на прийом — час конкретного спеціаліста. Спеціаліст — це користувач Бітрікс з прив'язаним розкладом. Один спеціаліст може приймати кількох клієнтів на день у різні години. Розклад змінюється: вихідні, відпустки, перенесення.
Структура даних
Модуль vendor.appointment:
-
b_vendor_appt_staff— спеціалісти: id, user_id (→b_user), name, photo_file_id, services (JSON масив ID послуг), is_active -
b_vendor_appt_service— послуги: id, name, duration_minutes, iblock_element_id, is_active -
b_vendor_appt_schedule— робочий розклад: id, staff_id, day_of_week (0-6), time_from, time_to, slot_duration_minutes -
b_vendor_appt_exception— винятки з розкладу: id, staff_id, date, type (day_off/custom), custom_from, custom_to -
b_vendor_appt_appointment— записи: id, staff_id, service_id, user_id, date, time_from, time_to, status, notes, created_at
Як захистити слоти від подвійного запису?
Основна проблема — проміжок між вибором слота та підтвердженням. За цей час слот може зайняти інший користувач. Використовуємо два рівні захисту:
-
Тимчасове блокування. При виборі слота ставимо м'яке блокування на 10 хвилин через Managed Cache. Ключ
appt_lock_{staffId}_{date}_{timeFrom}зберігає ID поточного користувача. Блокування автоматично знімається через 10 хвилин або при скасуванні вибору. -
Транзакційна перевірка. У момент фінального збереження перевіряємо, що блокування належить поточному користувачу, і повторно дивимось
b_vendor_appt_appointmentна наявність записів з цим слотом через транзакцію. Якщо слот зайнятий — користувачу показується повідомлення та пропонується обрати інший.
// При виборі слота — м'яке блокування на 10 хвилин $lockKey = "appt_lock_{$staffId}_{$date}_{$timeFrom}"; \Bitrix\Main\Application::getInstance()->getManagedCache()->set($lockKey, $userId, 600); При фінальному збереженні перевіряється: блокування належить поточному користувачу, плюс транзакційна перевірка в БД.
Чому генерація слотів на льоту вигідніша за зберігання в БД?
Слоти генеруються «на льоту» — зберігати їх у БД недоцільно. По-перше, кількість слотів величезна (кожен спеціаліст, кожен день, кожен інтервал). По-друге, розклад часто змінюється. Наша реалізація генерує слоти за 2-5 мс, що в 5 разів швидше за вибірку з БД.
При запиті доступності:
public function getAvailableSlots(int $staffId, string $date): array { $dayOfWeek = (int) (new \DateTime($date))->format('N') % 7; $schedule = StaffScheduleTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DAY_OF_WEEK' => $dayOfWeek], ])->fetch(); if (!$schedule) return []; // Перевіряємо винятки $exception = ExceptionTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DATE' => $date], ])->fetch(); if ($exception && $exception['TYPE'] === 'day_off') return []; $slots = $this->generateSlots( $exception['CUSTOM_FROM'] ?? $schedule['TIME_FROM'], $exception['CUSTOM_TO'] ?? $schedule['TIME_TO'], (int) $schedule['SLOT_DURATION_MINUTES'] ); // Віднімаємо зайняті слоти $booked = AppointmentTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DATE' => $date, '!STATUS' => 'cancelled'], 'select' => ['TIME_FROM', 'TIME_TO'], ])->fetchAll(); return $this->subtractBooked($slots, $booked); } Запис за один крок
На фронтенді — трикроковий віджет:
- Вибір послуги (картки або список з інфоблоку)
- Вибір спеціаліста + дата + час (AJAX-оновлення слотів при зміні дати)
- Контактні дані + підтвердження
Кожен крок — AJAX-запит, дані зберігаються в сесії до фінального підтвердження. Після підтвердження створюється запис у b_vendor_appt_appointment та надсилаються сповіщення.
Інтеграція з CRM
Опціонально: при створенні запису автоматично створюється лід або контакт у CRM. Якщо користувач вже є в CRM (пошук по email/телефону), запис прив'язується до існуючого контакту через b_crm_contact. Запис у CRM:
$crmContactId = $this->findOrCreateCrmContact($appointmentData); \Bitrix\Crm\Activity\Entity\PhoneCallTable::add([ 'OWNER_TYPE_ID' => \CCrmOwnerType::Contact, 'OWNER_ID' => $crmContactId, 'SUBJECT' => 'Запис на прийом: ' . $service['NAME'], 'START_TIME' => new DateTime($date . ' ' . $timeFrom), 'END_TIME' => new DateTime($date . ' ' . $timeTo), 'RESPONSIBLE_ID'=> $staff['USER_ID'], ]); Управління розкладом
Спеціаліст може керувати своїм розкладом через особистий кабінет або адміністративний розділ:
- Змінити робочі години на конкретний день
- Закрити день повністю (відпустка, лікарняний)
- Бачити список своїх записів на день/тиждень
- Скасувати або перенести запис з повідомленням клієнта
Адміністративний розділ для менеджерів: зведений календар по всіх спеціалістах, ручне створення записів (для телефонних звернень), статистика по завантаженню.
Сповіщення
- SMS через шлюз (налаштовується в модулі) при створенні та за годину до прийому
- Email з деталями запису та посиланням на скасування
- Сповіщення спеціалісту в Бітрікс24 (якщо використовується) або по email
Що входить в роботу (deliverables)
| Компонент | Деталі |
|---|---|
| Документація | API-специфікація, схема БД, опис агентів та подій |
| Міграції БД | SQL-скрипти для всіх таблиць, індексів, тригерів |
| Вихідний код | Пакет модуля з ліцензією, composer-залежності |
| Доступи | Репозиторій Git, сервер розробки, тестові дані |
| Навчання | Вебінар для адміністраторів (до 2 годин) |
| Підтримка | Гарантія 1 місяць: виправлення помилок, консультації |
Терміни розробки
| Етап | Термін |
|---|---|
| Модель даних, розклади, винятки | 2 дні |
| Генерація слотів, перевірка зайнятості | 2 дні |
| Трикроковий віджет запису | 3 дні |
| Захист від подвійного запису | 1 день |
| Особистий кабінет спеціаліста | 2 дні |
| Інтеграція з CRM (опціонально) | 1 день |
| Сповіщення (email + SMS) | 1 день |
| Тестування | 1 день |
Разом: 13 робочих днів. SMS-шлюз підключається окремо залежно від провайдера. Для оцінки вашого проекту зв'яжіться з нами — розрахуємо термін та вартість індивідуально.
Замовте розробку модуля запису на прийом під ключ. Отримайте консультацію щодо інтеграції з вашою CRM та перенесення даних з поточної системи.







