Skip to main content
Glama
g9.test.ts44 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import type { WithId } from '@medplum/core'; import { createReference, generateId, LOINC, RXNORM, SNOMED, UCUM } from '@medplum/core'; import type { AllergyIntolerance, Bundle, Composition, MedicationRequest, Patient, Resource } from '@medplum/fhirtypes'; import { convertFhirToCcda } from './fhir-to-ccda/convert'; import { OID_ADMINISTRATIVE_GENDER_CODE_SYSTEM, OID_BIRTH_SEX, OID_CDC_RACE_AND_ETHNICITY_CODE_SYSTEM, OID_SEX_OBSERVATION, OID_SMOKING_STATUS_OBSERVATION, OID_TOBACCO_USE_OBSERVATION, } from './oids'; import { ADMINISTRATIVE_GENDER_CODE_SYSTEM, ALLERGY_CLINICAL_CODE_SYSTEM, CLINICAL_CONDITION_CODE_SYSTEM, LANGUAGE_MODE_CODE_SYSTEM, LANGUAGE_MODE_URL, LANGUAGE_PROFICIENCY_CODE_SYSTEM, LANGUAGE_PROFICIENCY_URL, LOINC_ADMINISTRATIVE_SEX, LOINC_ALLERGIES_SECTION, LOINC_ASSESSMENTS_SECTION, LOINC_BIRTH_SEX, LOINC_DEVICES_SECTION, LOINC_ENCOUNTERS_SECTION, LOINC_GOALS_SECTION, LOINC_HEALTH_CONCERNS_SECTION, LOINC_HISTORY_OF_TOBACCO_USE, LOINC_IMMUNIZATIONS_SECTION, LOINC_MEDICATIONS_SECTION, LOINC_NOTES_SECTION, LOINC_PLAN_OF_TREATMENT_SECTION, LOINC_PROBLEMS_SECTION, LOINC_PROCEDURES_SECTION, LOINC_REASON_FOR_REFERRAL_SECTION, LOINC_REFERRAL_NOTE, LOINC_RESULTS_SECTION, LOINC_SOCIAL_HISTORY_SECTION, LOINC_TOBACCO_SMOKING_STATUS, LOINC_VITAL_SIGNS_SECTION, RACE_CODE_SYSTEM, US_CORE_ETHNICITY_URL, US_CORE_RACE_URL, } from './systems'; import type { CcdaCode, CcdaNarrative, CcdaQuantity, CcdaText } from './types'; describe('170.315(g)(9)', () => { describe('Patient Demographics', () => { test('should export first name', () => { const input = createCompositionBundle({ resourceType: 'Patient', name: [{ given: ['John'] }] }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.given?.[0]).toEqual('John'); }); // Last Name test('should export last name', () => { const input = createCompositionBundle({ resourceType: 'Patient', name: [{ family: 'Doe' }] }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.family).toEqual('Doe'); }); // Previous Name (if applicable) test('should export previous name', () => { const input = createCompositionBundle({ resourceType: 'Patient', name: [ { use: 'official', family: 'Johnson', given: ['Sarah'] }, { use: 'maiden', family: 'Smith', given: ['Sarah'], period: { end: '2018-06-15' } }, ], }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.['@_use']).toEqual('L'); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.given?.[0]).toEqual('Sarah'); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.family).toEqual('Johnson'); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[1]?.['@_use']).toEqual('L'); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[1]?.given?.[0]).toEqual('Sarah'); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[1]?.family).toEqual('Smith'); }); // Middle Name test('should export middle name', () => { const input = createCompositionBundle({ resourceType: 'Patient', name: [{ given: ['John', 'Doe'] }] }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.given?.[1]).toEqual('Doe'); }); // Suffix test('should export suffix', () => { const input = createCompositionBundle({ resourceType: 'Patient', name: [{ given: ['John'], suffix: ['Jr.'] }], }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.name?.[0]?.suffix?.[0]).toEqual('Jr.'); }); // Birth Sex test('should export birth sex', () => { const input = createCompositionBundle({ resourceType: 'Patient', gender: 'male' }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.administrativeGenderCode?.['@_code']).toEqual('M'); }); // Date of Birth test('should export date of birth', () => { const input = createCompositionBundle({ resourceType: 'Patient', birthDate: '1990-01-01' }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.patient?.birthTime?.['@_value']).toEqual('19900101'); }); // Race and Ethnicity test('should export race and ethnicity', () => { const patient: Patient = { resourceType: 'Patient', extension: [ { url: US_CORE_RACE_URL, extension: [ { url: 'ombCategory', valueCoding: { system: RACE_CODE_SYSTEM, code: '2106-3', display: 'White', }, }, { url: 'detailed', valueCoding: { system: RACE_CODE_SYSTEM, code: '2108-9', display: 'White European', }, }, ], }, { url: US_CORE_ETHNICITY_URL, extension: [ { url: 'ombCategory', valueCoding: { system: RACE_CODE_SYSTEM, code: '2186-5', display: 'Not Hispanic or Latino', }, }, ], }, ], }; const input = createCompositionBundle(patient); const output = convertFhirToCcda(input); // Test race code expect(output.recordTarget?.[0]?.patientRole?.patient?.raceCode?.[0]?.['@_code']).toEqual('2106-3'); expect(output.recordTarget?.[0]?.patientRole?.patient?.raceCode?.[0]?.['@_displayName']).toEqual('White'); expect(output.recordTarget?.[0]?.patientRole?.patient?.raceCode?.[0]?.['@_codeSystem']).toEqual( OID_CDC_RACE_AND_ETHNICITY_CODE_SYSTEM ); expect(output.recordTarget?.[0]?.patientRole?.patient?.raceCode?.[0]?.['@_codeSystemName']).toEqual( 'CDC Race and Ethnicity' ); // Test detailed race code const detailed = output.recordTarget?.[0]?.patientRole?.patient?.['sdtc:raceCode']?.[0]; expect(detailed?.['@_code']).toEqual('2108-9'); expect(detailed?.['@_displayName']).toEqual('White European'); expect(detailed?.['@_codeSystem']).toEqual(OID_CDC_RACE_AND_ETHNICITY_CODE_SYSTEM); expect(detailed?.['@_codeSystemName']).toEqual('CDC Race and Ethnicity'); // Test ethnicity code expect(output.recordTarget?.[0]?.patientRole?.patient?.ethnicGroupCode?.[0]?.['@_code']).toEqual('2186-5'); expect(output.recordTarget?.[0]?.patientRole?.patient?.ethnicGroupCode?.[0]?.['@_displayName']).toEqual( 'Not Hispanic or Latino' ); expect(output.recordTarget?.[0]?.patientRole?.patient?.ethnicGroupCode?.[0]?.['@_codeSystem']).toEqual( OID_CDC_RACE_AND_ETHNICITY_CODE_SYSTEM ); expect(output.recordTarget?.[0]?.patientRole?.patient?.ethnicGroupCode?.[0]?.['@_codeSystemName']).toEqual( 'CDC Race and Ethnicity' ); }); // Preferred Language test('should export preferred language', () => { const patient: Patient = { resourceType: 'Patient', communication: [ { language: { coding: [ { system: 'urn:ietf:bcp:47', code: 'en-US', }, ], }, preferred: true, extension: [ { url: LANGUAGE_MODE_URL, valueCodeableConcept: { coding: [ { system: LANGUAGE_MODE_CODE_SYSTEM, code: 'ESP', display: 'Expressed spoken', }, ], }, }, { url: LANGUAGE_PROFICIENCY_URL, valueCodeableConcept: { coding: [ { system: LANGUAGE_PROFICIENCY_CODE_SYSTEM, code: 'E', display: 'Excellent', }, ], }, }, ], }, ], }; const input = createCompositionBundle(patient); const output = convertFhirToCcda(input); expect( output.recordTarget?.[0]?.patientRole?.patient?.languageCommunication?.[0]?.languageCode?.['@_code'] ).toEqual('en-US'); }); // Current Address test('should export current address', () => { const input = createCompositionBundle({ resourceType: 'Patient', address: [{ use: 'home', line: ['123 Main St'], city: 'Anytown', state: 'CA', postalCode: '12345' }], }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.addr?.[0]?.['@_use']).toEqual('HP'); expect(output.recordTarget?.[0]?.patientRole?.addr?.[0]?.streetAddressLine?.[0]).toEqual('123 Main St'); expect(output.recordTarget?.[0]?.patientRole?.addr?.[0]?.city).toEqual('Anytown'); expect(output.recordTarget?.[0]?.patientRole?.addr?.[0]?.state).toEqual('CA'); expect(output.recordTarget?.[0]?.patientRole?.addr?.[0]?.postalCode).toEqual('12345'); }); // Phone Number test('should export phone number', () => { const input = createCompositionBundle({ resourceType: 'Patient', telecom: [{ system: 'phone', value: '123-456-7890' }], }); const output = convertFhirToCcda(input); expect(output.recordTarget?.[0]?.patientRole?.telecom?.[0]?.['@_value']).toEqual('tel:123-456-7890'); }); }); describe('Allergies', () => { // Must include reactions and severity test('should export reactions and severity', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_ALLERGIES_SECTION, { resourceType: 'AllergyIntolerance', reaction: [{ manifestation: [{ coding: [{ code: '123' }] }] }], }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.entryRelationship?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect((observation?.value as CcdaCode)?.['@_code']).toEqual('123'); }); // Include timing information and concern status Reference: Section III.A in test data samples [2] test('should export timing information and concern status', () => { const allergy: Partial<AllergyIntolerance> = { resourceType: 'AllergyIntolerance', clinicalStatus: { coding: [ { system: ALLERGY_CLINICAL_CODE_SYSTEM, code: 'active', }, ], }, category: ['medication'], recordedDate: '2024-01-01', onsetDateTime: '2023-12-25', reaction: [ { manifestation: [ { coding: [{ code: '123' }], }, ], }, ], }; const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_ALLERGIES_SECTION, allergy); const output = convertFhirToCcda(input); // Check that category="medication" converts to the correct code expect( ( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.value as CcdaCode )?.['@_code'] ).toEqual('419511003'); // Check act timing (when recorded) expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.effectiveTime?.[0]?.low?.[ '@_value' ] ).toEqual('20240101'); // Check observation timing (when started) expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.effectiveTime?.[0]?.low?.['@_value'] ).toEqual('20231225'); // Check status expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.statusCode?.['@_code'] ).toEqual('active'); }); test('should handle no known allergies', () => { const allergy: Partial<AllergyIntolerance> = { resourceType: 'AllergyIntolerance', clinicalStatus: { coding: [ { system: ALLERGY_CLINICAL_CODE_SYSTEM, code: 'active', }, ], }, code: { coding: [ { system: SNOMED, code: '716186003', display: 'No Known Allergy (situation)', }, ], text: 'NKA', }, recordedDate: '2024-01-01', onsetDateTime: '2023-12-25', }; const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_ALLERGIES_SECTION, allergy); const output = convertFhirToCcda(input); // Check that empty category converts to the default code expect( ( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.value as CcdaCode )?.['@_code'] ).toEqual('419199007'); // Look for the special NKA code expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.participant?.[0]?.participantRole?.playingEntity?.code?.['@_nullFlavor'] ).toEqual('NA'); }); }); // Medications describe('Medications', () => { test('should export timing information and dosage', () => { const medication: Partial<MedicationRequest> = { resourceType: 'MedicationRequest', status: 'active', medicationCodeableConcept: { coding: [ { system: RXNORM, code: '1049221', display: 'Insulin Glargine 100 UNT/ML Injectable Solution', }, ], }, dispenseRequest: { validityPeriod: { start: '2024-01-01', }, }, dosageInstruction: [ { timing: { repeat: { when: ['HS'], // At bedtime }, }, doseAndRate: [ { doseQuantity: { system: UCUM, value: 40, unit: '[IU]', code: '[IU]', }, }, ], route: { coding: [ { system: SNOMED, code: '34206005', display: 'Subcutaneous route', }, ], }, }, ], }; const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_MEDICATIONS_SECTION, medication); const output = convertFhirToCcda(input); // Check timing expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.effectiveTime?.[0]?.low?.['@_value'] ).toEqual('20240101'); // Check dose quantity expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.doseQuantity?.['@_value'] ).toEqual('40'); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.doseQuantity?.['@_unit'] ).toEqual('[IU]'); // Check route expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.routeCode?.['@_code'] ).toEqual('34206005'); }); }); describe('Problems', () => { test('should export problems', () => { // Include timing information // - Include concern status Reference: Section III.C in test data samples [2] const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_PROBLEMS_SECTION, { resourceType: 'Condition', clinicalStatus: { coding: [ { system: CLINICAL_CONDITION_CODE_SYSTEM, code: 'active', }, ], }, recordedDate: '2024-01-01', onsetDateTime: '2023-12-25', code: { coding: [ { system: SNOMED, code: '385093006', display: 'Community acquired pneumonia', }, ], }, }); const output = convertFhirToCcda(input); // Check act timing (when recorded) expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.effectiveTime?.[0]?.low?.[ '@_value' ] ).toEqual('20240101'); // Check observation timing (when started) expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.entryRelationship?.[0] ?.observation?.[0]?.effectiveTime?.[0]?.low?.['@_value'] ).toEqual('20231225'); // Check status expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.act?.[0]?.statusCode?.['@_code'] ).toEqual('active'); }); }); describe('Immunizations', () => { test('should export immunizations', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_IMMUNIZATIONS_SECTION, { resourceType: 'Immunization', }); const output = convertFhirToCcda(input); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration ).toBeDefined(); }); test('should include status and dates', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_IMMUNIZATIONS_SECTION, { resourceType: 'Immunization', status: 'completed', occurrenceDateTime: '2010-08-15', }); const output = convertFhirToCcda(input); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.statusCode?.['@_code'] ).toEqual('completed'); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.effectiveTime?.[0]?.['@_value'] ).toEqual('20100815'); }); test('should include lot number and manufacturer', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_IMMUNIZATIONS_SECTION, { resourceType: 'Immunization', lotNumber: '1', manufacturer: { display: 'Manufacturer' }, }); const output = convertFhirToCcda(input); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.consumable?.manufacturedProduct?.[0]?.manufacturedMaterial?.[0]?.lotNumberText?.[0] ).toEqual('1'); expect( output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.substanceAdministration?.[0] ?.consumable?.manufacturedProduct?.[0]?.manufacturerOrganization?.[0]?.name?.[0] ).toEqual('Manufacturer'); }); }); describe('Vital Signs', () => { test('should export vital signs', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_VITAL_SIGNS_SECTION, { resourceType: 'Observation', }); const output = convertFhirToCcda(input); expect(output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation).toBeDefined(); }); test('should include values and units', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_VITAL_SIGNS_SECTION, { resourceType: 'Observation', valueQuantity: { value: 100, unit: 'mg' }, }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); const value = observation?.value as CcdaQuantity; expect(value?.['@_value']).toEqual('100'); expect(value?.['@_unit']).toEqual('mg'); }); test('should handle observation components', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_VITAL_SIGNS_SECTION, { resourceType: 'Observation', id: '123', component: [ { code: { coding: [{ code: 'a' }] }, valueQuantity: { value: 100, unit: 'mg' } }, { code: { coding: [{ code: 'b' }] }, valueQuantity: { value: 200, unit: 'mg' } }, ], }, { resourceType: 'Observation', id: '456', hasMember: [{ reference: 'Observation/123' }], } ); const output = convertFhirToCcda(input); const organizer = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[1]?.organizer?.[0]; expect(organizer).toBeDefined(); const components = organizer?.component; expect(components).toBeDefined(); expect((components?.[0]?.observation?.[0]?.value as CcdaQuantity)['@_value']).toEqual('100'); expect((components?.[1]?.observation?.[0]?.value as CcdaQuantity)['@_value']).toEqual('200'); }); }); describe('Social History', () => { test('should handle tobacco smoking status', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_SOCIAL_HISTORY_SECTION, { resourceType: 'Observation', status: 'final', code: { coding: [{ system: LOINC, code: LOINC_TOBACCO_SMOKING_STATUS }] }, valueCodeableConcept: { coding: [{ system: SNOMED, code: '449868002' }] }, }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect(observation?.templateId?.[0]?.['@_root']).toEqual(OID_SMOKING_STATUS_OBSERVATION); expect((observation?.value as CcdaCode)?.['@_code']).toEqual('449868002'); }); test('should handle history of tobacco use', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_SOCIAL_HISTORY_SECTION, { resourceType: 'Observation', status: 'final', code: { coding: [{ system: LOINC, code: LOINC_HISTORY_OF_TOBACCO_USE }] }, valueCodeableConcept: { coding: [{ system: SNOMED, code: '449868002' }] }, }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect(observation?.templateId?.[0]?.['@_root']).toEqual(OID_TOBACCO_USE_OBSERVATION); expect((observation?.value as CcdaCode)?.['@_code']).toEqual('449868002'); }); test('should handle administrative gender', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_SOCIAL_HISTORY_SECTION, { resourceType: 'Observation', status: 'final', code: { coding: [{ system: LOINC, code: LOINC_ADMINISTRATIVE_SEX }] }, valueCodeableConcept: { coding: [{ system: SNOMED, code: '248152002' }] }, }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect(observation?.templateId?.[0]?.['@_root']).toEqual(OID_SEX_OBSERVATION); expect((observation?.value as CcdaCode)?.['@_code']).toEqual('248152002'); }); test('should handle birth sex', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_SOCIAL_HISTORY_SECTION, { resourceType: 'Observation', status: 'final', code: { coding: [{ system: LOINC, code: LOINC_BIRTH_SEX }] }, valueCodeableConcept: { coding: [{ system: ADMINISTRATIVE_GENDER_CODE_SYSTEM, code: 'F' }] }, }); const output = convertFhirToCcda(input); const observation = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect(observation?.templateId?.[0]?.['@_root']).toEqual(OID_BIRTH_SEX); expect((observation?.value as CcdaCode)?.['@_code']).toEqual('F'); expect((observation?.value as CcdaCode)?.['@_codeSystem']).toEqual(OID_ADMINISTRATIVE_GENDER_CODE_SYSTEM); }); }); describe('Procedures', () => { test('should handle missing location', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_PROCEDURES_SECTION, { resourceType: 'Procedure', id: '456', location: { reference: 'Location/123' }, }); const output = convertFhirToCcda(input); const procedure = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.procedure?.[0]; expect(procedure).toBeDefined(); }); test('should handle empty location', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_PROCEDURES_SECTION, { resourceType: 'Location', id: '123', }, { resourceType: 'Procedure', id: '456', location: { reference: 'Location/123' }, } ); const output = convertFhirToCcda(input); const procedure = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.procedure?.[0]; expect(procedure).toBeDefined(); const participant = procedure?.participant?.[0]; expect(participant).toBeDefined(); }); test('should create location participant', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_PROCEDURES_SECTION, { resourceType: 'Location', id: '123', name: 'Test Location', address: { line: ['123 Main St'], city: 'Anytown', state: 'CA', postalCode: '12345' }, telecom: [{ system: 'phone', value: '123-456-7890' }], }, { resourceType: 'Procedure', id: '456', location: { reference: 'Location/123' }, } ); const output = convertFhirToCcda(input); const procedure = output.component?.structuredBody?.component?.[0]?.section?.[0]?.entry?.[0]?.procedure?.[0]; expect(procedure).toBeDefined(); const participant = procedure?.participant?.[0]; expect(participant).toBeDefined(); expect(participant?.participantRole?.addr?.[0]?.streetAddressLine?.[0]).toEqual('123 Main St'); expect(participant?.participantRole?.addr?.[0]?.city).toEqual('Anytown'); expect(participant?.participantRole?.addr?.[0]?.state).toEqual('CA'); expect(participant?.participantRole?.addr?.[0]?.postalCode).toEqual('12345'); expect(participant?.participantRole?.telecom?.[0]?.['@_value']).toEqual('tel:123-456-7890'); expect(participant?.participantRole?.playingEntity?.name?.[0]).toEqual('Test Location'); }); }); describe('Labs', () => { test('should handle orders', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_PLAN_OF_TREATMENT_SECTION, { resourceType: 'ServiceRequest', status: 'active', intent: 'order', code: { coding: [ { system: 'http://loinc.org', code: '24357-6', display: 'Urinanalysis macro (dipstick) panel', }, ], }, occurrenceDateTime: '2015-06-29T07:00:00.000Z', authoredOn: '2025-02-27T01:32:00.000Z', }); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_PLAN_OF_TREATMENT_SECTION); const observation = section?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect(observation?.code?.['@_code']).toEqual('24357-6'); expect(observation?.effectiveTime?.[0]?.['@_value']).toMatch('20150629'); }); test('should handle reports', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_RESULTS_SECTION, { resourceType: 'Observation', id: '123', status: 'final', code: { coding: [ { system: 'http://loinc.org', code: '5778-6', display: 'Color of Urine', }, ], }, effectiveDateTime: '2015-06-22T07:00:00.000Z', valueString: 'YELLOW', }, { resourceType: 'DiagnosticReport', status: 'final', code: { coding: [ { system: 'http://loinc.org', code: '24357-6', display: 'Urinanalysis macro (dipstick) panel', }, ], }, effectiveDateTime: '2015-06-22T07:00:00.000Z', issued: '2015-06-22T07:00:00.000Z', result: [{ reference: 'Observation/123' }], } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_RESULTS_SECTION); const organizer = section?.entry?.[1]?.organizer?.[0]; expect(organizer).toBeDefined(); const components = organizer?.component; expect(components).toBeDefined(); expect((components?.[0]?.observation?.[0]?.value as CcdaText)['#text']).toEqual('YELLOW'); }); }); describe('Devices', () => { test('should handle device not found', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_DEVICES_SECTION, { resourceType: 'DeviceUseStatement', status: 'active', device: { reference: 'Device/123' }, }); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_DEVICES_SECTION); expect(section?.entry).toHaveLength(0); }); test('should handle device use statements', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_DEVICES_SECTION, { resourceType: 'Device', id: '123', udiCarrier: [ { deviceIdentifier: '00643169007222', issuer: 'FDA', carrierHRF: '(01)00643169007222(17)160128(21)BLC200461H', }, ], status: 'active', type: { coding: [ { system: 'http://snomed.info/sct', code: '704708004', display: 'Cardiac resynchronization therapy implantable pacemaker', }, ], }, }, { resourceType: 'DeviceUseStatement', status: 'active', device: { reference: 'Device/123' }, } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_DEVICES_SECTION); const procedure = section?.entry?.[0]?.procedure?.[0]; expect(procedure).toBeDefined(); expect(procedure?.code?.['@_code']).toEqual('360030002'); expect(procedure?.participant?.length).toEqual(1); expect(procedure?.participant?.[0]?.['@_typeCode']).toEqual('DEV'); const device = procedure?.participant?.[0]?.participantRole; expect(device).toBeDefined(); expect(device?.playingDevice?.code?.['@_code']).toEqual('704708004'); }); }); describe('Assessments', () => { test('should handle clinical impression', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_ASSESSMENTS_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'ClinicalImpression', status: 'completed', subject: { reference: 'Patient/01953565-5b00-72a8-ac87-3c4b3de1ba88', display: 'Alice Jones Newman', }, date: '2015-06-22T07:00:00.000Z', assessor: { reference: 'Practitioner/davis', display: 'Dr Albert Davis', }, summary: 'Lorem ipsum', } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_ASSESSMENTS_SECTION); expect(section?.text).toEqual('Lorem ipsum'); }); }); describe('Goals', () => { test('should handle goal', () => { const input = createCompositionBundle({ resourceType: 'Patient', id: '123' }, LOINC_GOALS_SECTION, { resourceType: 'Goal', lifecycleStatus: 'active', startDate: '2015-06-23', description: { text: 'Lorem ipsum', }, subject: { reference: 'Patient/123', display: 'Alice Jones Newman', }, }); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_GOALS_SECTION); const observation = section?.entry?.[0]?.observation?.[0]; expect(observation).toBeDefined(); expect((observation?.value as CcdaNarrative)['#text']).toEqual('Lorem ipsum'); }); }); describe('Health Concerns', () => { test('should handle clinical impression', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_HEALTH_CONCERNS_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'ClinicalImpression', status: 'completed', subject: { reference: 'Patient/01953565-5b00-72a8-ac87-3c4b3de1ba88', display: 'Alice Jones Newman', }, date: '2015-06-22T07:00:00.000Z', assessor: { reference: 'Practitioner/davis', display: 'Dr Albert Davis', }, summary: 'Lorem ipsum', } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_HEALTH_CONCERNS_SECTION); const act = section?.entry?.[0]?.act?.[0]; expect((act?.text as CcdaNarrative)['#text']).toEqual('Lorem ipsum'); }); }); describe('Notes', () => { test('should handle clinical impression', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_NOTES_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'ClinicalImpression', status: 'completed', subject: { reference: 'Patient/01953565-5b00-72a8-ac87-3c4b3de1ba88', display: 'Alice Jones Newman', }, date: '2015-06-22T07:00:00.000Z', assessor: { reference: 'Practitioner/davis', display: 'Dr Albert Davis', }, summary: 'Lorem ipsum', } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_NOTES_SECTION); const act = section?.entry?.[0]?.act?.[0]; expect((act?.text as CcdaNarrative)['#text']).toEqual('Lorem ipsum'); }); }); test('should handle practitioner role', () => { const input = createCompositionBundle( { resourceType: 'Patient' }, LOINC_NOTES_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'Organization', id: 'hospital', name: 'Hospital', }, { resourceType: 'PractitionerRole', id: 'role', practitioner: { reference: 'Practitioner/davis' }, organization: { reference: 'Organization/hospital' }, }, { resourceType: 'ClinicalImpression', status: 'completed', subject: { reference: 'Patient/01953565-5b00-72a8-ac87-3c4b3de1ba88', display: 'Alice Jones Newman', }, date: '2015-06-22T07:00:00.000Z', assessor: { reference: 'PractitionerRole/role', }, summary: 'Lorem ipsum', } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_NOTES_SECTION); const act = section?.entry?.[0]?.act?.[0]; expect((act?.text as CcdaNarrative)['#text']).toEqual('Lorem ipsum'); const author = act?.author?.[0]; expect(author).toBeDefined(); expect(author?.assignedAuthor?.assignedPerson?.name?.[0]?.family).toEqual('Davis'); expect(author?.assignedAuthor?.representedOrganization?.name?.[0]).toEqual('Hospital'); }); test('should handle missing author', () => { const input = createCompositionBundle({ resourceType: 'Patient' }, LOINC_NOTES_SECTION, { resourceType: 'ClinicalImpression', status: 'completed', subject: { reference: 'Patient/01953565-5b00-72a8-ac87-3c4b3de1ba88', display: 'Alice Jones Newman', }, date: '2015-06-22T07:00:00.000Z', assessor: { reference: 'PractitionerRole/role', }, summary: 'Lorem ipsum', }); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_NOTES_SECTION); const act = section?.entry?.[0]?.act?.[0]; expect((act?.text as CcdaNarrative)['#text']).toEqual('Lorem ipsum'); const author = act?.author?.[0]; expect(author).toBeUndefined(); }); }); describe('Encounters', () => { test('should handle diagnosis code', () => { const input = createCompositionBundle( { resourceType: 'Patient', id: '123' }, LOINC_ENCOUNTERS_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'Condition', id: 'diagnosis', clinicalStatus: { coding: [{ code: 'active' }] }, category: [{ coding: [{ code: 'encounter-diagnosis' }] }], code: { coding: [{ code: '386661006' }] }, onsetDateTime: '2011-10-05T07:00:00.000Z', recordedDate: '2025-02-24T20:51:00.000Z', recorder: { reference: 'Practitioner/davis' }, }, { resourceType: 'Encounter', status: 'finished', diagnosis: [{ condition: { reference: 'Condition/diagnosis' } }], period: { start: '2015-06-22T20:00:00.000Z', end: '2015-06-22T21:00:00.000Z' }, } ); const output = convertFhirToCcda(input); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.code?.['@_code']).toEqual(LOINC_ENCOUNTERS_SECTION); const encounter = section?.entry?.[0]?.encounter?.[0]; expect(encounter).toBeDefined(); const observation = encounter?.entryRelationship?.[0]?.act?.[0]?.entryRelationship?.[0]?.observation; expect(observation).toBeDefined(); expect(observation?.[0]?.code?.['@_code']).toEqual('282291009'); // Diagnostic interpretation expect((observation?.[0]?.value as CcdaCode)['@_code']).toEqual('386661006'); }); }); describe('Reason for Referral', () => { test('should handle referral service request', () => { const input = createCompositionBundle( { resourceType: 'Patient', id: '123' }, LOINC_REASON_FOR_REFERRAL_SECTION, { resourceType: 'Practitioner', id: 'davis', name: [{ family: 'Davis', given: ['Albert'] }], }, { resourceType: 'ServiceRequest', id: 'referral', status: 'active', intent: 'order', code: { coding: [{ code: '123' }] }, authoredOn: '2025-02-24T20:51:00.000Z', requester: { reference: 'Practitioner/davis' }, performer: [{ reference: 'Practitioner/davis' }], note: [{ text: 'Lorem ipsum' }], } ); const output = convertFhirToCcda(input, { type: 'referral' }); expect(output).toBeDefined(); expect(output.code?.['@_code']).toEqual(LOINC_REFERRAL_NOTE); const section = output.component?.structuredBody?.component?.[0]?.section?.[0]; expect(section).toBeDefined(); expect(section?.text).toEqual('Lorem ipsum'); expect(section?.code?.['@_code']).toEqual(LOINC_REASON_FOR_REFERRAL_SECTION); const act = section?.entry?.[0]?.act?.[0]; expect(act).toBeDefined(); }); }); function createCompositionBundle(patient: Patient, code?: string, ...resources: Partial<Resource>[]): Bundle { for (const resource of resources) { resource.id = resource.id ?? generateId(); } const composition: Composition = { resourceType: 'Composition', status: 'final', type: { text: 'test' }, date: new Date().toISOString(), author: [{ display: 'test' }], title: 'test', subject: createReference(patient), section: code ? [ { title: 'test', code: { coding: [ { code, }, ], }, entry: (resources as WithId<Resource>[]) .filter((r) => !['Device', 'Location', 'Practitioner'].includes(r.resourceType as string)) .map(createReference), }, ] : [], }; return { resourceType: 'Bundle', type: 'document', entry: [{ resource: composition }, { resource: patient }, ...resources.map((r) => ({ resource: r as Resource }))], }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server