← Knowledge library

Facility administration

Location

FacilityLocation is a node in a facility's building/ward/room/bed tree — where resources sit and where care happens. You work with it when you place an encounter somewhere, scope organization access to part of a facility, or model a site's…

3.1 · versioned documentation · 9 min read

FacilityLocation is a node in a facility's building/ward/room/bed tree — where resources sit and where care happens. You work with it when you place an encounter somewhere, scope organization access to part of a facility, or model a site's physical layout.

Source:

Nodes nest without limit: every node may have a parent and children, so one tree can run from a campus down to a single bed. Encounters and organizations attach to nodes, and access granted at a node cascades to its descendants asynchronously rather than resolving on each request. The model maps to the FHIR Location resource.

The Django model is only the storage layer. location_type, metadata, and cached_parent_json are opaque JSONFields; their real shape lives in the Pydantic resource specs (care/emr/resources/location/spec.py), which also define every enum and the read/write schema split. See Resource specs (API schema).

Models

Model Purpose
FacilityLocation A node in a facility's location tree (building, ward, room, bed, …)
FacilityLocationOrganization Grants a FacilityOrganization access to a location
FacilityLocationEncounter Records how/when an encounter occupied a location (e.g. a bed)

All three extend EMRBaseModel, which supplies external_id, audit fields, and soft-delete semantics.

FacilityLocation fields

Descriptive

Field Type Spec values / shape Notes
name CharField(255) str, required Must be unique among siblings at the same level under the same root (see validation)
description CharField(255) str, required Free-text
status CharField(255) StatusChoices enum One of StatusChoices
operational_status CharField(255) FacilityLocationOperationalStatusChoices enum FHIR operational status code; one of FacilityLocationOperationalStatusChoices
system_availability_status CharField(255) str (read-only) Server-maintained, derived from encounter association. Resolves to one of LocationAvailabilityStatusChoices (available / reserved)
mode CharField(255) FacilityLocationModeChoices enum kind (a type, e.g. a building/ward) or instance (a single location, e.g. Bed 1). Set on create, then frozen. See FacilityLocationModeChoices
location_type JSONField (default=dict, nullable) Coding | None (default None) A single FHIR Coding, not a CodeableConcept. Unbound — any coding is accepted
form CharField(255) FacilityLocationFormChoices enum FHIR physical form; one of FacilityLocationFormChoices

Hierarchy & tree caches

These fields denormalize the tree so descendants are queryable without recursive joins. save() and the cascade task own them; never set them from a client.

Field Type Notes
parent FK → FacilityLocation SET_NULL, nullable. Immediate parent. Accepted on write as a UUID (parent); on read it's dropped in favour of the serialized parent JSON
root_location FK → self CASCADE, related_name="root", nullable. Top of this node's tree. Excluded from specs
has_children BooleanField default=False. Set True on the parent when a child is created. Read-only in list/retrieve specs
level_cache IntegerField default=0. Depth in the tree (parent.level_cache + 1)
parent_cache ArrayField[int] Ordered ancestor IDs (parent.parent_cache + [parent.id])
cached_parent_json JSONField (default=dict) Serialized parent chain (FacilityLocationListSpec) plus a cache_expiry ISO timestamp. Rebuilt lazily by get_parent_json(), invalidated by the cascade task. cache_expiry_days = 15
sort_index IntegerField default=0. In specs int | None, default 0, constrained 0 ≤ sort_index ≤ 10000 (MIN_SORT_INDEX/MAX_SORT_INDEX). Auto-assigned as max(sibling sort_index) + 1 when left unset

Access & encounter

Field Type Notes
facility FK → facility.Facility PROTECT. Owning facility. Excluded from specs — resolved from route/context
facility_organization_cache ArrayField[int] default=list. Org IDs that can reach this location; rebuilt by sync_organization_cache()
current_encounter FK → Encounter SET_NULL, nullable, default=None. Populated from FacilityLocationEncounter. Excluded from the base spec; surfaced as serialized JSON in list/retrieve specs
metadata JSONField default=dict. Open extension bag for deployment-specific data

Enum values

Every enum is a str Enum in care/emr/resources/location/spec.py. Values below are character-for-character from source.

StatusChoices values

Value Meaning
active Location is active
inactive Location is inactive
unknown Status unknown

FacilityLocationOperationalStatusChoices values

FHIR HL7 v2 bed/location operational status codes.

Code Meaning
C Closed
H Housekeeping
O Occupied
U Unoccupied
K Contaminated
I Isolated

FacilityLocationModeChoices values

Value Meaning
instance A single, concrete location (e.g. Bed 1). Instances cannot have children
kind A class/type of location (e.g. a ward or building)

FacilityLocationFormChoices values

FHIR location-physical-type codes.

Code Meaning
si Site
bu Building
wi Wing
wa Ward
lvl Level
co Corridor
ro Room
bd Bed
ve Vehicle
ho House
ca Cabinet
rd Road
area Area
jdn Jurisdiction
vi Virtual

LocationEncounterAvailabilityStatusChoices values

Used by FacilityLocationEncounter.status — how an encounter occupies a location.

Value Meaning
planned Occupancy planned
active Currently occupied
reserved Reserved
completed Occupancy ended

LocationAvailabilityStatusChoices values

The server-derived values that system_availability_status resolves to.

Value Meaning
available Not actively tied to an encounter
reserved Tied to an encounter

Coding shape

location_type is a single Coding object (extra="forbid"):

Coding {
  system:  str | None = None
  version: str | None = None
  code:    str            # required
  display: str | None = None
}

Related models

FacilityLocationOrganization

Links an organization to a location. Users under that organization inherit access to the location and its encounters through whatever role they hold on the organization.

location     → FK FacilityLocation (CASCADE)
organization → FK FacilityOrganization (CASCADE)

Saving one of these rows calls location.save() (rebuilding facility_organization_cache), then location.cascade_changes() to propagate the grant down to descendants asynchronously. On write, the organization set comes from FacilityLocationWriteSpec.organizations, a list of UUIDs.

FacilityLocationEncounter

A bed assignment, in effect: it records how an encounter occupied a location over a time window.

Field Type Spec Notes
status CharField(25) LocationEncounterAvailabilityStatusChoices One of planned / active / reserved / completed
location FK → FacilityLocation excluded / nested CASCADE. Surfaced as JSON in ...ListSpecWithLocation
encounter FK → Encounter UUID on write, JSON on read CASCADE. Validated to exist on create
start_datetime DateTimeField datetime (required) Occupancy start
end_datetime DateTimeField (nullable) datetime | None Occupancy end; open-ended when null

FacilityLocation.current_encounter is populated from these rows.

Methods & save behaviour

save() side effects

On insert (no id yet):

  1. If parent is set, level_cache, root_location, and parent_cache are derived from the parent, and the parent's has_children is flipped to True if needed.
  2. If sort_index is unset, it's assigned max(sibling sort_index) + 1.

On update, cached_parent_json is cleared so it rebuilds lazily. After every super().save(), sync_organization_cache() runs and persists facility_organization_cache through a second save(update_fields=[...]), so each write touches the row twice.

Caches & cascade

validate_uniqueness()

Classmethod that enforces name uniqueness among siblings at the same level_cache within the same root_location — or among root-level locations when there's no root. For a new instance with a parent, level_cache and root_location are computed from that parent before the check runs.

Resource specs (API schema)

The Pydantic specs in care/emr/resources/location/spec.py define the request/response shapes. All extend EMRResource, which provides serialize/de_serialize plus the perform_extra_serialization/perform_extra_deserialization hooks (see base model and base.py).

Location specs

Spec class Role Exposes / notes
FacilityLocationBaseSpec shared base __model__ = FacilityLocation; id: UUID4 | None. __exclude__ = [parent, facility, organizations, root_location, current_encounter]
FacilityLocationSpec shared fields status, operational_status, name, description, location_type (Coding | None), form, sort_index (0..10000, default 0)
FacilityLocationWriteSpec write · create Adds parent: UUID4 | None, organizations: list[UUID4] (required), mode: FacilityLocationModeChoices. Validator: a set parent must exist and must not be mode = instance ("Instances cannot have children"). perform_extra_deserialization resolves the parent UUID to an FK
FacilityLocationUpdateSpec write · update Same fields as FacilityLocationSpec. Drops parent/organizations/mode — hierarchy and mode are fixed after creation
FacilityLocationMinimalListSpec read · minimal Adds parent: dict, mode: str, has_children: bool, system_availability_status: str. perform_extra_serialization sets id = external_id and parent = obj.get_parent_json()
FacilityLocationListSpec read · list Extends minimal; adds current_encounter: dict | None, serialized via EncounterListSpec when present
FacilityLocationRetrieveSpec read · detail Extends list; adds created_by/updated_by (via serialize_audit_users)

Encounter-association specs

Spec class Role Exposes / notes
FacilityLocationEncounterBaseSpec shared base __model__ = FacilityLocationEncounter; id: UUID4 | None. __exclude__ = [encounter, location]
FacilityLocationEncounterCreateSpec write · create status (LocationEncounterAvailabilityStatusChoices), encounter: UUID4, start_datetime, end_datetime: datetime | None. Validator: encounter must exist. perform_extra_deserialization resolves the encounter UUID to an FK
FacilityLocationEncounterUpdateSpec write · update status, start_datetime, end_datetime. Encounter is not re-assignable
FacilityLocationEncounterListSpec read · list encounter: UUID4, start_datetime, end_datetime, status: str; id = external_id
FacilityLocationEncounterListSpecWithLocation read · list Extends list; adds location: dict (serialized via FacilityLocationListSpec)
FacilityLocationEncounterReadSpec read · detail encounter: dict (serialized via EncounterRetrieveSpec), start_datetime, end_datetime, status, created_by/updated_by

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.