← Knowledge library

Appointments & queues

Booking

A booking puts a patient into a concrete time slot generated from a Schedule. TokenSlot is a bookable unit of availability; TokenBooking is a patient's appointment against that slot, carrying its status through the lifecycle. You touch both…

3.1 · versioned documentation · 7 min read

A booking puts a patient into a concrete time slot generated from a Schedule. TokenSlot is a bookable unit of availability; TokenBooking is a patient's appointment against that slot, carrying its status through the lifecycle. You touch both whenever an integration creates, cancels, reschedules, or reads an appointment.

Source:

These models live in two layers. The Django model is storage: status is an unconstrained CharField and several relations are opaque at the DB level. The Pydantic resource specs (care/emr/resources/scheduling/slot/) are the API layer — they pin status to a fixed enum, validate writes, and define the read schemas that embed slot, resource, facility, token, charge item, encounter, and patient sub-objects.

Models

Model Purpose
TokenSlot A concrete, bookable time window generated from a schedulable resource's availability
TokenBooking A patient's appointment against a TokenSlot, with status, notes, and optional links to an encounter, token, and charge item

Both extend EMRBaseModel, the shared MANSOQ EMR base providing external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON.

TokenBooking fields

Field Type Notes
token_slot FK → TokenSlot (PROTECT) The slot this appointment occupies; required. PROTECT prevents deleting a slot that has bookings
patient FK → emr.Patient (CASCADE) The booked patient; required
booked_on DateTimeField auto_now_add — stamped once at creation, never accepted from clients
booked_by FK → User (CASCADE) User who created the booking; nullable for self-service or system-created bookings
status CharField (storage) → BookingStatusChoices (API) Appointment lifecycle status. Unbounded on the model; the write spec restricts it to the BookingStatusChoices enum
note TextField Free-text note; nullable in storage but required (str) on write
tags ArrayField[int] Tag IDs, default empty list. Managed via SingleFacilityTagManager; reads return rendered tag objects, not raw IDs
associated_encounter FK → emr.Encounter (PROTECT) Encounter linked to the appointment; nullable, defaults to None. Surfaced only by TokenBookingRetrieveSpec
token FK → emr.Token (PROTECT) Queue token issued for this booking; nullable, defaults to None, related_name="token_booking". Created by the generate_token action
charge_item FK → emr.ChargeItem (CASCADE) Billing charge item for the appointment; nullable. Auto-created on booking when the schedule has a charge_item_definition

BookingStatusChoices values

BookingStatusChoices (str, Enum) is the full set of status values the write spec accepts:

Value Notes
proposed
pending
booked Default applied server-side when a booking is created via lock_create_appointment
arrived
fulfilled Terminal; in COMPLETED_STATUS_CHOICES
cancelled Set only via the cancel endpoint; in CANCELLED_STATUS_CHOICES + COMPLETED_STATUS_CHOICES
noshow Terminal; in COMPLETED_STATUS_CHOICES
entered_in_error Set only via the cancel endpoint; in CANCELLED_STATUS_CHOICES + COMPLETED_STATUS_CHOICES
checked_in
waitlist
in_consultation Cannot be cancelled — the cancel handler rejects it
rescheduled Set only via the reschedule endpoint; in CANCELLED_STATUS_CHOICES + COMPLETED_STATUS_CHOICES

Two derived sets (from slot/spec.py) drive the lifecycle rules:

Set Values
CANCELLED_STATUS_CHOICES entered_in_error, cancelled, rescheduled
COMPLETED_STATUS_CHOICES fulfilled, noshow, entered_in_error, cancelled, rescheduled

TokenBookingWriteSpec.perform_extra_deserialization rejects any write whose status is in CANCELLED_STATUS_CHOICES with "Cannot cancel a booking. Use the cancel endpoint". Cancellation and rescheduling go through dedicated endpoints (see below), never a plain update.

Related models

TokenSlot

A bookable window derived from a resource's availability. Bookings reference it via PROTECT, so a slot with active bookings cannot be deleted.

Field Type Notes
resource FK → SchedulableResource (CASCADE) The schedulable resource — practitioner, location, or healthcare service — the slot belongs to; required
availability FK → Availability (CASCADE) The availability rule that generated this slot; nullable
start_datetime DateTimeField Slot start; required, tz-aware
end_datetime DateTimeField Slot end; required, tz-aware
allocated IntegerField Count of bookings currently allocated to the slot, used to enforce capacity. Defaults to 0. Platform-maintained — never written by clients

SchedulableResource and Availability live in the Schedule module. SchedulableResource.resource_type is one of SchedulableResourceTypeOptions: practitioner, location, healthcare_service.

Resource specs (API schema)

Every spec extends EMRResource (base.py): serialize (DB → pydantic, read) and de_serialize (pydantic → DB, write), with perform_extra_serialization / perform_extra_deserialization hooks.

Spec class Role Exposes / behaviour
TokenBookingBaseSpec shared __model__ = TokenBooking, __exclude__ = ["token_slot", "patient"]
TokenBookingWriteSpec write · create + update Fields: status: BookingStatusChoices, note: str. Rejects status in CANCELLED_STATUS_CHOICES (use the cancel/reschedule endpoints). Serves as both pydantic_model and pydantic_update_model
TokenBookingMinimumReadSpec read · embed Lightweight read for when a booking is embedded in another resource, such as a token. Fields: id, token_slot (embedded TokenSlotBaseSpec), booked_on, status: str, note, created_date, modified_date
TokenBookingBaseReadSpec read · shared Adds booked_by: UserSpec, resource_type, resource (serialized resource), facility, created_by/updated_by, token: TokenReadSpec, tags: list[dict] (rendered), charge_item: dict
TokenBookingReadSpec read · list/default TokenBookingBaseReadSpec + patient: PatientRetrieveSpec. The viewset's pydantic_read_model for list responses
TokenBookingOTPReadSpec read · OTP flow TokenBookingBaseReadSpec + patient: PatientOTPReadSpec for the public/OTP booking flow
TokenBookingRetrieveSpec read · detail TokenBookingReadSpec + associated_encounter: dict (serialized EncounterListSpec). The viewset's pydantic_retrieve_model
TokenSlotBaseSpec read · embed __model__ = TokenSlot, __exclude__ = ["resource", "availability"]. Fields: id, availability (embedded as {name, tokens_per_slot, id, schedule:{name,id}}), start_datetime, end_datetime, allocated

Read serialization details (perform_extra_serialization)

Methods & save behaviour

status has no model-level choices; the lifecycle lives entirely in the spec/viewset layer (TokenBookingViewSet). The server-maintained behaviour:

API integration notes

Related

Source evidence

References are pinned to the private MANSOQ source repository. Repository access is required to open these links.