DEV Community

Kayabyte
Kayabyte

Posted on

Room types, not rooms: how a small B&B booking engine avoids double bookings

Full disclosure up front: I build Wix apps, and Stay Direct, the booking app this post is based on, is mine. The booking logic below works the same on any platform.

The difference between a cabin and a B&B

A holiday cabin is one unit: it is either free on a night or it isn't. A small B&B or guesthouse sells room types instead: "Double room with garden view, 4 rooms". Guests don't pick room 3, they pick the type, and the owner wants the calendar to keep selling until every room of that type is taken.

That sounds like a simple counter, but one rule makes it harder: a guest keeps the same room for the whole stay. Nobody wants to move rooms on night three.

What you can use before building anything

If you are on Wix, check the built-in routes first. Wix Hotels by HotelRunner is Wix's own hotel app; it handles room types and comes with a channel manager, which suits a hotel that already works that way. Wix Bookings is made for appointments and classes, so nightly stays across several rooms don't map onto it well. And plenty of small places simply link a "Book now" button to their Airbnb or Booking.com page, which costs nothing but keeps paying the commission.

What follows is for the case in between: a few rooms, direct bookings on your own site, and calendars that stay in sync with the big platforms.

Free rooms, not free nights

So the check is not "is there one free room each night" but "is there one room that is free on every night of the stay":

// blocks: bookings, holds and imported calendar blocks; unit = room number, or none for "all rooms"
function freeRooms(checkIn, checkOut, blocks, rooms) {
  const overlapping = blocks.filter((b) => b.start < checkOut && checkIn < b.end);
  const free = [];
  for (let room = 1; room <= rooms; room++) {
    const taken = overlapping.some((b) => b.unit == null || b.unit === room);
    if (!taken) free.push(room);
  }
  return free;
}
Enter fullscreen mode Exit fullscreen mode

A request for two rooms needs two entries in that list. And there is a third answer besides yes and no: every night has a free room, but never the same one for the whole stay. Telling the guest exactly that ("try different dates or two shorter stays") is better than a plain "unavailable".

Calendars per room

Most small places also list on Airbnb or Booking.com, which sync through iCal links. With room types, each physical room needs its own export link and its own imported calendars, because Booking.com may sell room 2 while Airbnb sells room 4. An imported block takes one room; a block the owner adds by hand ("closed for painting") can take all of them.

Rate options

B&Bs rarely have one price. The usual set is a standard rate, a cheaper non-refundable rate and a rate with breakfast. Modelling them as options on top of the nightly price keeps it simple: a percentage up or down per night, an optional amount per guest per night (breakfast), and its own deposit rule (a non-refundable rate is often paid in full at booking).

Keeping old bookings safe

The tricky part of adding rooms to an existing booking engine is the data that was there before. Old bookings have no room number. The safe default is "room 1": for a property with one room nothing changes, and when an owner later raises the room count, old bookings keep occupying exactly one room.

Summary

For multi-room properties: book room types, assign a concrete room for the whole stay, explain the "same room" case clearly, keep one calendar link per room, and treat old bookings as room 1.

If you run a B&B, guesthouse or holiday rental on Wix, Stay Direct does this on your own site, with iCal sync to Airbnb, Booking.com and Vrbo and deposits through your checkout, and a free plan for one property (online payments need a Wix Premium plan and a connected payment provider). It only works on Wix sites, and it syncs booked dates, not prices.

Stay Direct on the App Market: https://www.wix.com/app-market/6de5633d-3a41-473c-a642-20b4ba638d1d

Top comments (0)