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

References/Facility Config

From OHC Network Wiki
Revision as of 04:15, 5 July 2026 by Admin (talk | contribs) (OHC identity seed)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
referencefacilityCARE 3.0+

Holds one facility's billing configuration: a discount-code catalog, discount component definitions, a discount-stacking rule, and the invoice-number template. The Django model FacilityMonetoryConfig stores all of it, but three fields are plain JSONFields whose shape, enums, and validation live in the Pydantic specs that drive the API. Both layers are documented here.

Sources:

Models

Model Purpose
FacilityMonetoryConfig Per-facility billing config: facility-scoped discount codes, discount monetary component definitions, a discount-stacking rule, and the invoice-number expression

FacilityMonetoryConfig extends EMRBaseModel, so it inherits external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and the history/meta JSON fields.

FacilityMonetoryConfig fields

Field Type Required Default Notes
facility OneToOneField → Facility yes
discount_codes JSONField → list[Coding] no
discount_monetary_components JSONField → list[MonetaryComponentDefinition] no
discount_configuration JSONField → DiscountConfiguration no
invoice_number_expression CharField(1000) no

discount_codes, discount_monetary_components, and discount_configuration are declared as plain JSONFields. The database accepts any JSON — their structure is enforced only at the API layer by the Pydantic specs below.

JSON field shapes

Coding shape

Each discount_codes[] entry is a Coding object (model_config = extra="forbid", so unknown keys are rejected).

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

MonetaryComponentDefinition shape

Each discount_monetary_components[] entry subclasses MonetaryComponent and adds title. Definition mode overrides or disables the base duplicate-code and amount-or-factor checks, but rejects a base-typed component outright.

Field Type Required Default Notes
title str yes
monetary_component_type MonetaryComponentType enum yes
code Coding no
factor Decimal no
amount Decimal no
tax_included_amount Decimal no
global_component bool no
conditions list[EvaluatorConditionSpec] no

EvaluatorConditionSpec (each conditions[] entry):

Field Type Required Notes
metric str yes
operation str yes
value dict yes

DiscountConfiguration shape

The discount_configuration object.

Field Type Required Notes
max_applicable int (ge=0) yes
applicability_order DiscountApplicability enum yes

Enum values

MonetaryComponentType values

From care/emr/resources/common/monetary_component.py. String enum.

Value Meaning
base Base price (not allowed in a MonetaryComponentDefinition)
surcharge Additional charge
discount Discount line item
tax Tax line item
informational Informational-only component

DiscountApplicability values

From care/emr/resources/common/monetary_component.py. String enum.

Value Meaning
total_asc Apply discounts in ascending order of total
total_desc Apply discounts in descending order of total

Resource specs (API schema)

These Pydantic specs build on EMRResource (serialize/de_serialize, the perform_extra_serialization/perform_extra_deserialization hooks, __model__, __exclude__) 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.

Spec Role Bound to Notes
FacilityMonetaryCodeSpec write · set monetary config FacilityMonetoryConfig Validates and persists discount_codes, discount_monetary_components, discount_configuration in one payload. de_serialized onto the get-or-created config row
FacilityInvoiceExpressionSpec write · set invoice expression (plain BaseModel) Single field invoice_number_expression; validated by dry-run before save
FacilityRetrieveSpec read · facility detail Facility Surfaces the facility's monetary config plus instance-level catalogs in perform_extra_serialization
MonetaryComponentDefinition nested (write) Shape of each discount_monetary_components[] entry
DiscountConfiguration nested (write) Shape of discount_configuration
Coding nested (write) Shape of each discount_codes[] entry

FacilityMonetaryCodeSpec

__model__ = FacilityMonetoryConfig, __exclude__ = []. Write schema for the set_monetary_config action.

Field Type Notes
discount_codes list[Coding] Facility-defined codes
discount_monetary_components list[MonetaryComponentDefinition] Selectable discount definitions
discount_configuration DiscountConfiguration Stacking rule

Model validators run on write:

  • Count limitsdiscount_codes and discount_monetary_components must each hold fewer than 100 entries (DISCOUNT_CODE_COUNT_LIMIT / DISCOUNT_MONETARY_COMPONENT_COUNT_LIMIT = 100; the check rejects >= 100).
  • No duplicate codescode values within discount_codes must be unique.
  • No redefining system codes — a facility code may not reuse a [code, system] pair already in instance settings.DISCOUNT_CODES.
  • All component codes must be defined — every discount_monetary_components[i].code (when present) must match a [code, system] pair from either settings.DISCOUNT_CODES (instance) or the facility's discount_codes.

FacilityInvoiceExpressionSpec

Plain BaseModel, not an EMRResource. Write schema for the set_invoice_expression action.

Field Type Notes
invoice_number_expression str Validated via evaluate_invoice_dummy_expression(v); any exception raises "Invalid Expression". An empty value skips validation

The dry-run context supplies invoice_count=1234, current_year_yyyy=2025, current_year_yy=25. At runtime, evaluate_invoice_identifier_default_expression(facility) evaluates the stored expression against the live invoice count and current year.

FacilityRetrieveSpec (read path)

FacilityRetrieveSpec (extends FacilityReadSpec + FacilityPermissionsMixin) injects the monetary config into the facility detail response from perform_extra_serialization, calling FacilityMonetoryConfig.get_monetory_config(obj.id) (get-or-create). The monetary-config-derived fields on the read payload:

Field Source
invoice_number_expression config row
discount_codes config row (list[dict])
discount_monetary_components config row (list[dict])
discount_configuration null)
instance_discount_codes settings.DISCOUNT_CODES
instance_discount_monetary_components settings.DISCOUNT_MONETARY_COMPONENT_DEFINITIONS
instance_tax_codes settings.TAX_CODES
instance_tax_monetary_components settings.TAX_MONETARY_COMPONENT_DEFINITIONS
instance_informational_codes settings.INFORMATIONAL_MONETARY_CODES
flags obj.get_facility_flags()
patient_instance_identifier_configs PatientIdentifierConfigCache.get_instance_config()
patient_facility_identifier_configs PatientIdentifierConfigCache.get_facility_config(obj.id)

Facility codes layer on top of instance-level catalogs. The read payload returns both the facility's own discount_* fields and the instance_* settings-derived catalogs, while write-time validation stops a facility from redefining instance codes.

API integration

Both writes are detail actions on the facility viewset and require update authorization on the facility.

Action Method Request spec Behaviour
set_monetary_config POST (detail) FacilityMonetaryCodeSpec model_validate with context {is_update: True, object: <config>}, then de_serialize onto the get-or-created config, set updated_by, save(). Returns the facility retrieve payload
set_invoice_expression POST (detail) FacilityInvoiceExpressionSpec Sets invoice_number_expression on the get-or-created config, sets updated_by, save(). Returns the facility retrieve payload

Invoice number expression

invoice_number_expression is a string template evaluated by care.emr.utils.expression_evaluator.evaluate_expression. It can reference:

Variable Source
invoice_count count of Invoice rows for the facility
current_year_yyyy four-digit current year
current_year_yy two-digit current year (year % 100)

A null/empty expression evaluates to "", producing no number.

Methods & save behaviour

FacilityMonetoryConfig caches derived data in the Django cache and rebuilds it on every write.

Cache keys

Key Built by
facility:{facility_id}:monetory_component get_monetory_component_cache_key(facility_id)
facility:{facility_id}:discount_configuration get_discount_configuration_cache_key(facility_id)

Class methods

  • get_monetory_config(facility_id) — 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.
  • get_component_key(component) — derives a component's lookup key as code.system + "/" + code.code.
  • calculate_monetory_components(components) — folds a component list into a dict keyed by get_component_key.
  • get_monetory_component(facility_id) — returns the cached component dict, computing it from discount_monetary_components and caching it on a miss.
  • get_discount_configuration(facility_id) — returns the cached discount_configuration (default {}), caching it on a miss.

save() side effects

save() deletes both cache keys for the facility before calling super().save(). The next call to get_monetory_component() or get_discount_configuration() 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 get_monetory_config(facility_id) rather than querying the table directly — the set_monetary_config / set_invoice_expression actions and FacilityRetrieveSpec all route through this get-or-create.
  • discount_codes, discount_monetary_components, and discount_configuration are opaque JSONFields at the DB layer; their shape and validation come from FacilityMonetaryCodeSpec and the nested Coding / MonetaryComponentDefinition / DiscountConfiguration specs.
  • Monetary components are keyed by a FHIR-style code.system/code.code pair (get_component_key); match on that derived key.
  • get_monetory_component() / get_discount_configuration() results are cache-backed and platform-maintained. Don't write to the cache keys directly — write the model and let save() invalidate them.

Pages that link here: