A SupplyRequest is a single line item: a quantity of one catalogue item (ProductKnowledge) that someone wants moved. Requests never stand alone — each belongs to a RequestOrder that groups them and describes the movement into a destination facility location, optionally from a supplier organization and/or an origin location. You create requests when an order needs stock; you read them back as part of the order they hang off.
The Django model is only storage. status, priority, intent, reason, category, and supplied_item_condition are plain CharFields with no DB-level constraint, so the database will hold any string. The allowed values, validation, and request/response shapes live in the Pydantic resource specs under care/emr/resources/inventory/supply_request/, covered below.
Source:
Models
| Model | Purpose |
|---|
SupplyRequest | A request for a quantity of a catalogue item (product knowledge), grouped under an order |
RequestOrder | An order that groups supply requests for movement of items into a destination facility location |
Both extend EMRBaseModel, the shared Care EMR base providing external_id, audit fields (created_date/modified_date/created_by/updated_by), soft-delete via deleted, and history/meta JSON.
SupplyRequest fields
| Field | Type | Notes |
|---|
status | CharField(255) | Lifecycle status, spec-bound to SupplyRequestStatusOptions (see below). Required on write. |
quantity | DecimalField | max_digits=20, decimal_places=6, nullable in DB. The write spec accepts a Decimal capped to decimal_places=0 (whole numbers); the read spec returns it as an int. |
supplied_item_condition | CharField(255) | Model-only — no current spec reads or writes it, so it's unreachable through the API. |
item | FK → ProductKnowledge | CASCADE. The catalogue item being requested. Required on create, resolved server-side from an external_id. Cannot be changed afterwards. |
order | FK → RequestOrder | CASCADE, nullable in DB but required by the spec on both create and update. Resolved server-side from an external_id. |
SupplyRequestStatusOptions values
Defined in spec.py and bound to SupplyRequest.status.
| Value |
|---|
draft |
active |
suspended |
cancelled |
processed |
completed |
entered_in_error |
RequestOrder
The order is the unit you actually work with. It collects one or more SupplyRequest rows and carries the routing: a required destination facility location, plus an optional supplier organization and origin location.
supplier → FK Organization (nullable, CASCADE)
origin → FK FacilityLocation (nullable, CASCADE, related_name="origin_request_orders")
destination → FK FacilityLocation (CASCADE, related_name="destination_request_orders")
| Field | Type | Notes |
|---|
name | CharField(255) | Required. |
status | CharField(255) | Spec-bound to SupplyRequestOrderStatusOptions. |
note | TextField | Optional (str | None). |
tags | ArrayField[int] | Default list; tag IDs, not a relational join. Expanded to tag objects on read via SingleFacilityTagManager. |
priority | CharField(255) | Spec-bound to SupplyRequestPriorityOptions. |
intent | CharField(255) | Spec-bound to SupplyRequestIntentOptions. |
reason | CharField(255) | Spec-bound to SupplyRequestReason. |
category | CharField(255) | Spec-bound to SupplyRequestCategoryOptions. |
supplier | FK → Organization | Nullable CASCADE. On write, must be an organization with org_type == "product_supplier" — the server rejects anything else. |
origin | FK → FacilityLocation | Nullable CASCADE, related_name="origin_request_orders". The sending location. |
destination | FK → FacilityLocation | CASCADE, related_name="destination_request_orders". The receiving location. Required. |
origin and destination both point at FacilityLocation but carry distinct related_names, so one location can list the orders it sends (origin_request_orders) separately from the orders it receives (destination_request_orders).
RequestOrder enum values
From request_order.py. Each binds to the matching RequestOrder CharField.
SupplyRequestOrderStatusOptions (→ status)
| Value |
|---|
draft |
pending |
in_progress |
completed |
abandoned |
entered_in_error |
SUPPLY_REQUEST_ORDER_COMPLETED_STATUSES = [abandoned, entered_in_error, completed] marks the terminal/closed statuses.
SupplyRequestIntentOptions (→ intent)
| Value |
|---|
proposal |
plan |
directive |
order |
original_order |
reflex_order |
filler_order |
instance_order |
SupplyRequestCategoryOptions (→ category)
SupplyRequestPriorityOptions (→ priority)
| Value |
|---|
routine |
urgent |
asap |
stat |
SupplyRequestReason (→ reason)
| Value |
|---|
patient_care |
ward_stock |
Resource specs (API schema)
Every spec extends EMRResource (serialize / de_serialize, with perform_extra_serialization / perform_extra_deserialization hooks). Write specs resolve foreign keys from external_id values in perform_extra_deserialization; read specs expand related objects in perform_extra_serialization.
Supply request specs (spec.py)
| Spec class | Role | Fields | Notes |
|---|
BaseSupplyRequestSpec | shared | id, status, quantity | __model__ = SupplyRequest, __exclude__ = ["item"]. quantity: Decimal(max_digits=20, decimal_places=0). status: SupplyRequestStatusOptions. |
SupplyRequestWriteSpec | write · create | base + item: UUID4, order: UUID4 | Resolves item → ProductKnowledge and order → RequestOrder by external_id; 404 if either is missing. |
SupplyRequestUpdateSpec | write · update | base + order: UUID4 | Resolves order → RequestOrder by external_id. Omits item — the catalogue item is fixed once created. |
SupplyRequestReadSpec | read · detail/list | base + quantity: int, item: dict, order: dict | id = external_id. item expanded via ProductKnowledgeReadSpec; order via SupplyRequestOrderReadSpec. |
Request order specs (request_order.py)
| Spec class | Role | Fields | Notes |
|---|
BaseSupplyRequestOrderSpec | shared | id, status, name, note, intent, category, priority, reason | __model__ = RequestOrder. Coded fields bound to their enums; note optional. |
SupplyRequestOrderWriteSpec | write · create/update | base + supplier: UUID4 | None, origin: UUID4 | None, destination: UUID4 | Resolves supplier/origin/destination by external_id. Raises ValidationError unless supplier.org_type == "product_supplier". |
SupplyRequestOrderReadSpec | read · detail/list | base + supplier, origin: dict | None, destination: dict, tags: list[dict], created_date, modified_date, created_by, updated_by | id = external_id. supplier expanded via OrganizationReadSpec; origin/destination via FacilityLocationListSpec; tags via SingleFacilityTagManager; audit users via serialize_audit_users. |
Validation and server-maintained behaviour
- FK resolution. Every foreign key on write comes in as an
external_id UUID and is resolved server-side with get_object_or_404: item, order, supplier, origin, destination.
- Supplier type guard.
SupplyRequestOrderWriteSpec rejects any supplier whose org_type is not product_supplier.
id handling. Read specs set id to external_id; de_serialize never writes id or external_id back to the row.
quantity. Write accepts a Decimal pinned to decimal_places=0 (whole numbers) even though the DB column allows decimal_places=6; read returns an int.
item immutability. Create takes item; SupplyRequestUpdateSpec drops it, so the requested catalogue item can't change after creation.
Methods and save behaviour
- Neither model overrides
save(); standard EMRBaseModel audit and soft-delete behaviour applies.
- Status is free-text at the DB layer — the lifecycle is enforced only by the spec enums at the API boundary. Neither model tracks
status_history.
- Deleting a
RequestOrder cascades to its SupplyRequest rows (the order FK is CASCADE); deleting a referenced ProductKnowledge cascades to the request.
API integration notes
- Payload field names match the spec fields above. Foreign keys go out as
external_id UUIDs on write and come back as expanded objects on read.
- Send
status, priority, intent, reason, and category as the exact strings listed above — they're validated against the spec enums.
supplied_item_condition lives on the model but no current spec surfaces it.
quantity travels as a whole number through the specs; the DB column keeps six decimal places regardless.
tags on RequestOrder is an integer array of tag IDs, rendered to tag objects on read by the facility tag manager.
external_id (from EMRBaseModel) is the stable public identifier in API URLs — never the internal primary key.