Skip to content

Booking statuses

Page summary: Understand what state a booking is really in.

Use this when: Use this when building, testing, supporting, reporting on, or changing booking behaviour.

  • A booking has five independent status models.
  • “Confirmed” answers whether the trip is going ahead, not whether money arrived.
  • Start with the status model; use the exact rules only when you need transition behaviour or edge cases.

A booking has five statuses, not one

They move independently. None controls the others.

StatusAnswers
BookingIs the trip happening?
ItemIs each line accepted?
PaymentHas money arrived?
InvoiceWhere is the bill?
CancellationHas someone asked to cancel, and was it agreed?

So all of these are normal: confirmed and unpaid · cancelled and fully paid · paid while the invoice still says draft · confirmed with one line rejected · confirmed with a cancellation request waiting.

When someone says "the booking looks wrong", ask which of the five they are looking at. Different screens show different ones.

Evidence and test details
  • Code ems-backend/internal/shared/entities/booking.entity.go:33-38
  • Checked Confirmed in code, 5 Aug 2026

Booking status

Is the trip happening.

Shown asStored asMeans
RequestedrequestedGuest asked. Vendor has not answered.
Pending customer confirmationpending_customer_confirmationVendor proposed a change. Waiting on the guest.
ConfirmedconfirmedGoing ahead.
Partially confirmedpartially_confirmedValid, but nothing sets it and nothing shows it. See A status nothing can display.
RejectedrejectedVendor turned it down.
In progressin_progressHappening now.
DonedoneFinished.
No showno_showGuest did not turn up.
CancelledcancelledCalled off.
ArchivedarchivedFiled away. Nothing can change afterwards.

There is no "paid", "refunded" or "expired" booking status. Those belong to payment.

How a booking gets its first status

Guest books directlyrequested. The vendor then reviews each line. Any line approved makes it confirmed. A line proposed for change makes it pending customer confirmation. All lines rejected makes it rejected.

Partner booksconfirmed straight away, no vendor review.

Vendor books from the dashboardconfirmed, all checks skipped. See Vendor bookings skip every check.

Evidence and test details
  • Code ems-apis/constants/booking_status.go:5-29 · ems-backend/internal/booking/usecases/booking_create.usecase.go:43 · ems-backend/internal/booking/repositories/impl/booking.adapter.go:109-153 · ems-backend/internal/booking/usecases/booking_reseller.usecase.go:229
  • Checked Confirmed in code, 5 Aug 2026

What can change to what

FromCan become
ConfirmedIn progress, Done, No show, Cancelled, Archived
In progressConfirmed, Done
No showConfirmed
CancelledConfirmed, No show, Archived — but should not
DoneConfirmed, In progress
Archivednothing
Requested, Rejectednothing happens, and no error

Anything else is refused with "Cannot revert back".

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:531-600
  • Checked Confirmed in dev for Done → Confirmed and Done → In progress, booking BO10GI1LMR7, 5 Aug 2026. Rest confirmed in code.

Item status

One line per thing booked. Each is accepted or refused on its own, and the lines decide the booking status — not the other way round.

Six values: requested · pending customer confirmation · rejected · confirmed · cancelled · no show.

A two-item booking with one item rejected still shows as confirmed. The guest is coming, for less than they asked for.

Evidence and test details
  • Code ems-apis/constants/booking_item_status.go:11-18
  • Checked Confirmed in code, 5 Aug 2026

Payment status

Whether money arrived. Independent of whether the trip is happening.

Ten values: waiting payment · unpaid · due · overdue · processing · partially paid · paid · failed · partially refunded · refunded.

Every booking starts at waiting payment.

Evidence and test details
  • Code ems-apis/constants/payment_status.go:8-19 · ems-backend/internal/booking/usecases/booking_create.usecase.go:47
  • Checked Confirmed in code, 5 Aug 2026

Invoice status

Where the bill got to. Separate from whether money arrived.

Seven values: draft · invoice sent · partially paid · paid · partially refunded · fully refunded · voided.

Payment and invoice status share several words and can hold different values at once. The booking list shows the invoice one.

Evidence and test details
  • Code ems-apis/constants/invoice_status.go:5-13
  • Checked Confirmed in dev — booking list badge is labelled "Invoice Status", 5 Aug 2026

Cancellation status

A cancellation is its own record. It exists from the moment someone asks, which is not the same as the booking being cancelled.

Two values: requested and confirmed. It can cover some lines or all of them, so there are four real situations:

PartialFull
RequestedAsked to cancel part. Not agreed.Asked to cancel all. Not agreed.
ConfirmedPart cancelled, rest stands.All cancelled.

Each cancelled line has its own refund amount, and the agreed amount can differ from the amount asked for.

A confirmed partial cancellation leaves the booking status at confirmed. That is correct.

Evidence and test details
  • Code ems-apis/constants/cancellation_status.go · ems-backend/internal/shared/entities/booking.entity.go:719-743
  • Checked Confirmed in code, 5 Aug 2026

What each screen explains

The dashboard has a built-in status guide, reached from "Show status guide" on the booking list.

Guide tabExplainsSilent about
BookingConfirmed, In progress, Cancelled, DoneRequested, Pending, Rejected, No show, Archived, Partially confirmed
InvoiceInvoice sent, Partially paid, Paid, Partially refunded, Fully refundedDraft, Voided
PaymentNot paid, Processing, Paid, Partially refunded, Overdue, Due, FailedWaiting payment, Partially paid, Refunded, Unpaid

A vendor can see a status the guide does not explain — including waiting payment, which every booking starts at.

Evidence and test details
  • Code VMS-Frontend/apps/main/src/microapps/booking/components/BookingList/BookingListStatusGuidePopup/BookingListStatusGuidePopup.viewModel.tsx:16-40
  • Checked Confirmed in dev, 5 Aug 2026

Rules

Archived is final BST-001

What happens today: Nothing can be changed once a booking is archived. The attempt is refused.

Applies to: Everyone.

Expected behaviour: Not established.

Status: No stated intent.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:593-594
  • Checked Confirmed in code, 5 Aug 2026

A cancelled booking cannot safely be reopened BST-002

What happens today: The API allows a cancelled booking back to confirmed, no show or archived. The dashboard blocks it — the status control is switched off entirely for cancelled bookings.

Why it matters: Cancelling releases the seats, stops the unpaid payment schedule and removes any promotion. Coming back to confirmed restores none of it.

Expected behaviour: A cancelled booking stays cancelled.

Status: Product and code do not match. Only the screen prevents it.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:575-582 · dashboard VMS-Frontend/apps/main/src/microapps/booking/components/BookingStatusDropdown/BookingStatusDropdown.viewModel.tsx:87-91, 127-136
  • Checked Confirmed in code, 5 Aug 2026
  • Test Call the status-change API on a cancelled booking, asking for confirmed. It should be refused.
  • Follow-up Open decisions

A finished booking can be reopened BST-003

What happens today: A booking marked done can go back to confirmed or in progress.

Why it matters: The completion time is written when the booking becomes done and never cleared, so a reopened booking carries a completion time while not being complete. Reports read that field.

Expected behaviour: Exactly this. Confirmed by product.

Status: Matches, with a side effect worth knowing.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:583-589
  • Checked Confirmed in dev — booking BO10GI1LMR7, the dropdown offered Confirmed and In Progress, 5 Aug 2026

Some status changes do nothing, and say they worked BST-004

What happens today: Changing the status of a booking at requested or rejected returns success and changes nothing. No error. Any follow-on action runs against the old status.

Why it matters: The automatic cancellation job uses this route. A booking still at requested would fail to cancel and record that it succeeded.

Expected behaviour: Not established — either refuse with an error, or allow it. Silent success is wrong either way.

Status: No stated intent. Not yet reproduced.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:540-597
  • Checked Confirmed in code, 5 Aug 2026. Not reproduced in dev.
  • Test Take a booking at requested. Call the status-change API asking for cancelled. Check the response, then re-read the booking.
  • Follow-up Open decisions

Propose-changes always moves the booking to pending BST-005

What happens today: Proposing a change to a line moves the booking to pending customer confirmation. There is a switch for it, and it is on in dev, staging and production.

Expected behaviour: This. The older path is unreachable anywhere.

Status: Matches.

Evidence and test details
  • Code ems-backend/internal/booking/repositories/impl/booking.adapter.go:122-128
  • Checked Confirmed in code; setting read from all three environment configuration files, 5 Aug 2026

What cancelling actually does BST-006

What happens today: Three things together: unpaid payment schedules are stopped; any promotion is removed and its coupon released; a cancellation notification is triggered.

Exception: If the caller says what to do with each payment, that is used instead of stopping everything.

Expected behaviour: Not established.

Status: No stated intent.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:471-483, 506-514, 602-616
  • Checked Confirmed in code, 5 Aug 2026

Part-paid bookings are never cancelled automatically BST-007

What happens today: The automatic cancellation job stops if any part of the booking has been paid. A person can still cancel it by hand.

Why it matters: A deposit that never becomes a full payment holds its seat indefinitely.

Expected behaviour: Not established.

Status: No stated intent. Product has parked it with a recommendation.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:415-428
  • Checked Confirmed in code, 5 Aug 2026
  • Follow-up Open decisions

Timestamps are written once and never cleared BST-008

What happens today: Requested time at creation, confirmed time on confirmation, completed time on done. None is cleared when the booking leaves that status.

Why it matters: Reopening a finished booking is allowed, so a booking can be confirmed while carrying a completion time.

Expected behaviour: Not established.

Status: No stated intent.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_create.usecase.go:44 · ems-backend/internal/booking/repositories/impl/booking.adapter.go:131-133 · ems-backend/internal/booking/usecases/booking_internal.usecase.go:485-488
  • Checked Confirmed in code, 5 Aug 2026

Rejected bookings get a confirmation time BST-009

What happens today: Rejecting a booking sets the confirmed-at field to the moment of rejection.

Why it matters: Any report counting confirmations by that field counts rejections too.

Expected behaviour: Not established. Either the field is reused to mean "when this was decided", or it is a slip.

Status: No stated intent. Product has parked it with a recommendation.

Evidence and test details
  • Code ems-backend/internal/booking/repositories/impl/booking.adapter.go:140-144
  • Checked Confirmed in code, 5 Aug 2026
  • Follow-up Open decisions

Only instant-confirm experiences reach partners BST-010

What happens today: Partner bookings confirm without asking the vendor. Product says that is safe because experiences needing approval are never offered to partners.

Expected behaviour: This.

Status: The confirming half matches. The filtering half has not been found in the code.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_reseller.usecase.go:229
  • Checked Confirmed in code for the confirm step; intent stated by product, 5 Aug 2026
  • Follow-up Open decisions

The dashboard keeps its own copy of the transition rules BST-011

What happens today: The dashboard has its own list of which status can follow which, separate from the service's, and they disagree. The service allows archiving from confirmed and cancelled; the dashboard never offers it. The dashboard lists options for a cancelled booking then switches the button off.

Exception: For Get Your Guide bookings the dashboard switches the control off entirely.

Why it matters: What you can do depends on whether you use the screen or the API. The screen is currently the only thing preventing reopening a cancelled booking.

Expected behaviour: One list, in one place.

Status: Two copies, already drifted.

Evidence and test details
  • Code ems-backend/internal/booking/usecases/booking_internal.usecase.go:540-597 against VMS-Frontend/apps/main/src/microapps/booking/components/BookingStatusDropdown/BookingStatusDropdown.viewModel.tsx:68-98, 119-143
  • Checked Confirmed in code, 5 Aug 2026

The dashboard expects payment values the service never sends BST-012

What happens today: The service sends a full refund as refunded; the dashboard expects fully_refunded. The dashboard also handles four values that do not exist — pending_payment, not_paid, invoice_sent, voided — and does not handle unpaid, which does exist.

Why it matters: An unrecognised value gets no label and no colour, because both are looked up from the value itself.

Expected behaviour: One agreed list.

Status: Mismatch.

Evidence and test details
  • Code ems-apis/constants/payment_status.go:8-19 against VMS-Frontend/packages/utils/enums/PaymentStatus.ts:13-27
  • Checked Confirmed in code, 5 Aug 2026. Not yet seen on screen — needs a fully refunded booking in dev.
  • Test Find or make a fully refunded booking in dev. Look at the payment status badge on the booking list.

A status nothing can display BST-013

What happens today: partially_confirmed is defined in the service and accepted as valid. Nothing sets it, and the dashboard has never heard of it — no label, no colour, no list of allowed next statuses.

Why it matters: It is accepted as valid, so anything setting a status through the API can put a booking into a state the dashboard cannot render.

Expected behaviour: Not established. Finish it or remove it.

Status: No stated intent.

Evidence and test details
  • Code ems-apis/constants/booking_status.go:10, 23; absent from VMS-Frontend/packages/utils/enums/BookingStatus.ts and from the dashboard's transition list
  • Checked Confirmed in code, 5 Aug 2026

A payment status that fails its own validity check BST-014

What happens today: unpaid is defined, but left out of the service's own list of valid payment statuses. Any validity check rejects it.

Expected behaviour: Not established. Almost certainly a slip.

Status: No stated intent.

Evidence and test details
  • Code ems-apis/constants/payment_status.go:17 defined; absent from the check at lines 21-31
  • Checked Confirmed in code, 5 Aug 2026

A refunded invoice document says "Unpaid" BST-015

What happens today: The invoice PDF works out its own status word, separately from the badge on screen. Only four statuses have a word of their own; draft, partially refunded and fully refunded all fall through to "Unpaid". The PDF is rebuilt whenever the invoice changed since the file was last written — and a refund changes the invoice.

Why it matters: The PDF is what goes to the customer and what finance reconciles against. The badge on screen is correct; the document is not.

Expected behaviour: Every status has its own word.

Status: Mismatch, not yet seen on a real document.

Evidence and test details
  • Code ems-apis/constants/invoice_status.go:15-28, used at ems-backend/internal/payment/usecase/invoice.usecase.go:719; rebuild-on-download at :454-458
  • Checked Confirmed in code, 5 Aug 2026. No refunded invoice PDF opened yet.
  • Test Find a fully refunded booking in dev, download its invoice, read the status word on the document.

The status guide explains a payment status that does not exist BST-016

What happens today: The dashboard's status guide describes "Not Paid". The service has no such status — it has unpaid and waiting_payment, and the guide describes neither.

Why it matters: A vendor looking up the status in front of them will not find it, and will find one they never see. Every booking starts at waiting payment.

Expected behaviour: The guide describes the statuses the service actually sends.

Status: Mismatch.

Evidence and test details
  • Code ems-apis/constants/payment_status.go:8-19
  • Checked Confirmed in dev — status guide, Payment Status tab, 5 Aug 2026

Not established yet

GapWhy it mattersWho can settle it
Which notification each status change sendsNeeded to answer "why didn't the guest get an email"engineering
What each status change does to available seatsBlocks the availability pageengineering
Which words each screen, email and export showsGuests, vendors and partners may see different words for the same thingproduct
Whether some status changes do nothing, and say they worked (BST-004), the dashboard expects payment values the service never sends (BST-012) and a refunded invoice document says "Unpaid" (BST-015) show up in the running productThree are code readings onlyengineering, in dev