Онлайн-продажа автобусных билетов на WordPress и WooCommerce: кейс ТТК «Глобус»

Разработка сайта с онлайн бронированием и продажей билетов для транспортной компании перевозчика
Поделиться:

Для пассажирского перевозчика ТТК «Глобус» мы создали сайт с полным циклом онлайн-продажи билетов. Пассажир выбирает рейс и конкретное место в салоне, оформляет поездку сразу на нескольких человек, оплачивает заказ и автоматически получает PDF-билет. Диспетчер управляет рейсами и заказами в привычной панели WordPress.

Стандартный сценарий WooCommerce был превращён в билетную систему: с бронированием мест в реальном времени, защитой от двойных продаж, устойчивым оформлением заказа, оплатой через ЮKassa и автоматической выдачей PDF-билетов. Когда нумерованные места заканчиваются, система может продолжить продажу билетов со свободной рассадкой.

Интерфейс сайта ТТК «Глобус» для поиска рейса и покупки автобусного билета
Онлайн-покупка билета — от поиска рейса до получения документа после оплаты.

Задача проекта

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

Нужно было сохранить преимущества WordPress и WooCommerce — понятную админку, управление контентом и стандартные операции с заказами — но заменить обычную товарную модель на доменную логику пассажирского перевозчика. Тема и пользовательские сценарии были разработаны с нуля под проект, без переделки готового шаблона.

Ключевая задача состояла не в том, чтобы просто добавить кнопку оплаты, а в том, чтобы синхронизировать расписание, места, временные брони, пассажиров, дополнительные услуги, платежи, возвраты и работу диспетчера в одной системе.

Что должна была учитывать система

Конкретные места

Каждое место относится к определённому рейсу и салону. Его статус должен меняться сразу после выбора, оплаты, отмены или истечения срока брони.

Ограниченная бронь

Место нельзя удерживать бесконечно. Но его нельзя освободить и в тот момент, когда клиент уже перешёл на страницу платёжной системы и завершает оплату.

Составной заказ

В одном заказе могут находиться несколько пассажиров, разные тарифы, багаж, перевозка животного и дополнительные опции с отдельными правилами возврата.

Обычных товарных остатков WooCommerce для такой модели недостаточно. Поэтому критичная логика рейсов и мест была отделена от стандартного каталога и реализована через собственные сущности, таблицы базы данных и API.

Что получил бизнес

Продажу конкретных мест

Пассажир видит схему салона и выбирает место так же, как при покупке билета в кинотеатр или на самолёт. Состояние мест обновляется без перезагрузки страницы.

Продолжение продаж после заполнения салона

Когда все нумерованные места заняты, продажа не блокируется. Если правила рейса это допускают, система переключает оформление на свободную рассадку и продолжает принимать заказы.

Выбор и бронирование конкретного места на схеме салона автобуса
Выбранное место резервируется сразу после действия пассажира.

Защиту от двойных продаж

Система временно удерживает место на период оформления и отдельно учитывает время, когда покупатель находится во внешнем платёжном шлюзе. Незавершённая бронь освобождается автоматически.

Если подтверждение оплаты приходит слишком поздно, а место уже занято другим пассажиром, система не оставляет спорную покупку без обработки: она инициирует возврат через API ЮKassa и уведомляет клиента.

Оформление, устойчивое к сбоям

Состояние заказа хранится на сервере, поэтому разрыв соединения или проблема при переходе к оплате не заставляет покупателя начинать заново. Он возвращается к тому же заказу с ранее введёнными данными и выбранными местами, если срок брони ещё не истёк.

Экран подтверждения покупки билета в мобильной версии сайта
Бронь сохраняется на время оформления и ожидания ответа платёжной системы.

Автоматическую выдачу билетов

После оплаты пассажир получает PDF-билет по электронной почте. При отмене формируется обновлённый документ со статусом «Аннулирован». Повторная генерация не создаёт дубликаты.

Гибкую работу с дополнительными услугами

К заказу можно добавить багаж, перевозку животного и платный выбор места, а для ребёнка применить отдельный тариф. Каждая опция отражается отдельной строкой и может обрабатываться независимо.

Бесплатный багаж и бесплатный выбор места тоже остаются видимыми в составе заказа, но имеют нулевую стоимость. Диспетчер понимает, что именно выбрал клиент, и может вернуть конкретную опцию, не отменяя весь билет. Процентная скидка уменьшает цену билета без искусственной дополнительной строки в заказе.

Диспетчерскую и аналитику в реальном времени

Для сотрудников создана роль «Диспетчер» с доступом только к операционным разделам: маршрутам, рейсам, остановкам, заказам, отзывам и опциям. В админке видны свободные, забронированные и проданные места; данные обновляются автоматически.

  • диспетчер может оформить бронь за наличный расчёт по обращению клиента;
  • статусы названы понятными терминами «Бронь» и «Оплачен»;
  • после завершения рейс автоматически переводится в статус «Прошедший»;
  • отзывы модерируются через стандартные комментарии WordPress;
  • этапы воронки передаются в Яндекс.Метрику.
Панель диспетчера WordPress со статусами рейса, броней и проданных мест
Операционная панель показывает актуальное состояние рейса без ручного обновления страницы.

Как устроена продажа билета

  1. Пассажир выбирает маршрут и подходящий рейс.
  2. Система показывает актуальную схему салона.
  3. При выборе место временно закрепляется за текущим покупателем.
  4. В одном заказе заполняются данные нескольких пассажиров и выбираются дополнительные услуги.
  5. На время перехода в ЮKassa бронь получает отдельный срок ожидания оплаты.
  6. После подтверждения платежа заказ получает статус «Оплачен», а пассажиру отправляется PDF-билет.
  7. Если покупка не завершена, фоновая задача освобождает место и возвращает его в продажу.

Почему состояние мест хранится отдельно: собственные таблицы базы данных и кастомный REST API отделяют критичную логику бронирования от обычных товарных остатков WooCommerce. Это позволяет контролировать конкурентные действия покупателей и не зависеть от ограничений стандартной товарной модели.

Ключевые технические решения

Риск или задачаКак решено
Два клиента выбирают одно местоМесто резервируется на сервере, а актуальное состояние передаётся всем активным интерфейсам
Бронь истекает во время оплатыДля внешнего платёжного шлюза действует отдельный срок ожидания
Платёж подтверждён слишком поздноСистема проверяет место и при конфликте инициирует возврат через API ЮKassa
Клиент потерял соединениеСостояние оформления хранится на сервере и восстанавливается при возвращении
Зависшие брони занимают местаФоновая задача автоматически освобождает просроченные брони
Повторное уведомление от платёжной системыОперации защищены от повторного выполнения и не создают дубли билетов

Серверное состояние и отдельный срок ожидания оплаты

Оформление не зависит только от данных в браузере. Сервер хранит выбранный рейс, места и введённые данные, а для внешней оплаты действует отдельный TTL. Поэтому плановая очистка просроченных броней не освобождает место посреди нормального платёжного сценария.

Реальное время без конфликтов интерфейса

На клиентской стороне схема салона сразу реагирует на выбор места и перерисовывается, если место занял другой покупатель. В панели перевозчика WordPress Heartbeat API доставляет свежие данные о рейсе. Входящее обновление не перезаписывает действие, которое диспетчер выполняет в этот момент.

Автоматическое восстановление после спорных ситуаций

Фоновые задачи очищают зависшие брони без участия сотрудника. Операции обработки платежей защищены от повторного выполнения: запоздалые и повторные уведомления не создают дубли билетов и не меняют состояние заказа несколько раз.

Задачи по расписанию через WP-Cron

Для регулярных фоновых операций задействован планировщик WordPress WP-Cron. Он запускает очистку просроченных броней и автоматически переводит завершённые рейсы в статус «Прошедший». Операционные данные остаются актуальными без ручного контроля со стороны диспетчера.

Письма и документы для реальной эксплуатации

Служебные письма о билетах направляются на основной адрес перевозчика с резервным получателем. При массовой отмене создаётся одно сводное письмо вместо множества отдельных сообщений. PDF формируется через mPDF с корректной поддержкой кириллицы.

Производительный фронтенд

Для главной страницы подготовлены отдельные версии фонового видео. На мобильных устройствах загружается облегчённый файл, а при медленном соединении, экономии трафика или настройке prefers-reduced-motion видео заменяется статичным изображением WebP или AVIF.

Поиск рейсов обращается к закэшированному индексу маршрутов, который обновляется при изменении расписания. Это сокращает количество повторных вычислений и ускоряет выдачу подходящих рейсов.

Карты остановок в WordPress

Для SCF создан тип поля yandex-map. API карт загружается отложенно, когда поле действительно требуется, а функция the_yandex_map() выводит сохранённую точку на сайте.

На странице рейса карты отправления и прибытия показываются раздельно рядом с описаниями соответствующих остановок. Контент-менеджер при этом работает с координатами в обычной карточке остановки и не редактирует код.

Оформление билета онлайн на сайте транспортной компании с выбором рейса и места
Пассажир получает билет и видит точную точку посадки и высадки.

Стек проекта

СлойТехнологии
ПлатформаWordPress 6.7, WooCommerce, SCF и ACF-совместимые поля, CPT маршрутов, рейсов и остановок, стандартные комментарии WordPress для модерации отзывов
БэкендPHP, кастомный REST API, собственные таблицы БД для состояния мест, WP-Cron для фоновых задач
ФронтендVue 3, Webpack на базе @wordpress/scripts, SCSS по БЭМ
ИнтерактивWordPress Heartbeat API, GSAP, Swiper, Vivus
ОплатаЮKassa
ДокументыmPDF с поддержкой кириллицы
КартыПлагин jb-scf-yandex-map (justbusibness разработка) и поле yandex-map для SCF

Итог

Получилась не просто тема для WooCommerce, а специализированная билетная платформа на базе WordPress. Она объединяет выбор мест, конкурентное бронирование, устойчивое оформление, оплату, возвраты, документы, дополнительные услуги и операционную работу диспетчера.

Для пассажира

  • понятный выбор рейса и места;
  • оформление нескольких пассажиров;
  • онлайн-оплата;
  • автоматический PDF-билет;
  • восстановление незавершённого оформления.

Для диспетчера

  • актуальная схема заполнения рейса;
  • ручная бронь по телефону;
  • понятные статусы;
  • управление дополнительными услугами;
  • привычная админка WordPress.

Для бизнеса

  • автоматизация продаж;
  • снижение риска конфликтов по местам;
  • контроль возвратов и документов;
  • аналитика этапов оформления;
  • единая система для сайта и операций.

Критичные процессы — срок жизни брони, защита от двойной продажи, обработка запоздалой оплаты, очистка броней и перевод завершённых рейсов в статус «Прошедший» — автоматизированы. При этом сотрудникам не требуется осваивать отдельную корпоративную систему: они работают в адаптированной панели WordPress с привычными для перевозчика сущностями и статусами.

Частые вопросы

Можно ли использовать WooCommerce для продажи автобусных билетов?

Да, но стандартных товаров, вариаций и остатков недостаточно для полноценной билетной системы. WooCommerce удобно оставить как основу для заказов, платежей, возвратов и уведомлений, а рейсы, места, временные брони и правила рассадки реализовать отдельно. В этом проекте критичная логика работает через собственные таблицы базы данных, REST API и интерфейс на Vue.

Как система предотвращает продажу одного места двум пассажирам?

Место закрепляется за покупателем сразу после выбора и получает временный статус брони на сервере. Другие пользователи видят обновлённое состояние салона и не могут оформить это же место. Если бронь не оплачена вовремя, она автоматически освобождается. Перед окончательным подтверждением заказа система повторно проверяет доступность места.

Что происходит, если клиент прервал оплату или потерял соединение?

Выбранный рейс, места и введённые данные сохраняются на сервере. Если срок брони ещё действует, клиент может вернуться к оформлению и продолжить покупку без повторного заполнения. Для перехода во внешний платёжный шлюз предусмотрен отдельный срок ожидания, поэтому место не освобождается во время нормального процесса оплаты.

Что будет, если оплата подтвердится после истечения брони?

Система проверяет состояние места в момент получения подтверждения от ЮKassa. Если место всё ещё доступно, заказ завершается обычным образом. Если его уже занял другой пассажир, система инициирует возврат через API платёжного сервиса и отправляет клиенту уведомление. Это исключает ситуацию, когда два оплаченных билета выпущены на одно место.

Можно ли оформить билет сразу на нескольких пассажиров?

Да. Один заказ может включать нескольких пассажиров. Для каждого сохраняются персональные данные, место и применяемый тариф. В рамках того же оформления можно добавить багаж, перевозку животного и другие доступные услуги. В итоговом заказе и PDF-билете информация остаётся структурированной и понятной.

Что происходит после заполнения всех нумерованных мест?

Если правила конкретного рейса допускают свободную рассадку, система не закрывает продажи. Схема салона перестаёт предлагать номера мест, а новые билеты оформляются без закреплённого места. Этот режим корректно отображается в заказе, панели диспетчера и PDF-билете, поэтому пассажир заранее понимает условия посадки.

Может ли диспетчер оформить бронь вручную?

Да. Сотрудник с ролью «Диспетчер» может создать бронь по обращению клиента, например при заказе по телефону или оплате наличными. Ему доступны только необходимые операционные разделы, поэтому он не получает лишний доступ к системным настройкам WordPress.

Можно ли вернуть только багаж или другую дополнительную услугу?

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

Как обновляются статусы рейсов и модерируются отзывы?

WP-Cron запускает фоновые задачи по расписанию: освобождает просроченные брони и автоматически переводит завершённые рейсы в статус «Прошедший». Отзывы реализованы через стандартные комментарии WordPress, поэтому сотрудники проверяют, одобряют и публикуют их в привычном разделе админки.

Можно ли использовать такую архитектуру для других систем бронирования?

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


Нужен сайт с нестандартной логикой продаж?

Мы проектируем решения на WordPress и WooCommerce, когда стандартного интернет-магазина недостаточно: бронирование, сложные сценарии оформления, интеграции, документы, возвраты и специализированные роли сотрудников.

Посмотрите услугу разработки на WordPress, или расскажите о задаче — предложим подходящий формат реализации.

Поделиться: