Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

References/Product Knowledge: Difference between revisions

From OHC Network Wiki
Content deleted Content added
OHC identity seed
 
Automated edit (via update-page on MediaWiki MCP Server)
 
Line 379: Line 379:
* <code>facility</code> controls scope: omit it for instance-wide, set it for facility-local. Address records by slug (<code>i-&lt;slug&gt;</code> or <code>f-&lt;facility_external_id&gt;-&lt;slug&gt;</code>); the parsed parts come back as <code>slug_config</code>.
* <code>facility</code> controls scope: omit it for instance-wide, set it for facility-local. Address records by slug (<code>i-&lt;slug&gt;</code> or <code>f-&lt;facility_external_id&gt;-&lt;slug&gt;</code>); the parsed parts come back as <code>slug_config</code>.
* <code>code</code>, <code>names</code>, <code>storage_guidelines</code>, <code>definitional</code>, and <code>base_unit</code> carry their structure and value-set binding in the spec, not the model. <code>base_unit</code> is required.
* <code>code</code>, <code>names</code>, <code>storage_guidelines</code>, <code>definitional</code>, and <code>base_unit</code> carry their structure and value-set binding in the spec, not the model. <code>base_unit</code> is required.

{{Navbox definitions}}


{{Related}}
{{Related}}

Latest revision as of 09:36, 6 July 2026

referencedefinitionsCARE 3.0+

ProductKnowledge is the reusable definition of a product — its coding, base presentation unit, ingredients and nutrients, drug characteristics, and storage rules. Define it once and every concrete Product points back to it instead of carrying duplicate data. A definition is either instance-wide or scoped to a single facility.

The Django model is only the storage layer: code, names, storage_guidelines, definitional, and base_unit are opaque JSONFields whose real structure lives in the Pydantic resource specs. Every enum, nested JSON shape, validation rule, and read/write difference below comes from those specs.

Source:

Models

Model Purpose
ProductKnowledge Foundational, reusable definition of a product (medication, nutritional product, or consumable)

ProductKnowledge extends SlugBaseModel, which extends EMRBaseModel (the shared base providing external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON). SlugBaseModel sets FACILITY_SCOPED = True and adds the slug helpers calculate_slug and parse_slug, so a record is addressable by an instance slug (i-<slug>) or a facility slug (f-<facility_external_id>-<slug>).

ProductKnowledge fields

Identity & scope

Field Type Notes
facility FK → facility.Facility PROTECT, nullable. Null means an instance-level definition; set means facility-scoped. Excluded from the spec base (__exclude__ = ["facility"]); set on write via a facility UUID, surfaced on read as is_instance_level
slug CharField(255) Slug value; combined with facility to form the addressable slug. Set server-side from slug_value on write
alternate_identifier CharField(255) Nullable; secondary external identifier
status CharField(255) Lifecycle status. Spec-constrained to ProductKnowledgeStatusOptions (required)
product_type CharField(255) Product category. Spec-constrained to ProductTypeOptions (required)

