From 37ab80e250fa292bd3bb48749f28d2c0aec9cc07 Mon Sep 17 00:00:00 2001 From: David Raeside <132376220+davidraeside@users.noreply.github.com> Date: Tue, 7 Jan 2025 13:14:23 -0500 Subject: [PATCH] Enhance vital signs narrative generation (#6590) * add support for formatting observation.component entries in vital signs narrative generation * update --- ...l-signs-narrative-generation-template.yaml | 5 ++ .../jpa/ips/narrative/utility-fragments.html | 15 +++++ .../fhir/jpa/ips/narrative/vitalsigns.html | 9 ++- .../generator/IpsGeneratorSvcImplTest.java | 56 +++++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_8_0/6587-enhance-vital-signs-narrative-generation-template.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_8_0/6587-enhance-vital-signs-narrative-generation-template.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_8_0/6587-enhance-vital-signs-narrative-generation-template.yaml new file mode 100644 index 00000000000..41531e5d239 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_8_0/6587-enhance-vital-signs-narrative-generation-template.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 6587 +title: "Enhanced the IPS vital signs narrative template to include code and value information for + all entries in the `Observation.component` property." diff --git a/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/utility-fragments.html b/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/utility-fragments.html index 3dea18d43a8..552e48b8753 100644 --- a/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/utility-fragments.html +++ b/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/utility-fragments.html @@ -247,3 +247,18 @@ + + + + + Display + Code + Value + Value + Value + + + + + + diff --git a/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/vitalsigns.html b/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/vitalsigns.html index f890ad6c26e..55391cee2ed 100644 --- a/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/vitalsigns.html +++ b/hapi-fhir-jpaserver-ips/src/main/resources/ca/uhn/fhir/jpa/ips/narrative/vitalsigns.html @@ -4,6 +4,7 @@ Code: Observation.code.text || Observation.code.coding[x].display (separated by Result: Observation.valueQuantity || Observation.valueDateTime || Observation.valueCodeableConcept.text || Observation.valueCodeableConcept.coding[x].display (separated by
) || Observation.valueString Unit: Observation.valueQuantity.unit Interpretation: Observation.interpretation[0].text || Observation.interpretation[0].coding[x].display (separated by
) +Component(s): Observation.component[x].display || Observation.component[x].code + Observation.component[x].value (items separated by comma) Comments: Observation.note[x].text (separated by
) Date: Observation.effectiveDateTime || Observation.effectivePeriod.start */--> @@ -16,6 +17,7 @@ Date: Observation.effectiveDateTime || Observation.effectivePeriod.start Result Unit Interpretation + Component(s) Comments Date @@ -23,12 +25,13 @@ Date: Observation.effectiveDateTime || Observation.effectivePeriod.start - - + + Code Result Unit - Interpretation + Interpretation + Component(s) Comments Date diff --git a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImplTest.java b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImplTest.java index 96464a82b4d..80018cb7ff1 100644 --- a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImplTest.java +++ b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImplTest.java @@ -25,6 +25,8 @@ import org.hl7.fhir.r4.model.AllergyIntolerance; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CarePlan; import org.hl7.fhir.r4.model.ClinicalImpression; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Composition; import org.hl7.fhir.r4.model.Condition; import org.hl7.fhir.r4.model.Consent; @@ -45,6 +47,7 @@ import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.PositiveIntType; import org.hl7.fhir.r4.model.Procedure; +import org.hl7.fhir.r4.model.Quantity; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StringType; @@ -667,6 +670,59 @@ public class IpsGeneratorSvcImplTest { assertSame(strategy2, svc.selectGenerationStrategy("http://2")); } + @Test + public void testVitalSigns_withComponents() throws IOException { + // Setup Patient + initializeGenerationStrategy(); + registerPatientDaoWithRead(); + + Observation observation1 = new Observation(); + observation1.setId("Observation/1"); + observation1.setStatus(Observation.ObservationStatus.FINAL); + observation1.setCode( + new CodeableConcept().addCoding( + new Coding("http://loinc.org", "85354-9", "Blood pressure panel with all children optional") + ) + ); + observation1.addComponent( + new Observation.ObservationComponentComponent( + new CodeableConcept( + new Coding("http://loinc.org", "8480-6", "Systolic blood pressure") + ) + ).setValue(new Quantity().setValue(125).setUnit("mmHg").setSystem("http://unitsofmeasure.org").setCode("mm[Hg]")) + ); + observation1.addComponent( + new Observation.ObservationComponentComponent( + new CodeableConcept( + new Coding("http://loinc.org", "8462-4", "Diastolic blood pressure") + ) + ).setValue(new Quantity().setValue(75).setUnit("mmHg").setSystem("http://unitsofmeasure.org").setCode("mm[Hg]")) + ); + + ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(observation1, BundleEntrySearchModeEnum.MATCH); + IFhirResourceDao observationDao = registerResourceDaoWithNoData(Observation.class); + when(observationDao.search(any(), any())).thenReturn(new SimpleBundleProvider(Lists.newArrayList(observation1))); + registerRemainingResourceDaos(); + + // Test + Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID), null); + + // Verify + Composition compositions = (Composition) outcome.getEntry().get(0).getResource(); + Composition.SectionComponent section = findSection(compositions, DefaultJpaIpsGenerationStrategy.SECTION_CODE_VITAL_SIGNS); + + HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString()); + ourLog.info("Narrative:\n{}", narrativeHtml.asXml()); + + DomNodeList tables = narrativeHtml.getElementsByTagName("table"); + assertThat(tables).hasSize(1); + HtmlTable table = (HtmlTable) tables.get(0); + assertEquals("Code", table.getHeader().getRows().get(0).getCell(0).asNormalizedText()); + assertEquals("Blood pressure panel with all children optional", table.getBodies().get(0).getRows().get(0).getCell(0).asNormalizedText()); + assertEquals("Component(s)", table.getHeader().getRows().get(0).getCell(4).asNormalizedText()); + assertEquals("Systolic blood pressure 125 , Diastolic blood pressure 75", table.getBodies().get(0).getRows().get(0).getCell(4).asNormalizedText()); + } + @Nonnull private Composition.SectionComponent findSection(Composition compositions, String theSectionCode) { return compositions