References/Facility Config: Difference between revisions
From OHC Network Wiki
More languages
More actions
Content deleted Content added
OHC identity seed |
Automated edit (via update-page on MediaWiki MCP Server) |
||
| Line 99: | Line 99: | ||
! Notes |
! Notes |
||
{{Field|model=FacilityConfig|section=MonetaryComponentDefinition shape|name=metric|type=str|notes='''yes'''}} |
{{Field|model=FacilityConfig|section=MonetaryComponentDefinition shape|name=metric|type=str|notes='''yes'''}} |
||
{{Field|model=FacilityConfig|section=MonetaryComponentDefinition shape|name=operation|type=str|notes='''yes'''}} |
|||
{{Field|model=FacilityConfig|section=MonetaryComponentDefinition shape|name=value|type=dict | str|notes='''yes'''}} |
|||
|} |
|||
... content truncated for display in this response but full source used in update ... |
|||
=== <code>DiscountConfiguration</code> shape === |
|||
{{Navbox facility}} |
|||
The <code>discount_configuration</code> object. |
|||
{| class="wikitable" |
|||
|- |
|||
! Field |
|||
! Type |
|||
! Required |
|||
! Notes |
|||
{{Field|model=FacilityConfig|section=DiscountConfiguration shape|name=max_applicable|type=int (ge=0)|notes='''yes'''}} |
|||
{{Field|model=FacilityConfig|section=DiscountConfiguration shape|name=applicability_order|type=DiscountApplicability enum|notes='''yes'''}} |
|||
|} |
|||
== Enum values == |
|||
=== <code>MonetaryComponentType</code> values === |
|||
From <code>care/emr/resources/common/monetary_component.py</code>. String enum. |
|||
{| class="wikitable" |
|||
|- |
|||
! Value |
|||
! Meaning |
|||
|- |
|||
| <code>base</code> |
|||
| Base price (not allowed in a <code>MonetaryComponentDefinition</code>) |
|||
|- |
|||
| <code>surcharge</code> |
|||
| Additional charge |
|||
|- |
|||
| <code>discount</code> |
|||
| Discount line item |
|||
|- |
|||
| <code>tax</code> |
|||
| Tax line item |
|||
|- |
|||
| <code>informational</code> |
|||
| Informational-only component |
|||
|} |
|||
=== <code>DiscountApplicability</code> values === |
|||
From <code>care/emr/resources/common/monetary_component.py</code>. String enum. |
|||
{| class="wikitable" |
|||
|- |
|||
! Value |
|||
! Meaning |
|||
|- |
|||
| <code>total_asc</code> |
|||
| Apply discounts in ascending order of total |
|||
|- |
|||
| <code>total_desc</code> |
|||
| Apply discounts in descending order of total |
|||
|} |
|||
== Resource specs (API schema) == |
|||
These Pydantic specs build on [[References/Base models & conventions|<code>EMRResource</code>]] (<code>serialize</code>/<code>de_serialize</code>, the <code>perform_extra_serialization</code>/<code>perform_extra_deserialization</code> hooks, <code>__model__</code>, <code>__exclude__</code>) and define how monetary config is written and read. There is no standard CRUD endpoint for it — writes go through dedicated facility detail actions, and reads come back inside the facility retrieve payload. |
|||
{| class="wikitable" |
|||
|- |
|||
! Spec |
|||
! Role |
|||
! Bound to |
|||
! Notes |
|||
|- |
|||
| <code>FacilityMonetaryCodeSpec</code> |
|||
| write · set monetary config |
|||
| <code>FacilityMonetoryConfig</code> |
|||
| Validates and persists <code>discount_codes</code>, <code>discount_monetary_components</code>, <code>discount_configuration</code> in one payload. <code>de_serialize</code>d onto the get-or-created config row |
|||
|- |
|||
| <code>FacilityInvoiceExpressionSpec</code> |
|||
| write · set invoice expression |
|||
| (plain <code>BaseModel</code>) |
|||
| Single field <code>invoice_number_expression</code>; validated by dry-run before save |
|||
|- |
|||
| <code>FacilityRetrieveSpec</code> |
|||
| read · facility detail |
|||
| <code>Facility</code> |
|||
| Surfaces the facility's monetary config plus instance-level catalogs in <code>perform_extra_serialization</code> |
|||
|- |
|||
| <code>MonetaryComponentDefinition</code> |
|||
| nested (write) |
|||
| — |
|||
| Shape of each <code>discount_monetary_components[]</code> entry |
|||
|- |
|||
| <code>DiscountConfiguration</code> |
|||
| nested (write) |
|||
| — |
|||
| Shape of <code>discount_configuration</code> |
|||
|- |
|||
| <code>Coding</code> |
|||
| nested (write) |
|||
| — |
|||
| Shape of each <code>discount_codes[]</code> entry |
|||
|} |
|||
=== <code>FacilityMonetaryCodeSpec</code> === |
|||
<code>__model__ = FacilityMonetoryConfig</code>, <code>__exclude__ = []</code>. Write schema for the <code>set_monetary_config</code> action. |
|||
{| class="wikitable" |
|||
|- |
|||
! Field |
|||
! Type |
|||
! Notes |
|||
{{Field|model=FacilityConfig|section=FacilityMonetaryCodeSpec|name=discount_codes|type=list[Coding]|notes=Facility-defined codes}} |
|||
{{Field|model=FacilityConfig|section=FacilityMonetaryCodeSpec|name=discount_monetary_components|type=list[MonetaryComponentDefinition]|notes=Selectable discount definitions}} |
|||
{{Field|model=FacilityConfig|section=FacilityMonetaryCodeSpec|name=discount_configuration|type=DiscountConfiguration | null|notes=Stacking rule}} |
|||
|} |
|||
Model validators run on write: |
|||
* '''Count limits''' — <code>discount_codes</code> and <code>discount_monetary_components</code> must each hold fewer than 100 entries (<code>DISCOUNT_CODE_COUNT_LIMIT</code> / <code>DISCOUNT_MONETARY_COMPONENT_COUNT_LIMIT = 100</code>; the check rejects <code>>= 100</code>). |
|||
* '''No duplicate codes''' — <code>code</code> values within <code>discount_codes</code> must be unique. |
|||
* '''No redefining system codes''' — a facility code may not reuse a <code>[code, system]</code> pair already in instance <code>settings.DISCOUNT_CODES</code>. |
|||
* '''All component codes must be defined''' — every <code>discount_monetary_components[i].code</code> (when present) must match a <code>[code, system]</code> pair from either <code>settings.DISCOUNT_CODES</code> (instance) or the facility's <code>discount_codes</code>. |
|||
=== <code>FacilityInvoiceExpressionSpec</code> === |
|||
Plain <code>BaseModel</code>, not an <code>EMRResource</code>. Write schema for the <code>set_invoice_expression</code> action. |
|||
{| class="wikitable" |
|||
|- |
|||
! Field |
|||
! Type |
|||
! Notes |
|||
{{Field|model=FacilityConfig|section=FacilityInvoiceExpressionSpec|name=invoice_number_expression|type=str|notes=Validated via <code>evaluate_invoice_dummy_expression(v)</code>; any exception raises <code>"Invalid Expression"</code>. An empty value skips validation}} |
|||
|} |
|||
The dry-run context supplies <code>invoice_count=1234</code>, <code>current_year_yyyy=2025</code>, <code>current_year_yy=25</code>. At runtime, <code>evaluate_invoice_identifier_default_expression(facility)</code> evaluates the stored expression against the live invoice count and current year. |
|||
=== <code>FacilityRetrieveSpec</code> (read path) === |
|||
<code>FacilityRetrieveSpec</code> (extends <code>FacilityReadSpec</code> + <code>FacilityPermissionsMixin</code>) injects the monetary config into the facility detail response from <code>perform_extra_serialization</code>, calling <code>FacilityMonetoryConfig.get_monetory_config(obj.id)</code> (get-or-create). The monetary-config-derived fields on the read payload: |
|||
{| class="wikitable" |
|||
|- |
|||
! Field |
|||
! Source |
|||
|- |
|||
| <code>invoice_number_expression</code> |
|||
| config row |
|||
|- |
|||
| <code>discount_codes</code> |
|||
| config row (<code>list[dict]</code>) |
|||
|- |
|||
| <code>discount_monetary_components</code> |
|||
| config row (<code>list[dict]</code>) |
|||
|- |
|||
| <code>discount_configuration</code> |
|||
| config row (<code>dict | null</code>) |
|||
|- |
|||
| <code>instance_discount_codes</code> |
|||
| <code>settings.DISCOUNT_CODES</code> |
|||
|- |
|||
| <code>instance_discount_monetary_components</code> |
|||
| <code>settings.DISCOUNT_MONETARY_COMPONENT_DEFINITIONS</code> |
|||
|- |
|||
| <code>instance_tax_codes</code> |
|||
| <code>settings.TAX_CODES</code> |
|||
|- |
|||
| <code>instance_tax_monetary_components</code> |
|||
| <code>settings.TAX_MONETARY_COMPONENT_DEFINITIONS</code> |
|||
|- |
|||
| <code>instance_informational_codes</code> |
|||
| <code>settings.INFORMATIONAL_MONETARY_CODES</code> |
|||
|- |
|||
| <code>flags</code> |
|||
| <code>obj.get_facility_flags()</code> |
|||
|- |
|||
| <code>patient_instance_identifier_configs</code> |
|||
| <code>PatientIdentifierConfigCache.get_instance_config()</code> |
|||
|- |
|||
| <code>patient_facility_identifier_configs</code> |
|||
| <code>PatientIdentifierConfigCache.get_facility_config(obj.id)</code> |
|||
|} |
|||
<blockquote>Facility codes layer on top of instance-level catalogs. The read payload returns both the facility's own <code>discount_*</code> fields and the <code>instance_*</code> settings-derived catalogs, while write-time validation stops a facility from redefining instance codes. |
|||
</blockquote> |
|||
== API integration == |
|||
Both writes are detail actions on the facility viewset and require update authorization on the facility. |
|||
{| class="wikitable" |
|||
|- |
|||
! Action |
|||
! Method |
|||
! Request spec |
|||
! Behaviour |
|||
|- |
|||
| <code>set_monetary_config</code> |
|||
| <code>POST</code> (detail) |
|||
| <code>FacilityMonetaryCodeSpec</code> |
|||
| <code>model_validate</code> with context <code>{is_update: True, object: <config>}</code>, then <code>de_serialize</code> onto the get-or-created config, set <code>updated_by</code>, <code>save()</code>. Returns the facility retrieve payload |
|||
|- |
|||
| <code>set_invoice_expression</code> |
|||
| <code>POST</code> (detail) |
|||
| <code>FacilityInvoiceExpressionSpec</code> |
|||
| Sets <code>invoice_number_expression</code> on the get-or-created config, sets <code>updated_by</code>, <code>save()</code>. Returns the facility retrieve payload |
|||
|} |
|||
== Invoice number expression == |
|||
<code>invoice_number_expression</code> is a string template evaluated by <code>care.emr.utils.expression_evaluator.evaluate_expression</code>. It can reference: |
|||
{| class="wikitable" |
|||
|- |
|||
! Variable |
|||
! Source |
|||
|- |
|||
| <code>invoice_count</code> |
|||
| count of <code>Invoice</code> rows for the facility |
|||
|- |
|||
| <code>current_year_yyyy</code> |
|||
| four-digit current year |
|||
|- |
|||
| <code>current_year_yy</code> |
|||
| two-digit current year (<code>year % 100</code>) |
|||
|} |
|||
A <code>null</code>/empty expression evaluates to <code>""</code>, producing no number. |
|||
== Methods & save behaviour == |
|||
<code>FacilityMonetoryConfig</code> caches derived data in the Django cache and rebuilds it on every write. |
|||
=== Cache keys === |
|||
{| class="wikitable" |
|||
|- |
|||
! Key |
|||
! Built by |
|||
|- |
|||
| <code>facility:{facility_id}:monetory_component</code> |
|||
| <code>get_monetory_component_cache_key(facility_id)</code> |
|||
|- |
|||
| <code>facility:{facility_id}:discount_configuration</code> |
|||
| <code>get_discount_configuration_cache_key(facility_id)</code> |
|||
|} |
|||
=== Class methods === |
|||
* <code>get_monetory_config(facility_id)</code> — returns the facility's config, creating an empty one if none exists. This get-or-create entry point backs both write actions and the retrieve serializer. |
|||
* <code>get_component_key(component)</code> — derives a component's lookup key as <code>code.system + "/" + code.code</code>. |
|||
* <code>calculate_monetory_components(components)</code> — folds a component list into a dict keyed by <code>get_component_key</code>. |
|||
* <code>get_monetory_component(facility_id)</code> — returns the cached component dict, computing it from <code>discount_monetary_components</code> and caching it on a miss. |
|||
* <code>get_discount_configuration(facility_id)</code> — returns the cached <code>discount_configuration</code> (default <code>{}</code>), caching it on a miss. |
|||
=== <code>save()</code> side effects === |
|||
<code>save()</code> deletes both cache keys for the facility before calling <code>super().save()</code>. The next call to <code>get_monetory_component()</code> or <code>get_discount_configuration()</code> recomputes from the persisted row, so the cache invalidates on write and rebuilds lazily on the next read. |
|||
== API integration notes == |
|||
* One config exists per facility. Read or auto-create it through <code>get_monetory_config(facility_id)</code> rather than querying the table directly — the <code>set_monetary_config</code> / <code>set_invoice_expression</code> actions and <code>FacilityRetrieveSpec</code> all route through this get-or-create. |
|||
* <code>discount_codes</code>, <code>discount_monetary_components</code>, and <code>discount_configuration</code> are opaque <code>JSONField</code>s at the DB layer; their shape and validation come from <code>FacilityMonetaryCodeSpec</code> and the nested <code>Coding</code> / <code>MonetaryComponentDefinition</code> / <code>DiscountConfiguration</code> specs. |
|||
* Monetary components are keyed by a FHIR-style <code>code.system</code>/<code>code.code</code> pair (<code>get_component_key</code>); match on that derived key. |
|||
* <code>get_monetory_component()</code> / <code>get_discount_configuration()</code> results are cache-backed and platform-maintained. Don't write to the cache keys directly — write the model and let <code>save()</code> invalidate them. |
|||
{{Related}} |
{{Related}} |
||