Skip to content

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"