References/Supply Delivery: Difference between revisions
More languages
More actions
OHC identity seed |
Automated edit (via update-page on MediaWiki MCP Server) |
||
| Line 264: | Line 264: | ||
* <code>patient</code> and <code>origin</code> are mutually exclusive on an order (patient dispense vs location-to-location move). |
* <code>patient</code> and <code>origin</code> are mutually exclusive on an order (patient dispense vs location-to-location move). |
||
* <code>extensions</code> holds deployment-specific data, but only registered extension keys are persisted. |
* <code>extensions</code> holds deployment-specific data, but only registered extension keys are persisted. |
||
{{Navbox supply}} |
|||
{{Related}} |
{{Related}} |
||
Latest revision as of 09:48, 6 July 2026
A supply delivery records product moving into a destination location — either from another location or from an external supplier. Deliveries and dispensing together drive facility stock: supply delivered − supply dispensed = current stock. Each delivery belongs to a DeliveryOrder, the shipment grouping usually created from a supply request.
Source:
- Model: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/supply_delivery.py
care/emr/models/supply_delivery.py] - Resource specs: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/supply_delivery/spec.py
spec.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/supply_delivery/delivery_order.pydelivery_order.py]
The Django model is a thin store: status, delivery_type, and supplied_item_condition are plain CharFields, and extensions is an opaque JSONField. Enum values, validation, and the read/write schema split live in the Pydantic resource specs below.
Models
| Model | Purpose |
|---|---|
SupplyDelivery
|
A single line of delivered product (quantity, condition, source product/inventory) |
DeliveryOrder
|
Groups deliveries for a shipment between an origin and destination |
Both extend EMRBaseModel, which supplies external_id, the created_by/updated_by and created_date/modified_date audit fields, soft-delete via deleted, and history/meta JSON.
SupplyDelivery fields
Delivered item & quantity
| Field | Type | Notes |
|---|---|---|
supplied_item |
FK → Product (CASCADE) |
Nullable. The product delivered. Required at the API layer only when the order has no origin (external delivery); scoped to order.destination.facility on write
|
supplied_inventory_item |
FK → InventoryItem (CASCADE) |
Nullable. Specific inventory item (batch/lot) drawn from. Required at the API layer when the order has an origin (intra-facility move); scoped to order.origin.facility
|
supplied_item_quantity |
DecimalField(max_digits=20, decimal_places=6) |
Nullable in DB. On write a Decimal with decimal_places=0 (whole units); on read serialized as int. Auto-derived as pack_quantity × pack_size when both are given
|
supplied_item_pack_quantity |
IntegerField |
Nullable; default None. Number of packs delivered
|
supplied_item_pack_size |
IntegerField |
Nullable; default None. Units per pack
|
supplied_item_condition |
CharField(255) |
Optional. Condition of the delivered item — enum SupplyDeliveryConditionOptions (see below)
|
Status & classification
| Field | Type | Notes |
|---|---|---|
status |
CharField(255) |
Required. Lifecycle state — enum SupplyDeliveryStatusOptions (see below)
|
delivery_type |
CharField(255) |
Enum SupplyDeliveryTypeOptions (product / device). Stored on the model but not exposed on the current Create/Update specs, so it can't be set through the API
|
Links & pricing
| Field | Type | Notes |
|---|---|---|
supply_request |
FK → SupplyRequest (CASCADE) |
Nullable. Request this delivery fulfils. Set by external_id on write
|
order |
FK → DeliveryOrder (CASCADE) |
Nullable in DB, but required on create (referenced by external_id). Optional on update
|
total_purchase_price |
DecimalField(max_digits=20, decimal_places=6) |
Nullable. Total purchase cost. Spec: Decimal max_digits=20, decimal_places=6
{{Field|model=SupplyDelivery|section=Links & pricing|name=extensions|type=JSONField|notes=Default |
SupplyDelivery enum values
These are str enums in spec.py — the stored value equals the member value (snake_case), not a FHIR URI.
SupplyDeliveryStatusOptions (status)
| Value |
|---|
in_progress
|
completed
|
abandoned
|
entered_in_error
|
SupplyDeliveryConditionOptions (supplied_item_condition)
| Value |
|---|
normal
|
damaged
|
SupplyDeliveryTypeOptions (delivery_type)
| Value |
|---|
product
|
device
|
Related models
DeliveryOrder
A DeliveryOrder is one logical shipment. It groups its SupplyDelivery rows and moves stock between two facility locations, or from an external supplier into a facility.
supplier → FK Organization (CASCADE, nullable) -- external/source supplier
origin → FK FacilityLocation (CASCADE, nullable) -- related_name="origin_delivery_orders"
destination → FK FacilityLocation (CASCADE) -- related_name="destination_delivery_orders"
patient → FK Patient (PROTECT, nullable) -- patient the order is dispensed to
patient_invoice → FK Invoice (PROTECT, nullable) -- linked billing invoice
| Field | Type | Notes |
|---|---|---|
name |
CharField(255) |
Required. Human-readable order name |
status |
CharField(255) |
Required. Order lifecycle — enum SupplyDeliveryOrderStatusOptions (see below)
|
note |
TextField |
Nullable. Free-text note |
tags |
ArrayField[int] |
Default []. Tag IDs; rendered via SingleFacilityTagManager on read
|
supplier |
FK → Organization (CASCADE) |
Nullable. On write must be an Organization with org_type = product_supplier
|
origin |
FK → FacilityLocation (CASCADE) |
Nullable. Source location; absence means stock is entering from an external supplier
|
destination |
FK → FacilityLocation (CASCADE) |
Required. Receiving location |
patient |
FK → Patient (PROTECT) |
Nullable. Patient the order is dispensed to. Cannot be set together with origin
|
patient_invoice |
FK → Invoice (PROTECT) |
Nullable. Linked billing invoice; serialized as patient_invoice_id on read
|
extensions |
JSONField |
Default {}. Validated for ExtensionResource.supply_delivery_order
|
patient and patient_invoice use PROTECT: a referenced patient or invoice can't be deleted while a delivery order points to it.
SupplyDeliveryOrderStatusOptions (status)
| Value | Notes |
|---|---|
draft
|
Allowed on create |
pending
|
Allowed on create |
in_progress
|
|
completed
|
Terminal (in SUPPLY_DELIVERY_ORDER_COMPLETED_STATUSES)
|
abandoned
|
Terminal (in SUPPLY_DELIVERY_ORDER_COMPLETED_STATUSES)
|
entered_in_error
|
Terminal (in SUPPLY_DELIVERY_ORDER_COMPLETED_STATUSES)
|
Resource specs (API schema)
Every spec extends EMRResource ([https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/base.py base.py]): serialize builds the read payload from the DB object (perform_extra_serialization hook), de_serialize builds the DB object from the request (perform_extra_deserialization hook), and to_json() dumps the model excluding meta.
SupplyDelivery specs
| Spec | Role | Exposes / behaviour |
|---|---|---|
BaseSupplyDeliverySpec
|
shared | id, status (required), supplied_item_condition?, total_purchase_price?. __exclude__ = ["supplied_item", "supply_request", "supplied_inventory_item"] (these are resolved by hooks, not direct field copy)
|
SupplyDeliveryWriteSpec
|
write · create | Adds supplied_item_pack_quantity?, supplied_item_pack_size?, supplied_item_quantity (Decimal, decimal_places=0), supplied_item?, supplied_inventory_item?, supply_request?, order (required), extensions. Mixes in ExtensionValidator
|
SupplyDeliveryUpdateSpec
|
write · update | order? only (plus shared base fields + extensions). Mixes in ExtensionValidator
|
SupplyDeliveryReadSpec
|
read · list | supplied_item_quantity: int, created_date, modified_date, supplied_item_pack_quantity?, supplied_item_pack_size?, extensions, and nested objects supplied_item, supplied_inventory_item, supply_request, order (serialized as dict). Mixes in ExtensionListRenderer
|
SupplyDeliveryRetrieveSpec
|
read · detail | Extends SupplyDeliveryReadSpec; adds created_by/updated_by (UserSpec). Mixes in ExtensionRetrieveRenderer
|
Write validation (SupplyDeliveryWriteSpec):
validate_quantity: when bothsupplied_item_pack_quantityandsupplied_item_pack_sizeare set,supplied_item_quantityis overwritten with their product.validate_supplied_item(resolvesorderfromexternal_id):- if
order.originis set →supplied_inventory_itemis required (intra-facility stock move); - if
order.originis not set →supplied_itemis required (external delivery); supplied_itemandsupplied_inventory_itemcannot both be provided.
- if
perform_extra_deserialization: resolvesorderbyexternal_id; resolvessupplied_itemscoped toorder.destination.facility; iforder.originexists, resolvessupplied_inventory_itemscoped toorder.origin.facility; resolvessupply_requestbyexternal_id.
Update (SupplyDeliveryUpdateSpec): perform_extra_deserialization re-resolves order from external_id only when order is provided.
Read serialization: perform_extra_serialization sets id = external_id and inlines related objects via their read specs — supplied_item → ProductReadSpec, supplied_inventory_item → InventoryItemReadSpec, supply_request → SupplyRequestReadSpec, order → SupplyDeliveryOrderReadSpec.
DeliveryOrder specs
| Spec | Role | Exposes / behaviour |
|---|---|---|
BaseSupplyDeliveryOrderSpec
|
shared | id, status (required), name (required), note?. Mixes in ExtensionValidator
|
SupplyDeliveryOrderWriteSpec
|
write · create/update | Adds supplier?, origin?, destination (required), patient? (all by external_id)
|
SupplyDeliveryOrderReadSpec
|
read · list | Nested origin?, destination, supplier?, patient? (dict), tags, patient_invoice_id?, created_date, modified_date, created_by?, updated_by?. Mixes in ExtensionListRenderer
|
SupplyDeliveryOrderRetrieveSpec
|
read · detail | Extends SupplyDeliveryOrderReadSpec (no extra fields). Mixes in ExtensionRetrieveRenderer
|
Write validation (SupplyDeliveryOrderWriteSpec.perform_extra_deserialization):
- resolves
destination(required),origin?,patient?byexternal_id; - resolves
supplier?constrained toorg_type = product_supplier; patientandorigincannot be provided together;- on create the
statusmust bedraftorpending.
Read serialization: id = external_id; inlines origin/destination via FacilityLocationListSpec, supplier via OrganizationReadSpec, patient via PatientListSpec; renders tags via SingleFacilityTagManager; exposes the linked invoice as patient_invoice_id (string); attaches audit users.
Extensions
extensions is not free-form JSON. On write, ExtensionValidator runs each registered handler for the resource type (supply_delivery / supply_delivery_order): unknown keys are dropped, and known keys are validated and re-serialized. On read, ExtensionListRenderer / ExtensionRetrieveRenderer render every registered extension for the resource (list vs retrieve variants).
API integration notes
- Coded fields carry the snake_case enum values above (e.g.
status = "in_progress"), not FHIR URIs. Validate against the enum, not free text. - A delivery is created against a
DeliveryOrder(orderis required on create). The order'sorigindecides whether you sendsupplied_inventory_item(intra-facility) orsupplied_item(external) — never both. - Send
supplied_item_pack_quantity+supplied_item_pack_sizeto havesupplied_item_quantitycomputed server-side; otherwise sendsupplied_item_quantitydirectly (whole units). - A
DeliveryOrdermust start indraftorpending;completed/abandoned/entered_in_errorare terminal. patientandoriginare mutually exclusive on an order (patient dispense vs location-to-location move).extensionsholds deployment-specific data, but only registered extension keys are persisted.
Related
Pages that link here:
- Reference: References/Invoice