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

References/Account

From OHC Network Wiki
referencebillingCARE 3.0+

An Account is the financial bucket that aggregates every transaction made against a patient within a facility. You touch it indirectly: charge items land on a patient's default account, and invoices and reconciliations settle against it.

Several model fields are opaque JSONFields whose real structure lives in the Pydantic resource specs under care/emr/resources/account/. Each field below is paired with the spec-defined enums, JSON shapes, validation, and read/write schemas that govern it.

Source code

The files below are fetched live from the care repository — any changes pushed to the repo will show here automatically:

Model

Spec



Default account helper

Balance sync

Base resource





Models

Model Purpose
Account Aggregates charges and balances for one patient in one facility across encounters

Account extends EMRBaseModel, which contributes external_id, the audit fields created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON.

Accounts are perpetual. One active, open account exists per patient per facility (see get_default_account), and charge items land on it. After discharge, the account can be balanced and closed. Invoices are raised against an account or against the items within it.

Account fields

Identity & scope

Field Type Required Notes
facility FK → facility.Facility (PROTECT) yes
patient FK → emr.Patient (PROTECT) yes
name CharField(255) yes
description TextField no
primary_encounter FK → emr.Encounter (SET_NULL, nullable) no

Status

Field Type Required Notes
status CharField(255) yes
billing_status CharField(255) yes
service_period JSONField (default {}) yes (on spec)

Balances & totals

These decimal totals (max_digits=20, decimal_places=6, default 0) are platform-maintained aggregates that sync_account_items recomputes. None are client-writable, and none appear on a write spec.