{{Field|model=ProductKnowledge|section=Identity & scope|name=category|type=FK → emr.ResourceCategory|notes=CASCADE, nullable; classifies the product into a [[References/Resource Category}}

Naming

Field Type Notes
name CharField(255) Primary display name (required in spec)
names JSONField (list) Nullable; list of ProductName { name_type: ProductNameTypes, name: str }. name_type is bound to the ProductNameTypes enum, not a FHIR value set
names_cache CharField(2048) Nullable; denormalized space-joined string of name plus every names entry, rebuilt on each save() to power search. Platform-maintained, absent from every spec — never set it from clients

Coding & definition (JSON fields)

The model stores these as bare JSONFields; the spec enforces the shapes below.

Field Model type Spec type / shape Notes
code JSONField (dict) None Nullable; product code as a [[#coding
base_unit JSONField (dict) ValueSetBoundCoding[CARE_UCUM_UNITS] Required. A Coding bound to the UCUM units value set (system-ucum-units)
names JSONField (list) None See [[#productname
storage_guidelines JSONField (list) None See [[#storageguideline
definitional JSONField (dict) None Type-specific definition payload. See [[#productdefinitionspec

Enums

ProductTypeOptions (product_type)

Value
medication
nutritional_product
consumable

ProductKnowledgeStatusOptions (status)

Value
draft
active
retired
unknown

ProductNameTypes (names[].name_type)

Value
trade_name
alias
original_name
preferred

DrugCharacteristicCode (definitional.drug_characteristic[].code)

Value
imprint_code
size
shape
color
coating
scoring
logo
image

Nested spec shapes

These are plain Pydantic BaseModels in spec.py, not value-set bound unless noted.

ProductName

names[] — alternate names for the product.

Field Type Required Notes
name_type ProductNameTypes yes
name str yes

StorageGuideline

storage_guidelines[] — a storage note paired with a stability duration.

Field Type Required Notes
note str yes
stability_duration DurationSpec { value: int, unit: Coding } yes

ProductDefinitionSpec

definitional — type-specific definition payload.

Field Type Default Notes
dosage_form ValueSetBoundCoding[MEDICATION_FORM_CODES] required (nullable)
intended_routes list[Coding] []
ingredients list[ProductIngredient] []
nutrients list[ProductNutrient] []
drug_characteristic list[DrugCharacteristic] []

ProductIngredient

definitional.ingredients[].

Field Type Required Notes
is_active bool yes
substance ValueSetBoundCoding[CARE_SUBSTANCE_VALUSET] yes
strength ProductStrength yes

ProductNutrient

definitional.nutrients[].

Field Type Required Notes
item ValueSetBoundCoding[CARE_NUTRIENTS_VALUESET] yes
amount ProductStrength yes

ProductStrength

Shared by ProductIngredient.strength and ProductNutrient.amount.

Field Type Required Notes
ratio Ratio { numerator: Quantity, denominator: Quantity } yes
quantity Quantity yes

DrugCharacteristic

definitional.drug_characteristic[].

Field Type Required Notes
code DrugCharacteristicCode yes
value str yes

Shared common types

Coding

From care/emr/resources/common/coding.py (extra="forbid").

Field Type Required
system None no
version None no
code str yes
display None no

A ValueSetBoundCoding[<slug>] is a Coding subclass that additionally validates code against the named value set on deserialization.

Quantity

From care/emr/resources/common/quantity.py (extra="forbid").

Field Type Notes
value Decimal max 20 digits, 6 decimal places
unit Coding human-readable unit
code Coding machine-processable unit
meta dict

Ratio { numerator: Quantity, denominator: Quantity } — both required.

Resource specs (API schema)

Every spec builds on EMRResource (care/emr/resources/base.py), which provides serialize (DB → Pydantic), de_serialize (Pydantic → DB), and the perform_extra_serialization / perform_extra_deserialization hooks. EMRResource.serialize copies only non-FK database fields that are declared spec fields and not in __exclude__.

Spec class Role Adds / behaviour
BaseProductKnowledgeSpec shared base __exclude__ = ["facility"]. Fields: id, alternate_identifier, status, product_type, code, base_unit (required, UCUM-bound), name, names, storage_guidelines, definitional
ProductKnowledgeUpdateSpec write · update None (resource-category slug) and slug_value: SlugType (required). On deserialize, resolves category via ResourceCategory.objects.get(slug=...) and sets obj.slug = self.slug_value
ProductKnowledgeWriteSpec write · create None. On deserialize, runs the update-spec logic, then resolves facility via Facility.objects.get(external_id=...) when supplied
ProductKnowledgeReadSpec read · detail/list None, slug_config: dict, slug: str. On serialize, sets id = external_id, is_instance_level = not facility_id, serializes category via ResourceCategoryReadSpec, and sets slug_config = parse_slug(slug)

Validation & bound value sets

  • statusProductKnowledgeStatusOptions and product_typeProductTypeOptions, both required.
  • base_unit is required and bound to CARE_UCUM_UNITS (system-ucum-units, system http://unitsofmeasure.org).
  • definitional.dosage_form is bound to MEDICATION_FORM_CODES; ingredients[].substance to CARE_SUBSTANCE_VALUSET; nutrients[].item to CARE_NUTRIENTS_VALUESET. code and intended_routes stay free Codings.
  • slug_value uses SlugType: 5–50 chars, URL-safe (^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$), starting and ending alphanumeric.
  • category on write is a slug string; an unknown slug raises DoesNotExist from .get(...).

Server-maintained behaviour

  • facility never flows through the generic field loop (it sits in __exclude__); only ProductKnowledgeWriteSpec (create) sets it, from the facility UUID.
  • slug is set server-side from slug_value; names_cache is rebuilt in the model's save() (see below).
  • On read, is_instance_level, slug_config, and the serialized category are computed in perform_extra_serialization — none are stored columns.

Methods & save behaviour

save() side effects

save() rebuilds names_cache before persisting:

  1. names_cache is reset to "<name> ".
  2. For each entry in names, the entry's name (dict key or attribute) is appended, space-separated.
  3. super().save() persists the record, including the slug logic inherited from SlugBaseModel.

names_cache is platform-maintained — write to name and names instead of setting it directly.

API integration notes

  • Exposed through Care's REST API; aligns with the FHIR MedicationKnowledge and NutritionProduct concepts.
  • product_type decides what definitional means (medication, nutritional_product, or consumable).
  • facility controls scope: omit it for instance-wide, set it for facility-local. Address records by slug (i-<slug> or f-<facility_external_id>-<slug>); the parsed parts come back as slug_config.
  • code, names, storage_guidelines, definitional, and base_unit carry their structure and value-set binding in the spec, not the model. base_unit is required.

Pages that link here: