Процесс проверки гостей

В этом руководстве описано, как использовать список проживающих гостей в captive-портале: как сопоставлять введённые гостем данные со списком, когда должна завершаться сессия Wi-Fi, как часто обновлять список и какие поля сохранять для записей по закону № 5651.

Что запрашивать на портале#

Поскольку список содержит одновременно номер и личные данные, чаще всего используется форма номер комнаты + фамилия. Одного номера комнаты недостаточно: войти смог бы любой, кто знает номер соседней комнаты. Альтернативы — номер комнаты + номер удостоверения личности или паспорта либо фамилия + дата рождения; последний вариант оставьте запасным для гостей, у которых не заполнен номер документа.

Правила сопоставления#

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

  • Номер комнаты: обрежьте пробелы и переведите в верхний регистр. roomName — строка (например, "104", "A-12" или "Villa 3"); не преобразуйте его в число и не отбрасывайте ведущие нули.
  • Фамилия: переведите в верхний регистр (учитывайте турецкое соответствие i → İ) и замените повторяющиеся пробелы одним. Значения в списке обычно считываются с удостоверения личности в верхнем регистре.
  • Номер документа: удалите пробелы и переведите в верхний регистр. Турецкий национальный идентификационный номер состоит из 11 цифр; номер паспорта содержит буквы и цифры.
  • Дата рождения: в списке она в формате DD.MM.YYYY; если ваша форма принимает другой формат, преобразуйте её.
Сопоставление
const norm = (s) => String(s ?? "")
  .replace(/\s+/g, " ")
  .trim()
  .toLocaleUpperCase("tr-TR");

function findGuest(list, room, lastName) {
  return list.find((g) =>
    norm(g.roomName) === norm(room) && norm(g.lastName) === norm(lastName)
  ) || null;
}

const guest = findGuest(data.otelde, form.room, form.lastName);
if (!guest) {
  // «Номер комнаты и фамилия не совпадают» — считайте неудачные попытки, после 5 ограничьте частоту
}

Значение unique найденной записи — это идентификатор пользователя хотспота. Когда тот же гость входит со второго устройства, используйте учётную запись, привязанную к этому значению, а не создавайте новую, и применяйте к ней ограничение на число устройств.

Длительность сессии#

checkout — плановая дата выезда, указывающая на 00:00 (UTC) этого дня; времени суток в ней нет. Если открыть сессию до этого момента, гость потеряет доступ утром в день отъезда. Вычисляйте окончание сессии, прибавляя к дате расчётный час отеля:

Окончание сессии
const CHECKOUT_TIME = "12:00";                       // расчётный час отеля
const day = new Date(guest.checkout * 1000)
  .toLocaleDateString("en-CA", { timeZone: "UTC" });   // "2026-09-10"
const sessionEnd = new Date(`${day}T${CHECKOUT_TIME}:00+03:00`);

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

Периодическая синхронизация#

Список — это снимок текущего состояния; уведомлений об изменениях (webhook) нет. Запрашивайте список с фиксированным интервалом и сравнивайте его с предыдущим по unique:

  • Интервал: для большинства отелей достаточно 5 минут. Если гости должны получать доступ к сети сразу после заезда, интервал можно сократить до 1–2 минут, но не меньше 1 минуты.
  • Новый unique: подготовьте учётную запись; гость будет сопоставлен при первом входе на портал.
  • Пропавший unique: гость выехал или бронирование отменено. Завершите сессию и закройте учётную запись.
  • Тот же unique, другой roomName или checkout: переселение или продление. Обновите учётную запись.
  • Неудачный запрос: при тайм-ауте, 401 или 5xx сохраняйте последний успешно полученный список; никогда не закрывайте учётные записи по ответу с ошибкой.
Цикл синхронизации
async function sync(prev) {
  const res = await fetch(BASE + "/public/json/customer/inhotel", {
    method: "POST",
    headers: { "ApiKey": process.env.HMS_API_KEY, "HotelCode": HOTEL_CODE }
  });
  if (!res.ok) return prev;                                   // 401 / 5xx: оставляем старый список
  const { success, otelde } = await res.json();
  if (success !== 1) return prev;

  const next = new Map(otelde.map((g) => [g.unique, g]));
  for (const [id] of prev) {
    if (!next.has(id)) await closeAccount(id);                // выехал
  }
  for (const [id, g] of next) {
    const old = prev.get(id);
    if (!old) await openAccount(g);                           // новый гость
    else if (old.checkout !== g.checkout || old.roomName !== g.roomName) await updateAccount(g);
  }
  return next;
}

Несколько гостей в одном номере#

Каждый гость в номере — отдельная запись: rezervasyon_id у них общий, а unique разный. Открывайте учётные записи по гостям, а не по номерам, чтобы у каждого гостя были свои устройства, сессия и запись по закону № 5651. Запрос по номеру комнаты и фамилии может вернуть несколько записей для гостей с одинаковой фамилией (семьи); вместо того чтобы брать первое совпадение, уточняйте по имени или дате рождения либо откройте для них общую учётную запись.

Записи по закону № 5651#

Обязанность вести журналы доступа по закону № 5651 лежит на системе хотспота; HMS лишь предоставляет личные данные. При открытии сессии сохраняйте вместе с MAC/IP-адресом и временем следующие поля: unique, rezervasyon_id, firstName, lastName, identityNumber, birthDate, roomName, checkin, checkout. Когда гость исчезает из списка, HMS больше не предоставляет эти данные, поэтому храните записи на своей стороне.

Последнее обновление:: 21 сентября 2026 г.Нашли ошибку? Напишите нам