Invoice Profile¶
| Canonical | ../StructureDefinition/nexus-emr-core-invoice |
|---|---|
| Status | draft · 1.26.0 |
| Base | Invoice (constraint) |
| CQL primary code path | type — what this means |
| Source | FSH · JSON |
Nexus EMR profile for Invoice representing Canadian provider-side billing records. Aligned with Oscar Pro's billing model: one invoice per claim header, with its line items inline. Phase 1 scope: Ontario OHIP billing via Oscar Pro.
FSH
The authored source of truth: resources/StructureDefinition-nexus-emr-core-invoice.fsh (edit on GitHub). One FSH file may define several related artifacts.
// NexusEmrCoreInvoice.fsh
// Defines the Nexus EMR Invoice profile for Canadian provider-side billing records.
// Phase 1: Ontario (OHIP) + Oscar Pro. Aligns to oscar-pro's existing InvoiceConverter
// emission so the profile and converter are a matched pair.
//
// Source: billing_on_cheader1 (header) + billing_on_item (inline line items).
// Not for: payer submission (Claim), patient-pay ledger (Account), or patient-facing
// combined claim/adjudication views (ExplanationOfBenefit).
Alias: $NexusEmrCoreInvoice = ../StructureDefinition/nexus-emr-core-invoice
// Profile Definition
Profile: NexusEmrCoreInvoice
Parent: Invoice
Id: nexus-emr-core-invoice
Title: "Invoice Profile"
Description: "Nexus EMR profile for Invoice representing Canadian provider-side billing records. Aligned with Oscar Pro's billing model: one invoice per claim header, with its line items inline. Phase 1 scope: Ontario OHIP billing via Oscar Pro."
// THE effective date for this profile (see the EffectiveDate / NoEffectiveDate
// RuleSets): one date concept per resource, declared here rather than guessed.
* insert EffectiveDate([[date]])
// SMART on FHIR exposure -- this resource is reachable by an app, and these are the
// permissions each operation costs (see SmartExposed + the SmartExposed RuleSet).
* insert SmartExposed(invoice)
* ^url = $NexusEmrCoreInvoice
* ^status = #draft
* insert NoResourceNoteExtension
// --- Element Constraints ---
* . ^short = "Nexus EMR Invoice Core"
* . ^definition = """
Represents a Canadian provider-side billing record — the header and line items a physician
submits or records for services provided. Phase 1 sources from Oscar Pro's
a claim header and its line items. Covers OHIP FFS claims,
FHO/FHN shadow bills, third-party / patient-pay billing, WCB submissions, and bonus codes.
"""
* meta.source 0..1 MS
* meta.source ^short = "Identifies EMR instance & pipeline version the resource came from"
* meta.source ^definition = "A URI that identifies the EMR pipeline and version from which this resource originated."
* id 0..1 MS
* text 0..1
* text ^short = "Narrative"
* text ^definition = "A human-readable narrative summary of the Invoice."
// -----------------------------------------
// Identifiers — slicing
// -----------------------------------------
* identifier 0..* MS
* identifier.system 1..1
* identifier.value 1..1
* identifier ^short = "Invoice identifier(s) (recommended; any system)"
* identifier ^definition = """
Identifiers for the invoice. A business identifier is recommended but not required; no specific canonical system is mandated.
"""
* insert SourceIdentifier(identifier)
// -----------------------------------------
// Status — required binding; cannot carry raw Oscar codes
// -----------------------------------------
* status 1..1 MS
* status ^short = "draft | issued | balanced | cancelled | entered-in-error"
* status ^definition = """
FHIR `InvoiceStatus`. **Required binding — cannot carry raw Oscar status codes directly.**
Use the `oscar-billing-status-extension` on this invoice to preserve the 10-code Oscar enum.
Oscar → FHIR status mapping (see oscar-to-fhir feature docs):
| Oscar | FHIR Invoice.status | Notes |
|---|---|---|
| O (Bill OHIP) | `issued` | |
| P (Bill Patient) | `issued` | + `payProgram` extension |
| W (Bill WCB) | `issued` | + `payProgram=WCB` |
| B (Submitted OHIP) | `issued` | awaiting adjudication |
| X (Bad Debt) | `cancelled` | + `oscarBillingStatus=X` |
| H (Capitated) | `balanced` | + `shadowBill=true` |
| I (Bonus Codes) | `issued` | + `oscarBillingStatus=I` |
| S (Settled) | `balanced` | |
| D (Deleted) | `cancelled` | |
| N (Do Not Bill) | `entered-in-error` | |
The table is the contract. A reader meeting an Invoice whose `status` does not match the source
status it was converted from is meeting a converter that has not caught up, and should read the
table rather than the value.
"""
// -----------------------------------------
// Billing extensions (Oscar-specific)
// -----------------------------------------
* extension contains
$OscarBillingStatus named oscarBillingStatus 0..1 MS and
$OscarShadowBill named shadowBill 0..1 MS and
$OscarServiceLocation named serviceLocation 0..1 MS
// -----------------------------------------
// Type — carries the Oscar pay_program code (moved from extension in 1.9.9)
// -----------------------------------------
* type 0..1 MS
* type ^short = "Type of invoice — carries pay_program coding for Canadian billing"
* type ^definition = """
FHIR `Invoice.type` carries the destination payer / program classification for a bill. In 1.9.8
this lived on a custom `payProgram` extension; 1.9.9 migrated it to `Invoice.type.coding` using
the same OscarPayProgramCS code system so FHIR consumers can read it without unpacking a custom
extension. The extensible binding permits additional coding systems alongside the Oscar coding
(e.g. future AHCIP/MSP payer program codes).
"""
* type.coding 1..* MS
* type.coding ^slicing.discriminator.type = #value
* type.coding ^slicing.discriminator.path = "system"
* type.coding ^slicing.rules = #open
* type.coding contains
payProgram 0..1 MS
* type.coding[payProgram].system 1..1
* type.coding[payProgram].system = $OscarPayProgramCS (exactly)
* type.coding[payProgram].code 1..1 MS
* type.coding[payProgram] ^short = "The payment program the invoice is billed under"
* type.coding[payProgram] ^comment = "Carries the OSCAR pay_program code."
* type.coding[payProgram].code from OscarPayProgramVS (extensible)
// -----------------------------------------
// Subject — required reference to Nexus EMR Patient
// -----------------------------------------
* subject 1..1 MS
* subject ^short = "The patient who received the services"
* subject only Reference(NexusEmrCorePatient)
// -----------------------------------------
// Issuer — clinic / organization
// -----------------------------------------
* issuer 0..1 MS
* issuer ^short = "Organization issuing the invoice"
* issuer only Reference(NexusEmrCoreOrganization)
// -----------------------------------------
// Date — when the billing was recorded
// -----------------------------------------
* date 0..1 MS
* date ^short = "Billing date"
// -----------------------------------------
// Participant — billing provider + optional appointment/assistant providers
// Role is used to distinguish billing / appointment / assistant / referring providers;
// left un-sliced to allow flexibility in how source converters populate it.
// -----------------------------------------
* participant 0..* MS
* participant ^short = "Billing provider and related roles (billing, appointment, assistant, referring)"
* participant.actor only Reference(NexusEmrCorePractitioner or NexusEmrCorePractitionerRole or NexusEmrCoreOrganization)
* participant.role 0..1 MS
* participant.role ^short = "billing | appointment | assistant | referring | etc."
// -----------------------------------------
// Line items — inline InvoiceLineItemComponent, one per billing_on_item row
// -----------------------------------------
* lineItem 1..* MS
* lineItem ^short = "One line per billing service code"
* lineItem ^definition = """
One line item per billed service. Each line carries an OHIP fee code
(`chargeItemCodeableConcept`), a price component (fee amount + quantity), and up to three
diagnostic code extensions (`DIAGNOSTIC_1` / `DIAGNOSTIC_2` / `DIAGNOSTIC_3`).
**Note on OHIP submission:** Oscar stores up to 3 dx codes per line as a product feature, but
OHIP's H-file format allows only 1 dx per service line at submission time. Extra slots are
preserved in FHIR for round-trip fidelity.
"""
* lineItem.sequence 1..1 MS
* lineItem.chargeItem[x] only CodeableConcept
* lineItem.chargeItemCodeableConcept 1..1 MS
* lineItem.chargeItemCodeableConcept ^short = "OHIP fee code (e.g. A007)"
* lineItem.chargeItemCodeableConcept ^definition = "OHIP Schedule of Benefits fee code. Coding system should be `$OhipSoB` for Phase 1 Ontario bills."
* lineItem.chargeItemCodeableConcept.coding 1..* MS
* lineItem.chargeItemCodeableConcept.coding ^slicing.discriminator.type = #value
* lineItem.chargeItemCodeableConcept.coding ^slicing.discriminator.path = "system"
* lineItem.chargeItemCodeableConcept.coding ^slicing.rules = #open
* lineItem.chargeItemCodeableConcept.coding contains
ohip 0..1 MS
* lineItem.chargeItemCodeableConcept.coding[ohip].system = $OhipSoB (exactly)
* lineItem.chargeItemCodeableConcept.coding[ohip].code 1..1 MS
* lineItem.chargeItemCodeableConcept.coding[ohip] ^short = "OHIP Schedule of Benefits fee code"
* lineItem.priceComponent 1..* MS
* lineItem.priceComponent.type 1..1 MS
* lineItem.priceComponent.type ^short = "base | surcharge | deduction | discount | tax | informational"
* lineItem.priceComponent.amount 0..1 MS
* lineItem.priceComponent.amount ^short = "Fee amount"
* lineItem.priceComponent.factor 0..1 MS
* lineItem.priceComponent.factor ^short = "Service count / quantity"
// -----------------------------------------
// Totals
// -----------------------------------------
* totalGross 0..1 MS
* totalGross ^short = "Total gross amount"
// -----------------------------------------
// Note
// -----------------------------------------
* note 0..* MS
* note ^short = "Free-text comment"
// CQL PRIMARY CODE PATH. Names the code-valued element a bare CQL retrieve filters on, so
// `[Invoice: "some-code"]` knows what to compare. Base R4's own CQL ModelInfo declares no
// `primaryCodePath` for this resource, and the consequence is not a compile error: the
// retrieve COMPILES, the translator only warns, and the criterion silently filters on
// nothing while its data-requirements manifest emits a `codeFilter` with no `path` (which
// violates FHIR's own drq-1 invariant). Declaring it here is what makes the natural
// authoring form correct rather than merely accepted.
//
// The extension is HL7's own, from hl7.fhir.uv.extensions.r4 which this IG already depends
// on -- not a Nexus canonical. Read by ts/codegen/cql/gen-modelinfo.ts.
* ^extension[+].url = $cql-primary-code-path
* ^extension[=].valueString = "type"