Field Type Notes
total_net DecimalField Net total before adjustments. Not populated — the sync_account_items logic is commented out, so it holds the default 0
total_gross DecimalField Sum of total_price over charge items in paid or billed status
total_paid DecimalField Sum of active+complete payment reconciliations, minus credit-note reconciliations
total_balance DecimalField total_gross − total_paid
total_billable_charge_items DecimalField Sum of total_price over charge items in billable status
total_price_components JSONField (default {}) Intended price-component breakdown (taxes, discounts, etc.) as a list of MonetaryComponent (see MonetaryComponent shape
cached_items JSONField (default {}) Denormalized snapshot of the account's charge items, serialized as a list on retrieve. Not populated — the sync logic is commented out
calculated_at DateTimeField (nullable) When the balances were last computed; set to care_now() on each sync

Tags & extensions

Field Type Notes
tags ArrayField[int] (default []) Tag IDs applied to the account; rendered through SingleFacilityTagManager on read
extensions JSONField (default {}) Open bag for deployment-specific metadata. ExtensionValidator checks it against ExtensionResource.account; surfaced only on the retrieve spec

Enum values

AccountStatusOptions values

Stored as the raw enum value string in status.

Value Meaning
active Open and in use (the default-account state)
inactive No longer actively used
entered_in_error Created in error
on_hold Temporarily paused

Values use underscores (entered_in_error, on_hold), not the FHIR-style hyphenated forms.

AccountBillingStatusOptions values

Stored as the raw enum value string in billing_status.

Value Meaning
open Billing open and accruing (the default-account state)
carecomplete_notbilled Care complete, not yet billed
billing Billing in progress
closed_baddebt Closed as bad debt
closed_voided Closed and voided
closed_completed Closed, billing completed
closed_combined Closed, combined into another account

JSON field shapes

service_period shape

service_period stores a PeriodSpec (from [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/base.py resources/base.py]):

PeriodSpec {
  start: datetime | null   # ISO 8601, timezone-aware
  end:   datetime | null   # ISO 8601, timezone-aware
}

PeriodSpec.validate_period enforces three rules:

  • start, if present, must be timezone-aware — a naive datetime raises "Start Date must be timezone aware".
  • end, if present, must be timezone-aware — "End Date must be timezone aware".
  • With both present, start <= end, or "Start Date cannot be greater than End Date".

The default account sets only start, formatted as "%Y-%m-%dT%H:%M:%S.%fZ" from care_now().

The FHIR-style [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/common/period.py Period] common type ({ id?, start?, end? }, extra="forbid") is a related but distinct shape — Account binds service_period to PeriodSpec, not Period.

MonetaryComponent shape

total_price_components is meant to hold a list of [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/common/monetary_component.py MonetaryComponent] entries, the same shape used across billing:

MonetaryComponent {
  monetary_component_type: base | surcharge | discount | tax | informational
  code:                    Coding | null
  factor:                  Decimal(max_digits=20, decimal_places=6) | null
  amount:                  Decimal(max_digits=20, decimal_places=6) | null
  tax_included_amount:     Decimal(max_digits=20, decimal_places=6) | null
  global_component:        bool = false
  conditions:              EvaluatorConditionSpec[] = []
}

MonetaryComponent validation: tax_included_amount is allowed only on a base component; a base component must carry an amount, no factor, and no conditions; amount and factor are mutually exclusive; exactly one of amount/factor is required unless the entry is a global_component with a code.

Resource specs (API schema)

The API layer lives in [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/account/spec.py resources/account/spec.py]. Every spec builds on EMRResource (serialize / de_serialize, with the perform_extra_serialization / perform_extra_deserialization hooks). AccountSpec sets __exclude__ = ["patient"] and binds ___extension_resource_type__ = ExtensionResource.account.

Spec class Role Fields exposed (beyond base)
AccountSpec shared base id, status, billing_status, name, service_period (PeriodSpec), description
AccountCreateSpec write · create base + patient (UUID, required)
AccountUpdateSpec write · update base + primary_encounter (UUID, optional)
AccountMinimalReadSpec read · minimal base + total_gross, total_paid, total_balance, total_billable_charge_items (all Decimal 20/6), calculated_at, created_date, modified_date
AccountReadSpec read · list minimal + patient (serialized PatientListSpec), tags (rendered tag dicts)
AccountRetrieveSpec read · detail read + patient (serialized PatientRetrieveSpec), primary_encounter (serialized EncounterRetrieveSpec when set), cached_items (list), total_price_components (dict), extensions (dict)

Validation & server-side behaviour

  • Create (AccountCreateSpec): mixes in ExtensionValidator to validate extensions, and requires patient as a UUID. perform_extra_deserialization resolves it via get_object_or_404(Patient, external_id=...) and assigns obj.patient; patient is otherwise excluded from the base serialize loop.
  • Update (AccountUpdateSpec): mixes in ExtensionValidator; primary_encounter is optional. When supplied, perform_extra_deserialization resolves it via get_object_or_404(Encounter, external_id=...) and assigns obj.primary_encounter.
  • Status / billing_status: the Pydantic enums AccountStatusOptions / AccountBillingStatusOptions reject any value outside their members.
  • Read serialization: perform_extra_serialization sets mapping["id"] = obj.external_id. AccountReadSpec serializes the patient (PatientListSpec) and renders tags via SingleFacilityTagManager; AccountRetrieveSpec serializes the full patient (PatientRetrieveSpec, scoped to obj.facility) and, when present, the primary encounter (EncounterRetrieveSpec).
  • Totals are read-only: balance and aggregate fields appear only on read specs. sync_account_items recomputes them; client payloads never set them.

<a id="default-account"></a>

Default account

get_default_account(patient, facility) ([https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/account/default_account.py default_account.py]) returns the first account for that patient + facility with status = active and billing_status = open. If none exists, it creates one with:

  • status = active, billing_status = open
  • service_period = { "start": care_now() } (start only)
  • name = "{patient.name} {YYYY-MM-DD}"

This runs when the first charge item is added, so the default account materializes on demand. Clients normally never create accounts directly.

<a id="balance-sync"></a>

Balance sync

sync_account_items(account) ([https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/account/sync_items.py sync_items.py]) recomputes the totals under an AccountLock:

  • total_billable_charge_items = Σ total_price of charge items with status billable
  • total_gross = Σ total_price of charge items with status paid or billed
  • total_paid = Σ amount of active + complete non-credit-note payment reconciliations − the same for credit notes
  • total_balance = total_gross − total_paid
  • calculated_at = care_now()

Every sum runs through care_round. total_net, cached_items, and total_price_components are not updated — their logic is commented out — so they hold their defaults. rebalance_account_task(account_id) is the Celery wrapper that runs the sync and saves.

Account is the only class in account.py. Its relationships:

facility          → FK facility.Facility (PROTECT)
patient           → FK emr.Patient (PROTECT)
primary_encounter → FK emr.Encounter (SET_NULL, nullable)

Charge items reference the account they belong to and drive its totals; invoices and payment reconciliations settle against the account or its items.

API integration notes

  • The REST API aligns to the FHIR Account resource, but spec field names and enum values differ (enums use underscores, not hyphens).
  • get_default_account creates the default account when the first charge item is added for a patient in a facility; clients normally do not create accounts directly.
  • On create, supply patient as the patient's external_id (UUID); facility is server-scoped.
  • On update, primary_encounter accepts an encounter external_id (UUID); only the base fields plus primary_encounter are mutable.
  • Balance and aggregate fields (total_net, total_gross, total_paid, total_balance, total_billable_charge_items, total_price_components, cached_items, calculated_at) are platform-maintained and appear only on read specs — never set them from clients.
  • service_period requires timezone-aware datetimes with start <= end.
  • extensions is the supported place for custom key-value data without schema migrations; ExtensionValidator checks it, and it surfaces only on the retrieve spec.
  • Gate account data behind permissions that restrict access to users with rights to financial information.

Pages that link here: