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

У цьому посібнику пояснено, як використовувати список гостей, які проживають у готелі, у 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 знайденого запису — це ідентифікатор користувача hotspot. Коли той самий гість входить із другого пристрою, використовуйте обліковий запис, прив’язаний до цього значення, а не створюйте новий, і застосовуйте обмеження кількості пристроїв до цього облікового запису.

Тривалість сеансу#

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 змінюється; порівнюйте це поле під час синхронізації й оновлюйте кінець сеансу. У разі пізнього виїзду безпечніше залишати доступ відкритим, доки гість є в списку.

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

Список — це знімок стану; сповіщень про зміни (вебхуків) немає. Отримуйте список із фіксованим інтервалом і порівнюйте його з попереднім за 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 покладено на систему hotspot; HMS лише надає ідентифікаційні дані. Коли відкривається сеанс, зберігайте разом з MAC/IP-адресою й міткою часу такі поля: unique, rezervasyon_id, firstName, lastName, identityNumber, birthDate, roomName, checkin, checkout. Щойно гість зникає зі списку, HMS більше не надає цих даних, тож зберігайте запис на своєму боці.

Останнє оновлення: 21 вересня 2026 р.Знайшли помилку? Повідомте нам