Oscar to FHIR Mapping
Download YAML
Oscar_To_FHIR_Mapping:
# =========================================================================
# billing_on_cheader1 (header) → Invoice
# Source: ca.kai.billing.header.BillingONCHeader1
# =========================================================================
billing_on_cheader1:
id: Invoice.id
header_id: Invoice.identifier[rawCode].value
transc_id: "**Not mapped** (internal Oscar transaction tag, constant 'HE')"
rec_id: "**Not mapped** (internal Oscar record tag, constant 'H')"
hin: "**Not mapped on Invoice** — patient HIN lives on the referenced Patient resource"
ver: "**Not mapped on Invoice** — patient HIN version lives on Patient"
dob: "**Not mapped on Invoice** — DOB lives on Patient"
pay_program: Invoice.type.coding[payProgram].code # system=$OscarPayProgramCS (moved from extension in 1.9.9)
payee: "**Not mapped** (Oscar default 'P')"
ref_num: Invoice.participant[role=referring].actor.reference # referring provider Practitioner ref
facilty_num: Invoice.extension[facilityNum].valueString # existing apps.health/Invoice/facility-num
admission_date: Invoice.extension[admissionDate].valueDate # existing apps.health/Invoice/admission-date
ref_lab_num: Invoice.extension[refLabNum].valueString # existing apps.health/Invoice/ref-lab-num
man_review: Invoice.extension[manualReview].valueString # existing apps.health/Invoice/manual-review
location: Invoice.extension[serviceLocation].valueReference # Reference(NexusEmrCoreLocation); SLI code on Location.identifier[sliCode] (refactored from string extension in 1.9.9)
demographic_no: Invoice.subject.reference # → Patient/<demographic_no>
provider_no: Invoice.participant[role=billing].actor.reference # → Practitioner/<provider_no>
provider_ohip_no: Invoice.identifier[rawCode].value # snapshot of OHIP # at bill time (system: provider_ohip_no)
provider_rma_no: Invoice.identifier[rawCode].value # snapshot of RMA # at bill time
appointment_no: Invoice.extension[appointmentNo].valueInteger # existing apps.health/Invoice/appointment-no
demographic_name: "**Not mapped** (derived from Patient resource on read)"
sex: "**Not mapped on Invoice** — lives on Patient"
province: Invoice.extension[province].valueString # existing apps.health/Invoice/province
billing_date: Invoice.date
billing_time: Invoice.date # combined with billing_date
total: Invoice.totalGross.value
paid: Invoice.extension[paid].valueMoney # existing apps.health/Invoice/paid
status: "Invoice.status (mapped per table below) + Invoice.extension[oscarBillingStatus].valueCode (raw Oscar code)"
comment1: Invoice.note[0].text
visittype: Invoice.extension[visitType].valueString # existing apps.health/Invoice/visit-type
apptProvider_no: Invoice.participant[role=appointment].actor.reference
asstProvider_no: Invoice.participant[role=assistant].actor.reference
creator: "**Not mapped** (audit-only in Oscar; available via meta.source)"
timestamp1: Invoice.meta.lastUpdated
clinic: Invoice.issuer.reference # → Organization
# -------------------------------------------------------------------------
# billing_on_cheader1.status → Invoice.status (FHIR required binding)
# Plus oscarBillingStatus extension carries raw Oscar code
# -------------------------------------------------------------------------
billing_on_cheader1_status_enum:
O_Bill_OHIP: "Invoice.status = issued"
P_Bill_Patient: "Invoice.status = issued (+ payProgram=PAT extension)"
W_Bill_WCB: "Invoice.status = issued (+ payProgram=WCB extension)"
B_Submitted_OHIP: "Invoice.status = issued (+ oscarBillingStatus=B extension)"
S_Settled: "Invoice.status = balanced"
H_Capitated: "Invoice.status = balanced (+ shadowBill=true + oscarBillingStatus=H)"
I_Bonus_Codes: "Invoice.status = issued (+ oscarBillingStatus=I)"
X_Bad_Debt: "Invoice.status = cancelled (+ oscarBillingStatus=X)"
D_Deleted: "Invoice.status = cancelled (+ oscarBillingStatus=D)"
N_Do_Not_Bill: "Invoice.status = entered-in-error (+ oscarBillingStatus=N)"
# =========================================================================
# billing_on_item (line items) → Invoice.lineItem[]
# Source: ca.kai.billing.item.BillingItem
# =========================================================================
billing_on_item:
id: Invoice.lineItem.id
ch1_id: Invoice.lineItem.extension[HEADER_ID].valueInteger # apps.health/InvoiceLineItem/header-id
transc_id: "**Not mapped** (internal)"
rec_id: "**Not mapped** (internal)"
service_code: Invoice.lineItem.chargeItemCodeableConcept.coding[ohip].code # system: $OhipSoB
fee: Invoice.lineItem.priceComponent[type=base].amount.value # parsed from String via BigDecimal
ser_num: Invoice.lineItem.priceComponent[type=base].factor # parsed from String
service_date: Invoice.lineItem.extension[SERVICE_DATE].valueDate # apps.health/InvoiceLineItem/service-date
dx: Invoice.lineItem.extension[DIAGNOSTIC_1].valueCodeableConcept # apps.health/InvoiceLineItem/diagnostic1
dx1: Invoice.lineItem.extension[DIAGNOSTIC_2].valueCodeableConcept # apps.health/InvoiceLineItem/diagnostic2
dx2: Invoice.lineItem.extension[DIAGNOSTIC_3].valueCodeableConcept # apps.health/InvoiceLineItem/diagnositc3 (URL typo)
status: Invoice.lineItem.extension[STATUS].valueString # apps.health/InvoiceLineItem/status; 'D' rows filtered via @Where on BillingONCHeader1.billingItems (BillingONCHeader1.java:190)
timestamp: Invoice.lineItem.extension[LAST_UPDATED].valueDateTime
# =========================================================================
# provider → Practitioner + PractitionerRole
# Source: ca.kai.provider.Provider
# =========================================================================
provider:
provider_no: Practitioner.identifier.value
last_name: Practitioner.name.family
first_name: Practitioner.name.given
provider_type: PractitionerRole.code.coding # doctor / nurse / etc.
supervisor: "**Not mapped** (Oscar-internal supervisor link)"
specialty: PractitionerRole.specialty.coding # free text in Oscar; needs code-system binding
credentials: Practitioner.qualification
team: "**Not mapped** (Oscar-internal)"
sex: Practitioner.gender
dob: Practitioner.birthDate
address: Practitioner.address.line
city: Practitioner.address.city
province: Practitioner.address.state
postalCode: Practitioner.address.postalCode
phone: Practitioner.telecom[use=home].value
work_phone: Practitioner.telecom[use=work].value
ohip_no: Practitioner.identifier[ohipBillingNumber].value # system: $OhipBillingNumber — NEW slice
rma_no: Practitioner.identifier[rmaNumber].value # system: $RmaNumber — NEW slice
billing_no: Practitioner.identifier[rawCode].value # generic billing id
hso_no: "**Not mapped (Phase 1)** (legacy capitation identifier)"
practitionerNo: Practitioner.identifier[rawCode].value # CPSO; system URI TBD
practitionerNoType: Practitioner.identifier[rawCode].type # pairs with practitionerNo
email: Practitioner.telecom[system=email].value
title: Practitioner.name.prefix
status: Practitioner.active # '1' → true
provider_activity: "**Not mapped** (Oscar scheduling hint)"
signed_confidentiality: "**Not mapped** (audit-only)"
onMohLastRosterReportDate: "Practitioner.extension[onMohLastRosterReportDate].valueDate (new extension, TBD) — used by Jarvis to infer FHO/FHN shadow billing"
# =========================================================================
# dxresearch → Condition (category=problem-list-item)
# Source: ca.kai.diseaseregistry.DxResearch
# =========================================================================
dxresearch:
dxresearch_no: Condition.id
demographic_no: Condition.subject.reference # → Patient
start_date: Condition.onsetDateTime # per existing converter, also recordedDate
update_date: Condition.meta.lastUpdated
dxresearch_code: Condition.code.coding[standard].code
coding_system: Condition.code.coding[standard].system # MUST map 'icd9' → $ICD9CM (converter bug)
association: Condition.extension[association].valueBoolean # https://apps.health/Condition/association
providerNo: Condition.recorder.reference # → Practitioner (column is camelCase — DxResearch.java:50 has no @Column override, unlike peer entities)
status: "Condition.clinicalStatus (A→active, C/D→inactive per existing ConditionConverter)"
# NEW in Phase 1:
category: "Condition.category = problem-list-item (net-new — existing converter doesn't set it)"
# =========================================================================
# casemgmt_issue (CPP) → Condition (category=problem-list-item)
# Source: ca.kai.caseManagementNote.CaseManagementIssue
# NET-NEW converter path — not in existing Oscar Pro FHIR infrastructure
# =========================================================================
casemgmt_issue:
id: Condition.id
demographic_no: Condition.subject.reference
issue_id: "**Lookup** to Issue catalog table → Condition.code.coding" # joined via JPA
acute: Condition.severity # derived
certain: Condition.verificationStatus # certain=true → confirmed
major: Condition.extension[major].valueBoolean # new extension TBD
resolved: Condition.clinicalStatus # resolved=true → resolved
type: "Condition.category — value determines routing. SocHistory/FamHistory map to Observation.category=SOCIALHISTORY per ca.kai.fhir.converter.CaseManagementNoteCode enum. MedHistory (per CaseManagementNoteRepository.java:137, not in the enum) routes to Condition.category=problem-list-item — the converter must add this path."
program_id: "**Not mapped** (Oscar program binding)"
update_date: Condition.meta.lastUpdated
# =========================================================================
# demographic → Patient
# Source: ca.kai.demographic.Demographic
# =========================================================================
demographic:
demographic_no: Patient.identifier.value
title: Patient.name.prefix
first_name: Patient.name.given
last_name: Patient.name.family
address: Patient.address.line
city: Patient.address.city
province: Patient.address.state
postal: Patient.address.postalCode
phone: Patient.telecom[use=home].value
phone2: Patient.telecom[use=mobile].value
email: Patient.telecom[system=email].value
year_of_birth: Patient.birthDate # concatenated YYYY-MM-DD
month_of_birth: Patient.birthDate
date_of_birth: Patient.birthDate
hin: "Patient.identifier[jurisdictional].value (system: $OntarioHCN)"
ver: Patient.identifier[jurisdictional].extension[hcnVersion]
hinType: "**Derived** (transient — not persisted; inferred from hin+ver)"
roster_status: Patient.extension[rosterStatus].valueCode # existing $URL_ROSTER_STATUS
patient_status: Patient.active # 'AC' → true
# =========================================================================
# casemgmt_note → Encounter (via appointment join)
# Relevant for Encounter.length (time-based OHIP codes)
# Source: ca.kai.caseManagementNote.CaseManagementNote
# =========================================================================
casemgmt_note:
note_id: Encounter.identifier[rawCode].value
demographic_no: Encounter.subject.reference
provider_no: Encounter.participant.individual.reference
note: "**Not on Encounter** — maps to DocumentReference"
observation_date: Encounter.period.start
update_date: Encounter.meta.lastUpdated
encounter_type: Encounter.class.code
billing_code: "**Note: existing Oscar field — may duplicate Invoice data**"
appointmentNo: Encounter.appointment.reference
hourOfEncounterTime: "Encounter.length (combined with minuteOfEncounterTime → duration in minutes) — the converter must populate this"
minuteOfEncounterTime: "Encounter.length"
hourOfEncTransportationTime: Encounter.extension[transportationTime].valueDuration # new extension TBD
minuteOfEncTransportationTime: Encounter.extension[transportationTime].valueDuration
# =========================================================================
# billingservice (fee catalog) — NOT MAPPED TO FHIR in Phase 1
# Jarvis queries via REST endpoint /api/billing/service
# Future Phase 2: map to ChargeItemDefinition if catalog-as-FHIR needed
# =========================================================================
billingservice:
"**Not mapped (Phase 1)** — query via REST /api/billing/service endpoint; ChargeItemDefinition deferred to Phase 2"