Easy booking availability checking with Breezbook

Mike HoganMike Hogan
6 min read

Here are some code samples to show what kind of availability checking is possible when attempting to make bookings or appointments using breezbook.

Request a booking with "any suitable resource"

Here is a code sample showing how to check availability for a booking that requires "any suitable resource", in this case, a room:

    const room = resourceType("room");
    const room1 = resource(room, 
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [], 
            resourceId("room1"));
    const room2 = resource(room, 
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [], 
            resourceId("room2"));

    const meetingService = service(
        resourceRequirements(
            [anySuitableResource(room)]));

    const requestedBooking = bookingSpec(meetingService);

    const requestedTimeSlots = [
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        timeslotFns.sameDay("2023-07-01", "11:00", "12:00"),
        timeslotFns.sameDay("2023-07-01", "13:00", "14:00"),
    ];

    const availability = listAvailability(
        [room1, room2],
        [],
        requestedBooking,
        requestedTimeSlots
    )

    availability.forEach((slot) => {
        const time = `${startTime(slot)} to ${endTime(slot)}`
        if (slot._type === "available") {
            console.log(`Slot ${time} is available`);
            console.log(`\tIt uses resource : ${(bookedResources(slot))}`);
            console.log(`\tThe potential capacity at this slot is ${slot.potentialCapacity.value}`)
            console.log(`\tThe consumed capacity at this slot is ${slot.consumedCapacity.value}`)
        } else {
            console.log(`Slot ${time} is unavailable`);
        }
    });

This declares a resourceType ("room") and creates two rooms - room1 and room2.

Then it creates a meetingService which requires anySuitable room.

requestedBooking and requestedTimeSlots are the means to express what service we want to check availability for, and what time slots we want to check against.

The listAvailability takes four params:

  1. available resources

  2. existing bookings

  3. the request booking spec

  4. the time slots we want to check availability against

The function returns whether the requested booking is possible at each slot. It also states how much potential capacity is at each slot, and how much capacity is used.

As there are no existing bookings in this example, all slots are available, and we get output like this:

Slot 10:00 to 11:00 is available
    It uses resource : room1
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0
Slot 11:00 to 12:00 is available
    It uses resource : room1
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0
Slot 13:00 to 14:00 is available
    It uses resource : room1
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0

What happens if there are existing bookings?

This code shows what happens if you have existing bookings. The code is very similar to the above, except this time we have two bookings in the 10:00 to 11:00 slot. As we have only two rooms, we would now expect this slot to be unavailable.

    const room = resourceType("room");
    const room1 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [],
        resourceId("room1"));
    const room2 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [],
        resourceId("room2"));

    const meetingService = service(
        resourceRequirements(
            [anySuitableResource(room)]));

    const requestedBooking = bookingSpec(meetingService);

    const requestedTimeSlots = [
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        timeslotFns.sameDay("2023-07-01", "11:00", "12:00"),
        timeslotFns.sameDay("2023-07-01", "13:00", "14:00"),
    ];

    const booking1 = booking(
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        meetingService);
    const booking2 = booking(
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        meetingService);

    const availability = listAvailability(
        [room1, room2],
        [booking1, booking2],
        requestedBooking,
        requestedTimeSlots
    )

    availability.forEach((slot) => {
        const time = `${startTime(slot)} to ${endTime(slot)}`
        if (slot._type === "available") {
            console.log(`Slot ${time} is available`);
            console.log(`\tIt uses resource : ${(bookedResources(slot))}`);
            console.log(`\tThe potential capacity at this slot is ${slot.potentialCapacity.value}`)
            console.log(`\tThe consumed capacity at this slot is ${slot.consumedCapacity.value}`)
        } else {
            console.log(`Slot ${time} is unavailable`);
        }
    });

And indeed we get the expected output:

Slot 10:00 to 11:00 is unavailable
Slot 11:00 to 12:00 is available
    It uses resource : room1
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0
Slot 13:00 to 14:00 is available
    It uses resource : room1
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0

Requesting a specific resource

There are cases where you want to override the resource allocation with a specific resource. For example, a user might want to book a personal training session with a specific personal trainer, rather than just get a random one.

This code shows the use of resourceCommitment in the requestedBooking to override the service stating that it requires anySuitableResource(room), in favour of using room2`:

    const room = resourceType("room");
    const room1 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [],
        resourceId("room1"));
    const room2 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [],
        resourceId("room2"));
    const anySuitableRoom = anySuitableResource(room);
    const meetingService = service(
        resourceRequirements([anySuitableRoom]));

    const requestedBooking = bookingSpec(meetingService,
        [resourceCommitment(anySuitableRoom, room2)]);

    const requestedTimeSlots = [
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        timeslotFns.sameDay("2023-07-01", "11:00", "12:00"),
        timeslotFns.sameDay("2023-07-01", "13:00", "14:00"),
    ];

    const availability = listAvailability(
        [room1, room2],
        [],
        requestedBooking,
        requestedTimeSlots
    )

    availability.forEach((slot) => {
        const time = `${startTime(slot)} to ${endTime(slot)}`
        if (slot._type === "available") {
            console.log(`Slot ${time} is available`);
            console.log(`\tIt uses resource : ${(bookedResources(slot))}`);
            console.log(`\tThe potential capacity at this slot is ${slot.potentialCapacity.value}`)
            console.log(`\tThe consumed capacity at this slot is ${slot.consumedCapacity.value}`)
        } else {
            console.log(`Slot ${time} is unavailable`);
        }
    });

And in the resulting output, you can see that all the slots end up using room2 everywhere:

Slot 10:00 to 11:00 is available
    It uses resource : room2
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0
Slot 11:00 to 12:00 is available
    It uses resource : room2
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0
Slot 13:00 to 14:00 is available
    It uses resource : room2
    The potential capacity at this slot is 2
    The consumed capacity at this slot is 0

Choosing resources based on attributes

This final piece of code shows how you can check availability against resources that have attributes - the typical meeting room resourcing case.

    const room = resourceType("room");
    const room1 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [
            {name: "capacity", value: 10},
            {name: "hasProjector", value: true}
        ], resourceId("room1"));
    const room2 = resource(room,
        [timeslotFns.sameDay("2023-07-01", "09:00", "17:00")], [
            {name: "capacity", value: 20},
            {name: "hasProjector", value: true}
        ], resourceId("room2"));

    const meetingRoomRequirement = complexResourceRequirement(room,
        [
            {name: "capacity", value: 15, operator: "greaterThan"},
            {name: "hasProjector", value: true, operator: "equals"}
        ]);

    const meetingService = service(
        resourceRequirements([meetingRoomRequirement]));
    const proposedBooking = bookingSpec(meetingService);

    const requestedTimeSlots = [
        timeslotFns.sameDay("2023-07-01", "10:00", "11:00"),
        timeslotFns.sameDay("2023-07-01", "11:00", "12:00"),
        timeslotFns.sameDay("2023-07-01", "13:00", "14:00"),
    ];

    const availability = listAvailability(
        [room1, room2],
        [],
        proposedBooking,
        requestedTimeSlots
    );

    availability.forEach((slot) => {
        const time = `${startTime(slot)} to ${endTime(slot)}`
        if (slot._type === "available") {
            console.log(`Slot ${time} is available`);
            console.log(`\tIt uses resource : ${(bookedResources(slot))}`);
            console.log(`\tThe potential capacity at this slot is ${slot.potentialCapacity.value}`)
            console.log(`\tThe consumed capacity at this slot is ${slot.consumedCapacity.value}`)
        } else {
            console.log(`Slot ${time} is unavailable`);
        }
    });

Here we assign attributes to the resources and express a need against these attributes using complexResourceRequirement. We have two rooms, both with a projector, but one has capacity 10 and the other capacity 20.

We request a projector and a capacity of 15 or more, so the only match is room2, and indeed the resulting output is:

Slot 10:00 to 11:00 is available
    It uses resource : room2
    The potential capacity at this slot is 1
    The consumed capacity at this slot is 0
Slot 11:00 to 12:00 is available
    It uses resource : room2
    The potential capacity at this slot is 1
    The consumed capacity at this slot is 0
Slot 13:00 to 14:00 is available
    It uses resource : room2
    The potential capacity at this slot is 1
    The consumed capacity at this slot is 0

There is a ton of stuff glossed over here, not least:

  • that resources have their own availability

  • that capacity based services are possible (think a yoga class taking in 12 people)

  • that complex resource requirement combinations are supported

Regardless, I hope you get a flavour of what's possible using the breezbook resourcing and availability functions.

The repo is here and these specific test cases are available here.

0
Subscribe to my newsletter

Read articles from Mike Hogan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mike Hogan
Mike Hogan

Building an open source booking and appointments software stack - https://github.com/cozemble/breezbook