Skip to main content
Version: 3.1

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:

Models

ModelPurpose
ChargeItemDefinitionFacility-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

FieldTypeRequiredNotes
facilityFK → facility.FacilityyesPROTECT — the owning facility cannot be deleted while definitions reference it
versionIntegerFieldDefault 1. Revision number; the spec surfaces it read-only
statusCharField(255)yesLifecycle status, constrained by ChargeItemDefinitionStatusOptions (draft, active, retired). See Status values
titleCharField(255)yesHuman-readable name
slugCharField(255)yesStored slug. The client sends slug_value; the server prefixes it (see slug behaviour)
derived_from_uriTextFieldnoNullable, default None. URI of the upstream definition this was derived from

Descriptive

FieldTypeRequiredNotes
descriptionTextFieldnoNullable, default None. Natural-language description
purposeTextFieldnoNullable, default None. Why the definition exists

Pricing & rules

FieldTypeRequiredNotes
price_componentsJSONFieldyesDefault []. List of MonetaryComponent — see Price components shape
discount_configurationJSONFieldnoNullable, default None. Shaped as DiscountConfiguration — see Discount configuration shape
can_edit_charge_itemBooleanFieldyesDefault True. Whether a charge item generated from this definition stays editable after creation
categoryFK → emr.ResourceCategorynoCASCADE, nullable. On write supplied as an ExtendedSlugType slug and resolved server-side
tagsArrayField[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.

ValueMeaning
draftNot yet active; excluded from live billing
activeIn use; only these should drive new charge items
retiredWithdrawn; excluded from live billing

Monetary component type values

MonetaryComponentType (common/monetary_component.py) sets the monetary_component_type of each price component.

ValueMeaning
baseThe base rate. Exactly one allowed; must carry an amount; may not have conditions or a factor
surchargeAn additive charge layered on the base
discountA reduction layered on the base
taxA tax component
informationalNon-priced informational component

Discount applicability values

DiscountApplicability (common/monetary_component.py) sets discount_configuration.applicability_order.

ValueMeaning
total_ascApply discounts in ascending order of total
total_descApply 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:

RuleDetail
tax_included_amount base-onlyAllowed only when monetary_component_type == base
base no conditionsA base component must have no conditions
base requires amountA base component must have an amount
amount xor factoramount and factor cannot both be present
amount or factor requiredOne 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 classRoleExposes / behaviour
ChargeItemDefinitionSpecshared baseid, status, title, derived_from_uri, description, purpose, price_components, can_edit_charge_item, discount_configuration. __exclude__ = []
ChargeItemDefinitionWriteSpecwrite · create + updateAdds slug_value: SlugType and `category: ExtendedSlugType
ChargeItemDefinitionReadSpecread · list + detailAdds 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_codes field validator): no two price_components may share the same (code.code, monetary_component_type) pair. Only components that carry a code are checked.
  • perform_extra_deserialization (ChargeItemDefinitionWriteSpec):
    • When category (slug) is supplied, resolves it via ResourceCategory.objects.get(slug=category) and sets obj.category.
    • Sets obj.slug = self.slug_value (the unprefixed value; the model's slug helpers prefix it — see below).

Read-spec serialization

  • perform_extra_serialization (ChargeItemDefinitionReadSpec):
    • idobj.external_id.
    • categoryResourceCategoryReadSpec.serialize(obj.category) when set.
    • slug_configobj.parse_slug(obj.slug) (decomposes the stored slug into {facility, slug_value} or {slug_value}).
    • tagsSingleFacilityTagManager().render_tags(obj).
    • created_by / updated_by ← serialized via serialize_audit_users.

Slug type constraints

TypeConstraints
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-

ChargeItemDefinition references two other models by foreign key:

facility → FK facility.Facility (PROTECT)
category → FK emr.ResourceCategory (CASCADE, nullable)
  • facility is protected: a facility cannot be deleted while definitions reference it.
  • category cascades: deleting the resource category removes the link.

Methods & save behaviour

ChargeItemDefinition overrides nothing of its own; slug behaviour comes from SlugBaseModel (FACILITY_SCOPED = True):

MethodBehaviour
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), and price_components mirror the FHIR MonetaryComponent shape.
  • Field names diverge between write and read: the client sends slug_value, not slug, and category is 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); only active definitions should drive new charge items.
  • can_edit_charge_item controls whether a derived charge item is mutable, not the definition itself.