<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FProduct</id>
	<title>References/Product - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FProduct"/>
	<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Product&amp;action=history"/>
	<updated>2026-07-06T08:43:50Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.4</generator>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/Product&amp;diff=452&amp;oldid=prev</id>
		<title>Admin: Automated edit (via update-page on MediaWiki MCP Server)</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Product&amp;diff=452&amp;oldid=prev"/>
		<updated>2026-07-06T04:17:22Z</updated>

		<summary type="html">&lt;p&gt;Automated edit (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 09:47, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 182:&lt;/td&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 182:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &amp;lt;code&amp;gt;batch&amp;lt;/code&amp;gt; is a structured &amp;lt;code&amp;gt;{ lot_number }&amp;lt;/code&amp;gt;, not a free-form dict, even though the column is a &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt;.&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &amp;lt;code&amp;gt;batch&amp;lt;/code&amp;gt; is a structured &amp;lt;code&amp;gt;{ lot_number }&amp;lt;/code&amp;gt;, not a free-form dict, even though the column is a &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt;.&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Use &amp;lt;code&amp;gt;extensions&amp;lt;/code&amp;gt; for deployment-specific key-value data without a schema migration. Values are checked against the schemas registered for the &amp;lt;code&amp;gt;product&amp;lt;/code&amp;gt; extension resource.&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Use &amp;lt;code&amp;gt;extensions&amp;lt;/code&amp;gt; for deployment-specific key-value data without a schema migration. Values are checked against the schemas registered for the &amp;lt;code&amp;gt;product&amp;lt;/code&amp;gt; extension resource.&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Navbox supply}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;!-- diff cache key mediawiki:diff:1.41:old-178:rev-452:wikidiff2=table:1.14.2:bc2a06be --&gt;
&lt;/table&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/Product&amp;diff=178&amp;oldid=prev</id>
		<title>Admin: OHC identity seed</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Product&amp;diff=178&amp;oldid=prev"/>
		<updated>2026-07-04T22:45:48Z</updated>

		<summary type="html">&lt;p&gt;OHC identity seed&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Doc header&lt;br /&gt;
|type=reference&lt;br /&gt;
|domain=supply&lt;br /&gt;
|title=Product&lt;br /&gt;
|order=1&lt;br /&gt;
|introduced=3.0&lt;br /&gt;
|model=Product&lt;br /&gt;
|reference=References/Base models &amp;amp;amp; conventions&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; is a concrete batch of stock at a facility — a single lot of a medication, nutritional product, or consumable, with its own expiry, lot number, and purchase price. It instantiates a catalogue entry: everything generic about the item (name, codes, dosage form, &amp;lt;code&amp;gt;product_type&amp;lt;/code&amp;gt;) lives on the linked [[References/Product Knowledge|&amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt;]], and a &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; adds only what&amp;#039;s true of one batch.&lt;br /&gt;
&lt;br /&gt;
The Django model is storage; the shape you send and receive is defined by the Pydantic resource specs, which set the enums, narrow the model&amp;#039;s opaque &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt;s, enforce validation, and split read from write. The fields below note where the spec diverges from the column; [[#resource-specs-api-schema|Resource specs (API schema)]] covers the full read/write split.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Source:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Model: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/models/product.py &amp;lt;code&amp;gt;care/emr/models/product.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Spec: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/product/spec.py &amp;lt;code&amp;gt;care/emr/resources/inventory/product/spec.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
== Models ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Model&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt;&lt;br /&gt;
| A concrete, batch-level instantiation of a &amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt; definition at a facility (medication, nutritional product, or consumable)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; extends [[References/Base models &amp;amp;amp; conventions|&amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;]], which supplies &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;, audit fields, and soft-delete semantics.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; fields ==&lt;br /&gt;
&lt;br /&gt;
=== Relationships ===&lt;br /&gt;
&lt;br /&gt;
All three foreign keys are &amp;lt;code&amp;gt;PROTECT&amp;lt;/code&amp;gt;, so a referenced row can&amp;#039;t be deleted while a product points at it.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Product|section=Relationships|name=facility|type=FK → facility.Facility (PROTECT)|notes=Required at storage, but not a spec field — the viewset sets it from the URL, never the request body.}}&lt;br /&gt;
{{Field|model=Product|section=Relationships|name=product_knowledge|type=FK → emr.ProductKnowledge (PROTECT)|notes=The catalogue definition this batch instantiates. Write takes a &amp;lt;code&amp;gt;slug&amp;lt;/code&amp;gt; string and resolves it; read returns the nested [[References/Product Knowledge}}&lt;br /&gt;
{{Field|model=Product|section=Relationships|name=charge_item_definition|type=FK → emr.ChargeItemDefinition (PROTECT, nullable)|notes=Drives charge-item creation when the product is billed. Write takes a &amp;lt;code&amp;gt;slug&amp;lt;/code&amp;gt; string; read returns the nested [[References/Charge Item Definition}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Classification &amp;amp;amp; status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Product|section=Classification &amp;amp;amp; status|name=status|type=CharField(255)|notes=yes (spec)}}&lt;br /&gt;
{{Field|model=Product|section=Classification &amp;amp;amp; status|name=product_type|type=CharField(255)|notes=—}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Batch &amp;amp;amp; pricing ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Default&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Product|section=Batch &amp;amp;amp; pricing|name=batch|type=JSONField (nullable)|notes=no}}&lt;br /&gt;
{{Field|model=Product|section=Batch &amp;amp;amp; pricing|name=expiration_date|type=DateTimeField (nullable)|notes=no}}&lt;br /&gt;
{{Field|model=Product|section=Batch &amp;amp;amp; pricing|name=standard_pack_size|type=IntegerField (nullable)|notes=no}}&lt;br /&gt;
{{Field|model=Product|section=Batch &amp;amp;amp; pricing|name=purchase_price|type=DecimalField(max_digits=20, decimal_places=6) (nullable)|notes=no}}&lt;br /&gt;
{{Field|model=Product|section=Batch &amp;amp;amp; pricing|name=extensions|type=JSONField|notes=yes (spec)}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Enums ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;ProductStatusOptions&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
Defined in [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/product/spec.py &amp;lt;code&amp;gt;spec.py&amp;lt;/code&amp;gt;] and bound to the model &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;active&amp;lt;/code&amp;gt;&lt;br /&gt;
| Product is in use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;inactive&amp;lt;/code&amp;gt;&lt;br /&gt;
| Product is no longer in use but retained&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;entered_in_error&amp;lt;/code&amp;gt;&lt;br /&gt;
| Record created in error&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;ProductTypeOptions&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
Not a field on the &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; spec. It&amp;#039;s defined in [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/product_knowledge/spec.py &amp;lt;code&amp;gt;product_knowledge/spec.py&amp;lt;/code&amp;gt;] and carried on the linked [[References/Product Knowledge|&amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt;]]; it appears here only because the model keeps a &amp;lt;code&amp;gt;product_type&amp;lt;/code&amp;gt; storage column.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;medication&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nutritional_product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;consumable&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Nested JSON shapes ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;ProductBatch&amp;lt;/code&amp;gt; shape ===&lt;br /&gt;
&lt;br /&gt;
Structure of the &amp;lt;code&amp;gt;batch&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;care/emr/resources/inventory/product/spec.py&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Default&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Product|section=ProductBatch shape|name=lot_number|type=str | None|notes=no}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Resource specs (API schema) ==&lt;br /&gt;
&lt;br /&gt;
Every spec derives from &amp;lt;code&amp;gt;EMRResource&amp;lt;/code&amp;gt; ([&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/base.py &amp;lt;code&amp;gt;care/emr/resources/base.py&amp;lt;/code&amp;gt;]), which supplies &amp;lt;code&amp;gt;serialize&amp;lt;/code&amp;gt; (DB → pydantic, via the &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt; hook) and &amp;lt;code&amp;gt;de_serialize&amp;lt;/code&amp;gt; (pydantic → DB, via the &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; hook).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Spec class&lt;br /&gt;
! Role&lt;br /&gt;
! Fields beyond the base&lt;br /&gt;
! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseProductSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| shared&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;batch&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;expiration_date&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;extensions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;standard_pack_size&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;purchase_price&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;__model__ = Product&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;__exclude__ = [&amp;amp;quot;product_knowledge&amp;amp;quot;, &amp;amp;quot;charge_item_definition&amp;amp;quot;]&amp;lt;/code&amp;gt; — these FKs are resolved by the hooks, not by automatic field mapping. &amp;lt;code&amp;gt;___extension_resource_type__ = ExtensionResource.product&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ProductWriteSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · create&lt;br /&gt;
| adds &amp;lt;code&amp;gt;product_knowledge: str&amp;lt;/code&amp;gt; (slug), &amp;lt;code&amp;gt;charge_item_definition: str | None&amp;lt;/code&amp;gt; (slug)&lt;br /&gt;
| Mixes in &amp;lt;code&amp;gt;ExtensionValidator&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; resolves &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; via &amp;lt;code&amp;gt;get_object_or_404(ProductKnowledge, slug=...)&amp;lt;/code&amp;gt; and, when present, &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; via &amp;lt;code&amp;gt;get_object_or_404(ChargeItemDefinition, slug=...)&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ProductUpdateSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · update&lt;br /&gt;
| adds &amp;lt;code&amp;gt;charge_item_definition: str | None&amp;lt;/code&amp;gt; (slug)&lt;br /&gt;
| Mixes in &amp;lt;code&amp;gt;ExtensionValidator&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; resolves &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; via &amp;lt;code&amp;gt;ChargeItemDefinition.objects.get(slug=...)&amp;lt;/code&amp;gt; when supplied. &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; is immutable after create, so it is not re-bound.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ProductReadSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| read · list &amp;amp;amp; detail&lt;br /&gt;
| adds &amp;lt;code&amp;gt;product_knowledge: dict&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;charge_item_definition: dict | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt; sets &amp;lt;code&amp;gt;id = external_id&amp;lt;/code&amp;gt; and inlines &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; (via &amp;lt;code&amp;gt;ProductKnowledgeReadSpec&amp;lt;/code&amp;gt;) and, when set, &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; (via &amp;lt;code&amp;gt;ChargeItemDefinitionReadSpec&amp;lt;/code&amp;gt;). One spec serves both list and detail.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consequences for an integrator:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;product_type&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; never appear in the request or response. &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; comes from the route; &amp;lt;code&amp;gt;product_type&amp;lt;/code&amp;gt; comes from &amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; go out as slug strings and come back as fully serialized nested objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;extensions&amp;lt;/code&amp;gt; is validated on write against the JSON schemas registered for &amp;lt;code&amp;gt;ExtensionResource.product&amp;lt;/code&amp;gt;. Keys with no registered handler are silently dropped — current behaviour, with a TODO to make it an error.&lt;br /&gt;
* There is no server-side &amp;lt;code&amp;gt;status_history&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; does not track status changes.&lt;br /&gt;
* The base &amp;lt;code&amp;gt;de_serialize&amp;lt;/code&amp;gt; dumps with &amp;lt;code&amp;gt;exclude_defaults=True&amp;lt;/code&amp;gt;, so unset optional fields never reach the model.&lt;br /&gt;
&lt;br /&gt;
== Methods &amp;amp;amp; save behaviour ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; adds no methods of its own. Persistence, &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;, audit fields, and soft delete all come from &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Write:&amp;#039;&amp;#039;&amp;#039; request body → &amp;lt;code&amp;gt;ProductWriteSpec&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ProductUpdateSpec&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;de_serialize&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; (FK slug resolution) → &amp;lt;code&amp;gt;obj.save()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Read:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; row → &amp;lt;code&amp;gt;ProductReadSpec.serialize&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt; (inline &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt;) → JSON.&lt;br /&gt;
* &amp;lt;code&amp;gt;PROTECT&amp;lt;/code&amp;gt; on every FK blocks deletion of a referenced &amp;lt;code&amp;gt;Facility&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;ChargeItemDefinition&amp;lt;/code&amp;gt; while products still reference it.&lt;br /&gt;
&lt;br /&gt;
== API integration notes ==&lt;br /&gt;
&lt;br /&gt;
* A &amp;lt;code&amp;gt;Product&amp;lt;/code&amp;gt; carries batch data only. Pull name, codes, dosage form, and &amp;lt;code&amp;gt;product_type&amp;lt;/code&amp;gt; from the linked [[References/Product Knowledge|&amp;lt;code&amp;gt;ProductKnowledge&amp;lt;/code&amp;gt;]] — they aren&amp;#039;t duplicated here.&lt;br /&gt;
* Send &amp;lt;code&amp;gt;product_knowledge&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; as slugs on write; both return as full nested objects on read.&lt;br /&gt;
* Set &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt; to wire the product into billing — charge items are created automatically when it&amp;#039;s billed.&lt;br /&gt;
* &amp;lt;code&amp;gt;batch&amp;lt;/code&amp;gt; is a structured &amp;lt;code&amp;gt;{ lot_number }&amp;lt;/code&amp;gt;, not a free-form dict, even though the column is a &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Use &amp;lt;code&amp;gt;extensions&amp;lt;/code&amp;gt; for deployment-specific key-value data without a schema migration. Values are checked against the schemas registered for the &amp;lt;code&amp;gt;product&amp;lt;/code&amp;gt; extension resource.&lt;br /&gt;
&lt;br /&gt;
{{Related}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>