Charge Item Definition
A charge item definition is a facility's pricing template for a billable resource: it answers "how much does resource X cost". It binds the resource to a set of price components — base rate, surcharges, discounts, and taxes — that get evaluated when a charge item is generated during data entry. You touch it when defining or revising the prices a facility charges.
The resource spans two layers. The Django model (care/emr/models/charge_item_definition.py) is storage: price_components and discount_configuration are opaque JSONFields with no structure of their own. The Pydantic specs (care/emr/resources/charge_item_definition/) are the API: they define the status enum, give those JSON fields a real shape via MonetaryComponent and DiscountConfiguration, enforce validation, and split the read and write schemas. See Resource specs (API schema).
Source:
- Model:
care/emr/models/charge_item_definition.py - Resource spec:
care/emr/resources/charge_item_definition/spec.py - Shared spec:
care/emr/resources/common/monetary_component.py
Models
| Model | Purpose |
|---|---|
ChargeItemDefinition | Facility-scoped pricing template defining the price components applied to a billable resource |
ChargeItemDefinition extends SlugBaseModel, the slug-aware Care EMR base, which itself extends EMRBaseModel. From that chain it inherits external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and the history/meta JSON fields, then adds facility-scoped slug helpers (see Methods & save behaviour).
ChargeItemDefinition fields
Identity & versioning
| Field | Type | Required | Notes |
|---|---|---|---|
facility | FK → facility.Facility | yes | PROTECT — the owning facility cannot be deleted while definitions reference it |
version | IntegerField | — | Default 1. Revision number; the spec surfaces it read-only |
status | CharField(255) | yes | Lifecycle status, constrained by ChargeItemDefinitionStatusOptions (draft, active, retired). See Status values |
title | CharField(255) | yes | Human-readable name |
slug | CharField(255) | yes | Stored slug. The client sends slug_value; the server prefixes it (see slug behaviour) |
derived_from_uri | TextField | no | Nullable, default None. URI of the upstream definition this was derived from |
Descriptive
| Field | Type | Required | Notes |
|---|---|---|---|
description | TextField | no | Nullable, default None. Natural-language description |
purpose | TextField | no | Nullable, default None. Why the definition exists |
Pricing & rules
| Field | Type | Required | Notes |
|---|---|---|---|
price_components | JSONField | yes | Default []. List of MonetaryComponent — see Price components shape |
discount_configuration | JSONField | no | Nullable, default None. Shaped as DiscountConfiguration — see Discount configuration shape |
can_edit_charge_item | BooleanField | yes | Default True. Whether a charge item generated from this definition stays editable after creation |
category | FK → emr.ResourceCategory | no | CASCADE, nullable. On write supplied as an ExtendedSlugType slug and resolved server-side |
tags | ArrayField[int] | — | Default []. Tag IDs on write; rendered to objects on read |
Enum values
Status values
ChargeItemDefinitionStatusOptions (spec.py) constrains status. The model CharField is unconstrained at the DB level, so the spec is the source of truth.
| Value | Meaning |
|---|---|
draft | Not yet active; excluded from live billing |
active | In use; only these should drive new charge items |
retired | Withdrawn; excluded from live billing |
Monetary component type values
MonetaryComponentType (common/monetary_component.py) sets the monetary_component_type of each price component.
| Value | Meaning |
|---|---|
base | The base rate. Exactly one allowed; must carry an amount; may not have conditions or a factor |
surcharge | An additive charge layered on the base |
discount | A reduction layered on the base |
tax | A tax component |
informational | Non-priced informational component |
Discount applicability values
DiscountApplicability (common/monetary_component.py) sets discount_configuration.applicability_order.
| Value | Meaning |
|---|---|
total_asc | Apply discounts in ascending order of total |
total_desc | Apply discounts in descending order of total |
JSON field shapes
Price components shape
price_components is a list[MonetaryComponent]. Each entry (common/monetary_component.py):
MonetaryComponent {
monetary_component_type : MonetaryComponentType # required; see enum above
code : Coding | null # billing code (system/version/code/display); code required if present
factor : Decimal | null # max_digits=20, decimal_places=6
amount : Decimal | null # max_digits=20, decimal_places=6
tax_included_amount : Decimal | null # max_digits=20, decimal_places=6; base-only
global_component : bool # default false
conditions : list[EvaluatorConditionSpec] # default []
}
Coding (common/coding.py, extra="forbid"): { system: str|null, version: str|null, code: str (required), display: str|null }.
EvaluatorConditionSpec (common/condition_evaluator.py): { metric: str, operation: str, value: dict|str }. metric is validated against EvaluatorMetricsRegistry, and that metric's evaluator validates operation and value.
Each MonetaryComponent is checked against these rules:
| Rule | Detail |
|---|---|
tax_included_amount base-only | Allowed only when monetary_component_type == base |
| base no conditions | A base component must have no conditions |
| base requires amount | A base component must have an amount |
| amount xor factor | amount and factor cannot both be present |
| amount or factor required | One of amount/factor must be present — except when global_component is true and a code is set |
Discount configuration shape
discount_configuration is a DiscountConfiguration | null (common/monetary_component.py):
DiscountConfiguration {
max_applicable : int # required; >= 0
applicability_order : DiscountApplicability # required; total_asc | total_desc
}
Resource specs (API schema)
The API never serializes the Django model directly. It routes through Pydantic specs built on EMRResource (resources/base.py), which provide serialize (DB → API) and de_serialize (API → DB).
| Spec class | Role | Exposes / behaviour |
|---|---|---|
ChargeItemDefinitionSpec | shared base | id, status, title, derived_from_uri, description, purpose, price_components, can_edit_charge_item, discount_configuration. __exclude__ = [] |
ChargeItemDefinitionWriteSpec | write · create + update | Adds slug_value: SlugType and `category: ExtendedSlugType |
ChargeItemDefinitionReadSpec | read · list + detail | Adds read-only version, category: dict, slug_config: dict, tags: list[dict], slug: str, created_by, updated_by, created_date, updated_date |
These specs reuse several nested specs: MonetaryComponent (price component), DiscountConfiguration (discount rules), Coding (component code), and EvaluatorConditionSpec (component conditions).
Write-spec validation & side effects
- Duplicate (code, type) check (
check_components_with_duplicate_codesfield validator): no twoprice_componentsmay share the same(code.code, monetary_component_type)pair. Only components that carry acodeare checked. perform_extra_deserialization(ChargeItemDefinitionWriteSpec):- When
category(slug) is supplied, resolves it viaResourceCategory.objects.get(slug=category)and setsobj.category. - Sets
obj.slug = self.slug_value(the unprefixed value; the model's slug helpers prefix it — see below).
- When
Read-spec serialization
perform_extra_serialization(ChargeItemDefinitionReadSpec):id←obj.external_id.category←ResourceCategoryReadSpec.serialize(obj.category)when set.slug_config←obj.parse_slug(obj.slug)(decomposes the stored slug into{facility, slug_value}or{slug_value}).tags←SingleFacilityTagManager().render_tags(obj).created_by/updated_by← serialized viaserialize_audit_users.
Slug type constraints
| Type | Constraints |
|---|---|
SlugType (slug_value) | min_length=5, max_length=50; pattern ^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$ (URL-safe; alphanumeric start/end) |
ExtendedSlugType (category) | min_length=7, max_length=88; same pattern, and must start with f- or i- |
Related models
ChargeItemDefinition references two other models by foreign key:
facility → FK facility.Facility (PROTECT)
category → FK emr.ResourceCategory (CASCADE, nullable)
facilityis protected: a facility cannot be deleted while definitions reference it.categorycascades: deleting the resource category removes the link.
Methods & save behaviour
ChargeItemDefinition overrides nothing of its own; slug behaviour comes from SlugBaseModel (FACILITY_SCOPED = True):
| Method | Behaviour |
|---|---|
calculate_slug() | Returns f-{facility.external_id}-{slug} when facility-scoped with a facility, otherwise i-{slug} |
calculate_slug_from_facility(facility_external_id, slug) | Classmethod — builds a facility-scoped slug string |
calculate_slug_from_instance(slug) | Classmethod — builds an instance-scoped slug string |
parse_slug(slug) | Splits a stored slug back into {facility, slug_value} (facility-scoped, f- prefix) or {slug_value} (instance-scoped, i- prefix); validates the embedded facility UUID; raises on length <= 2 or an unknown prefix |
Because slugs are namespaced by the owning facility's external_id, the same slug_value (for example consultation-fee) can coexist across facilities without colliding.
API integration notes
- The structure is FHIR-aligned (
ChargeItemDefinition), andprice_componentsmirror the FHIRMonetaryComponentshape. - Field names diverge between write and read: the client sends
slug_value, notslug, andcategoryis a slug string on write but an object on read.slug_config,tags,category, and audit users are computed server-side and appear only on read. - The spec enum-gates
status(draft/active/retired); onlyactivedefinitions should drive new charge items. can_edit_charge_itemcontrols whether a derived charge item is mutable, not the definition itself.
Related
- Source: charge_item_definition.py on GitHub
- Spec: charge_item_definition/spec.py on GitHub
- Spec: common/monetary_component.py on GitHub
- Reference: Charge Item
- Reference: Invoice
- Reference: Account
- Reference: Resource Category
- Reference: Base Model