A booking system is a scheduling system

There is a booking system on this site. It exists so that a wholesale buyer can put a thirty minute call in the calendar, tell us roughly how many cans a month they move, and walk away knowing which discount tier their account lands on when the call is over. It is a small feature on an energy drink shop.
It is also, almost exactly, the thing a consultancy sells, and the thing a hotel sells. The difference between the three is smaller than it looks, and worth explaining, because scheduling is the feature clients most often assume is a plugin.
What is actually on this site
A visitor opens the reseller page, says what they buy and how often, and sees the tier that volume qualifies for. Then they pick a slot. Slots are thirty minutes, generated against Romania time, and only the free ones are offered. They fill in company, phone and an optional note, and the booking is made.
Two emails go out immediately: a confirmation to the buyer with a link into their account, and a notification to the team with everything needed to prepare, with the buyer’s address set as the reply address. The booking appears in the customer’s account, where it can be cancelled. It also appears in a WooCommerce admin screen, where it can be marked complete.
When a call is marked complete, or when it has simply passed, the customer’s account is moved onto the discount tier the volume earned. Every future order is priced at that tier. That last sentence is the part that matters: the booking is not a calendar entry, it is a step in a process that changes what the customer pays.
Why booking looks trivial and is not
A booking form is a date, a time and a name. A booking system is what happens when two people submit the same slot within the same second.
Checking whether a slot is free and then writing the booking is two operations, and anything can happen between them. The usual result is a calendar with two people in one half hour and nobody noticing until one of them is sitting on a call alone.
The fix on this site is to make the database refuse. Every booking carries a lock value derived from its start time, and that column is unique. The insert is the check. Two simultaneous requests both try to write; the database accepts one and rejects the other, and the rejected one gets a clear message telling them somebody took that time a moment ago and to pick another. Cancelling a booking clears the lock, which frees the slot again.
That is the entire concurrency design, and it is four lines of code. Getting to those four lines is the part you are paying for.
The parts that are never in the brief
Anybody can list the happy path. The work lives here:
- Time zones. Slots are stored in universal time and displayed in the business’s time zone. The moment a buyer in Chicago books a slot shown in Romania time, the two numbers must still describe the same instant, and the confirmation email has to say which zone it means.
- Generating availability. Working hours, days off, the length of a slot, how far ahead bookings open and how close to the start they close. Every one of those is a business rule that will change after launch.
- Cancellation. Who may cancel, until when, what it frees, and what the other side is told.
- Completion. A booking that has passed is not the same as a booking that happened. On this site a scheduled task promotes bookings whose time has gone, and it claims each one with a conditional update so that two overlapping runs cannot promote the same booking twice and hand out the discount twice.
- Notifications. Confirmation, reminder, cancellation, reschedule. Each one is a template, a trigger and a decision about who receives it.
- The admin side. Somebody has to see today’s bookings, mark them done, cancel one, and find the person who booked it. That screen is as much work as the public form.
The same machine, selling consultancy
Consider a firm that sells advisory time. The shape is identical: a visitor picks a slot, the slot locks, a confirmation goes out, the session happens, a record closes.
Three things change, and none of them are structural.
The slot becomes the product. On this site the call is free and the outcome is a discount tier. For a consultancy the call is the thing being sold, so the slot carries a price. WooCommerce already knows how to price and sell a thing, take payment for it and issue an invoice for it. The booking stops being a table of its own and becomes an order line with a start time attached.
The lock has to survive checkout. This is the one genuinely new problem. When money is involved there is a gap between choosing a slot and paying for it, and during that gap the slot must be held but not yet booked. That means a reservation with an expiry, a job that releases abandoned reservations, and a decision about what happens when payment succeeds after the hold has lapsed. It is a known problem with a known shape, and it is where an honest estimate spends its hours.
Calendar and delivery. A paid session usually wants a calendar invitation, a video link, and a reminder the day before. Each is an integration rather than an invention.
What does not change is everything underneath: availability generation, the unique lock, cancellation, the completion sweep, the admin screen, the emails. That is most of the system, and it is already built.
The same machine, selling rooms
A hotel is the same system with a different unit of time and one extra dimension.
Instead of a thirty minute slot on one day, the unit is a night, and a booking spans a range of them. Instead of one bookable resource there are many, and each is bookable independently. So the lock stops being one value per start time and becomes an overlap check per room: no booking for this room may intersect this range. The database still does the refusing, it just refuses on a different condition.
Everything else maps cleanly. Availability generation becomes a calendar rather than a list of times. Pricing becomes per night, with rates that vary by season and by length of stay, which is the same tiered pricing logic this site already uses to make a case of cans cheaper than a single can. Cancellation policy becomes a refund rule rather than a yes or no. The confirmation email becomes a reservation with dates.
And the commercial part is genuinely simple once the reservation exists, because an accepted reservation is an order, and WooCommerce has spent fifteen years learning how to be good at orders. Payment, partial payment, deposits, invoices, refunds, tax by country: none of that has to be invented.
What changes when you charge
Three things, and they are the honest scope difference between a free booking form and a paid one.
A hold that expires. Described above. It is the difference between a booking system and a booking system that takes money.
Money that can fail after the fact. Payments are refused, refunded and disputed days later. Every one of those states has to move the booking somewhere sensible, which means the booking listens to payment events rather than being created by a form submission.
Rules about refunds. Free cancellation until a date, partial after that, none inside a window. This is where most of the argument with a client happens, and it is worth having before the build rather than during it.
Why this is not a plugin decision
Booking plugins exist and some of them are good. They are also the thing you will fight, for exactly the reason a theme is the thing you will fight: they made the decisions already.
The reseller booking on this site exists because it had to do something no plugin does, which is change the pricing tier on a customer account when a call completes. It is roughly four hundred lines. It is built into the same data as everything else, which is why the tier it assigns is the tier the cart charges, without a synchronisation step between two systems that each think they own the truth.
That is the real argument for building it. Not that the plugin cannot book a slot, but that the plugin cannot know what the booking is for.
What to bring to the conversation
If you are considering something in this family, four answers make the estimate honest rather than defensive.
- What is being booked, and is there one of it or many? One calendar is a different system from forty rooms.
- Is money involved at the moment of booking, later, or never? This is the single biggest lever on scope.
- What happens after? A booking that only sits in a calendar is cheap. A booking that changes pricing, unlocks access or triggers a delivery is a process.
- Who cancels, and what does that cost them? Write the policy in a sentence before anybody writes code.
Arrive with those four and the first meeting is about the business rather than about definitions. That is the whole point of this article.
This shop is a working demonstration of what a headless WooCommerce build is capable of, and everything described here is running on it. If you are weighing a build of your own, it was made by Pavels Web Solutions.


