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

References/Charge Item Definition

From OHC Network Wiki
referencedefinitionsCARE 3.0+

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

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
version IntegerField
status CharField(255) yes
title CharField(255) yes
slug CharField(255) yes
derived_from_uri TextField no

Descriptive

Field Type Required Notes
description TextField no
purpose TextField no

Pricing & rules

Field Type Required Notes
price_components JSONField yes
discount_configuration JSONField no
can_edit_charge_item BooleanField yes
category FK → emr.ResourceCategory no
tags ArrayField[int]

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

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-

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):

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), 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.

Pages that link here: