References/Facility Config
More languages
More actions
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:
- Model: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/facility_config.py
care/emr/models/facility_config.py] - Spec: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/facility/spec.py
care/emr/resources/facility/spec.py] - Monetary types: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/common/monetary_component.py
care/emr/resources/common/monetary_component.py] - Coding: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/common/coding.py
care/emr/resources/common/coding.py] - Expression evaluator: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/invoice/default_expression_evaluator.py
care/emr/resources/invoice/default_expression_evaluator.py] - API viewset: [https://github.com/ohcnetwork/care/blob/develop/care/emr/api/viewsets/facility.py
care/emr/api/viewsets/facility.py]
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, anddiscount_configurationare declared as plainJSONFields. 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 limits —
discount_codesanddiscount_monetary_componentsmust each hold fewer than 100 entries (DISCOUNT_CODE_COUNT_LIMIT/DISCOUNT_MONETARY_COMPONENT_COUNT_LIMIT = 100; the check rejects>= 100). - No duplicate codes —
codevalues withindiscount_codesmust be unique. - No redefining system codes — a facility code may not reuse a
[code, system]pair already in instancesettings.DISCOUNT_CODES. - All component codes must be defined — every
discount_monetary_components[i].code(when present) must match a[code, system]pair from eithersettings.DISCOUNT_CODES(instance) or the facility'sdiscount_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 theinstance_*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 ascode.system + "/" + code.code.calculate_monetory_components(components)— folds a component list into a dict keyed byget_component_key.get_monetory_component(facility_id)— returns the cached component dict, computing it fromdiscount_monetary_componentsand caching it on a miss.get_discount_configuration(facility_id)— returns the cacheddiscount_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 — theset_monetary_config/set_invoice_expressionactions andFacilityRetrieveSpecall route through this get-or-create. discount_codes,discount_monetary_components, anddiscount_configurationare opaqueJSONFields at the DB layer; their shape and validation come fromFacilityMonetaryCodeSpecand the nestedCoding/MonetaryComponentDefinition/DiscountConfigurationspecs.- Monetary components are keyed by a FHIR-style
code.system/code.codepair (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 letsave()invalidate them.
Related
Pages that link here:
- Reference: References/Base models & conventions