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
Revision as of 09:40, 6 July 2026 by Admin (talk | contribs) (Automated edit (via update-page on MediaWiki MCP Server))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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:

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

{{Field|model=Account|section=Balances & totals|name=total_price_components|type=JSONField (default {})|notes=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:

Wiki: ohcnwiki.tellmey.fyi