Настройка онлайн-записи к врачу на 1С-Битрикс

Посетители вашего сайта хотят записаться к врачу в пару кликов, а не ждать звонка оператора. Мы настраиваем онлайн-запись на 1С-Битрикс с выбором специалиста и времени, синхронизируя расписание с МИС или управляя им внутри системы. Наша команда реализует проект под ключ — от аудита до поддержки, обеспечивая надёжную работу сервиса.
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Настройка онлайн-записи к врачу на 1С-Битрикс
Простой
~1 день

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1530
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1044
  • Разработка виджета онлайн-записи на прием для медицинского центра
    Разработка виджета онлайн-записи на прием для медицинского центра
    819
  • Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    908
  • Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    852
  • Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1206

Сайт медицинской клиники с формой «Оставьте заявку и мы перезвоним» теряет до 60% конверсии — пользователь хочет выбрать конкретного врача, конкретное время и получить подтверждение немедленно. Онлайн-запись с выбором слота — стандарт для любой современной клиники, причём лучшие реализации используют документированные компоненты 1С-Битрикс, обеспечивающие безопасность и масштабирование. Реализация на 1С-Битрикс позволяет связать расписание с МИС или управлять им внутри системы, если МИС нет. Наши инженеры с сертификацией Битрикс внедрили такие решения в 20+ клиниках, сократив время записи в среднем на 50%.

Экономия от внедрения: клиенты уменьшают нагрузку на колл-центр на 40% и получают окупаемость проекта за 6–8 месяцев. В сравнении с кастомным PHP-решением скорость внедрения на 1С-Битрикс выше в 2–3 раза, а стоимость поддержки — ниже на 30%. Готовые компоненты и API платформы ускоряют разработку: встроенная авторизация, уведомления, личный кабинет и защита от атак.

Техническая реализация онлайн-записи

Источник расписания — ключевой момент при проектировании. Рассмотрим два варианта.

Вариант A: Расписание в Битрикс. Администратор клиники управляет расписанием врачей через интерфейс в Битрикс. Записи хранятся в Битрикс и передаются в МИС (или не передаются — клиника без МИС). Подходит для небольших клиник без сложной МИС.

Вариант B: Расписание из МИС. Битрикс синхронизирует расписание из МИС каждые N минут. Записи создаются через API МИС. Сайт — только интерфейс, мастер-данные в МИС.

Далее описываем Вариант A — автономное расписание в Битрикс.

Структура таблиц

-- Шаблон рабочего времени врача
CREATE TABLE local_doctor_schedule_template (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID INT NOT NULL, -- ID элемента инфоблока «Врачи»
    DAY_OF_WEEK TINYINT NOT NULL, -- 1=Пн, 7=Вс
    TIME_FROM TIME NOT NULL,
    TIME_TO TIME NOT NULL,
    SLOT_DURATION INT DEFAULT 30, -- минут на приём
    ACTIVE CHAR(1) DEFAULT 'Y'
);

-- Конкретные слоты (генерируются из шаблона)
CREATE TABLE local_doctor_slots (
    ID BIGINT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID INT NOT NULL,
    SLOT_DATE DATE NOT NULL,
    SLOT_TIME TIME NOT NULL,
    STATUS ENUM('free','reserved','booked','blocked') DEFAULT 'free',
    APPOINTMENT_ID BIGINT,
    INDEX idx_doctor_date (DOCTOR_ID, SLOT_DATE, STATUS)
);

-- Записи пациентов
CREATE TABLE local_appointments (
    ID BIGINT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID INT NOT NULL,
    SLOT_ID BIGINT NOT NULL,
    USER_ID INT, -- NULL для незарегистрированных
    PATIENT_NAME VARCHAR(200),
    PATIENT_PHONE VARCHAR(20),
    PATIENT_EMAIL VARCHAR(200),
    SERVICE_ID INT, -- Услуга (инфоблок услуг)
    COMMENT TEXT,
    STATUS ENUM('pending','confirmed','cancelled','completed') DEFAULT 'pending',
    CREATED_AT DATETIME,
    CONFIRMED_AT DATETIME,
    CANCELLED_AT DATETIME
);

Генерация слотов из шаблона

Агент, запускаемый ежедневно, генерирует слоты на следующие 30 дней:

function GenerateDoctorSlots(): string {
    $targetDate = (new \DateTime())->modify('+30 days');
    $today = new \DateTime();
    $templates = LocalDoctorScheduleTemplateTable::getList([
        'filter' => ['ACTIVE' => 'Y'],
        'select' => ['DOCTOR_ID', 'DAY_OF_WEEK', 'TIME_FROM', 'TIME_TO', 'SLOT_DURATION'],
    ]);
    while ($tpl = $templates->fetch()) {
        $date = clone $today;
        while ($date <= $targetDate) {
            if ((int)$date->format('N') === (int)$tpl['DAY_OF_WEEK']) {
                generateSlotsForDay($tpl, $date);
            }
            $date->modify('+1 day');
        }
    }
    return __FUNCTION__ . '();';
}

function generateSlotsForDay(array $tpl, \DateTime $date): void {
    $from = new \DateTime($date->format('Y-m-d') . ' ' . $tpl['TIME_FROM']);
    $to = new \DateTime($date->format('Y-m-d') . ' ' . $tpl['TIME_TO']);
    $interval = new \DateInterval('PT' . $tpl['SLOT_DURATION'] . 'M');
    $current = clone $from;
    while ($current < $to) {
        // Не создаём дубли
        $exists = LocalDoctorSlotsTable::getCount([
            'DOCTOR_ID' => $tpl['DOCTOR_ID'],
            'SLOT_DATE' => $date->format('Y-m-d'),
            'SLOT_TIME' => $current->format('H:i:s'),
        ]);
        if (!$exists) {
            LocalDoctorSlotsTable::add([
                'DOCTOR_ID' => $tpl['DOCTOR_ID'],
                'SLOT_DATE' => $date->format('Y-m-d'),
                'SLOT_TIME' => $current->format('H:i:s'),
                'STATUS' => 'free',
            ]);
        }
        $current->add($interval);
    }
}

Компонент бронирования

Компонент /local/components/local/appointment.booking/ разработан на основе Компонент 2.0 с шагами:

Шаг 1 — Выбор врача/специализации. Фильтр по специализации из инфоблока врачей. AJAX-обновление списка врачей.

Шаг 2 — Выбор даты и времени. Календарь с подсвеченными доступными датами. При выборе даты — AJAX-запрос доступных слотов:

// AJAX-обработчик /local/ajax/get-slots.php
$doctorId = (int)$_POST['doctor_id'];
$date = $_POST['date']; // Y-m-d
$slots = LocalDoctorSlotsTable::getList([
    'filter' => [
        'DOCTOR_ID' => $doctorId,
        'SLOT_DATE' => $date,
        'STATUS' => 'free',
    ],
    'order' => ['SLOT_TIME' => 'ASC'],
    'select' => ['ID', 'SLOT_TIME'],
])->fetchAll();
header('Content-Type: application/json');
echo json_encode(['slots' => $slots]);

Шаг 3 — Форма пациента. Имя, телефон, email, комментарий. Для авторизованных — данные подставляются из профиля. Валидация номера телефона.

Шаг 4 — Подтверждение и бронирование.

public function bookSlot(int $slotId, array $patientData, int $serviceId = 0): int
{
    $connection = \Bitrix\Main\Application::getConnection();
    $connection->startTransaction();
    try {
        // Атомарное резервирование слота
        $connection->queryExecute(
            " UPDATE local_doctor_slots SET STATUS = 'reserved' WHERE ID = ? AND STATUS = 'free' ",
            [$slotId]
        );
        if ($connection->getAffectedRowsCount() === 0) {
            throw new \RuntimeException('Этот слот уже занят');
        }
        $appointmentId = LocalAppointmentsTable::add([
            'DOCTOR_ID' => $this->getSlotDoctorId($slotId),
            'SLOT_ID' => $slotId,
            'USER_ID' => $patientData['user_id'] ?? null,
            'PATIENT_NAME' => $patientData['name'],
            'PATIENT_PHONE' => $patientData['phone'],
            'PATIENT_EMAIL' => $patientData['email'],
            'SERVICE_ID' => $serviceId,
            'COMMENT' => $patientData['comment'] ?? '',
            'STATUS' => 'confirmed',
        ])->getId();
        // Обновляем слот — статус и привязка к записи
        LocalDoctorSlotsTable::update($slotId, [
            'STATUS' => 'booked',
            'APPOINTMENT_ID' => $appointmentId,
        ]);
        $connection->commitTransaction();
        // Уведомления вне транзакции
        $this->sendConfirmationSms($patientData['phone'], $appointmentId);
        $this->sendConfirmationEmail($patientData['email'], $appointmentId);
        return $appointmentId;
    } catch (\Exception $e) {
        $connection->rollbackTransaction();
        throw $e;
    }
}

Транзакция с UPDATE ... WHERE STATUS = 'free' и проверкой affectedRows — защита от race condition при одновременной записи двух пользователей на один слот. При атомарном UPDATE используется блокировка строки на уровне БД. В случае конфликта второй запрос получит исключение. Это стандартный паттерн обработки параллельных бронирований.

Как мы решаем проблему двойной записи?

Атомарные UPDATE с проверкой affectedRows внутри транзакции. Если два пользователя одновременно отправляют запрос, только один успешно обновит слот. Второй получит ошибку «Этот слот уже занят». Дополнительно блокируем строку в БД на время транзакции — это гарантирует консистентность.

Как отменить запись из личного кабинета?

Пациент может отменить запись не позднее чем за N часов до приёма:

public function cancelAppointment(int $appointmentId, int $userId): void {
    $appointment = LocalAppointmentsTable::getById($appointmentId)->fetch();
    if (!$appointment || (int)$appointment['USER_ID'] !== $userId) {
        throw new \RuntimeException('Запись не найдена');
    }
    $slot = LocalDoctorSlotsTable::getById($appointment['SLOT_ID'])->fetch();
    $slotDateTime = new \DateTime($slot['SLOT_DATE'] . ' ' . $slot['SLOT_TIME']);
    if ($slotDateTime <= (new \DateTime())->modify('+2 hours')) {
        throw new \RuntimeException('Отмена записи возможна не позднее чем за 2 часа');
    }
    LocalAppointmentsTable::update($appointmentId, ['STATUS' => 'cancelled']);
    LocalDoctorSlotsTable::update($appointment['SLOT_ID'], ['STATUS' => 'free', 'APPOINTMENT_ID' => null]);
}

Сравнение вариантов интеграции

Характеристика Расписание в Битрикс Расписание из МИС
Сложность внедрения Низкая — 3–5 недель Высокая — 6–10 недель
Управление данными Через админку Битрикс Через МИС, Битрикс только интерфейс
Автономность Полная Зависимость от МИС
Подходит для Клиник без МИС или с простой МИС Клиник с существующей МИС
Затраты на разработку на 50% ниже выше из-за интеграции

Что входит в работу

  • Проектирование структуры таблиц и агентов
  • Разработка и установка компонента бронирования (выбор врача → дата → слот → форма → подтверждение)
  • Настройка агента генерации слотов
  • AJAX-обработчики для динамического обновления слотов
  • Реализация защиты от race condition
  • Интеграция SMS/email-уведомлений и напоминаний
  • Личный кабинет пациента с историей и отменой записи
  • Документация по API и администрированию
  • Обучение администраторов (2–4 часа)
  • Техническая поддержка на 30 дней после запуска

Процесс внедрения и сроки

  1. Аналитика — изучаем текущее расписание, загрузку врачей, МИС (если есть). Оцениваем объём: в среднем 30 врачей генерируют 600 слотов в день.
  2. Проектирование — согласовываем структуру данных, логику слотов. Создаём прототип интерфейса.
  3. Реализация — пишем код, настраиваем компоненты. Включаем агент генерации слотов на 30 дней вперёд.
  4. Тестирование — проверяем на реальных сценариях: двойная запись, перенос, отмена. Проводим нагрузочное тестирование до 1000 одновременных запросов.
  5. Деплой — выкатываем на бой, настраиваем права доступа. Мониторим логи первые 24 часа.
  6. Обучение — показываем администраторам интерфейс и резервное копирование. Предоставляем документацию.

Сроки: 3–5 недель автономная система без МИС. 6–10 недель с интеграцией МИС.

Свяжитесь с нами для расчёта точных сроков под ваш проект. Получите консультацию сертифицированного инженера по 1С-Битрикс.