mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-16 09:55:09 +00:00
Several IPS fixes (#5297)
* Several IPS fixes * One more fix * Fix * Fixes * med fixes * Null safety
This commit is contained in:
parent
da58e9f250
commit
03ebabad5b
@ -0,0 +1,13 @@
|
||||
---
|
||||
type: fix
|
||||
issue: 5297
|
||||
title: "Several fixes have been made to the IPS generator:
|
||||
<ul>
|
||||
<li>The display names associated with several sections have been corrected to exactly match the LOINC definitions for their codes</li>
|
||||
<li>Immunizations will now be ordered from most recent to least recent</li>
|
||||
<li>IPS documents containing Consent resources for Advanced Directives could result in a crash</li>
|
||||
<li>IPS documents containing Procedure resources for History of Procedures with a performed date could result in a crash</li>
|
||||
<li>IPS documents containing AllergyIntolerance resources containing an occurrence but not a reaction date could result in a crash</li>
|
||||
<li>IPS documents containing AllergyIntolerance resources containing an onset value in string format could result in a crash</li>
|
||||
<li>IPS documents containing MedicationRequest resources with no associated Medication could result in a crash</li>
|
||||
</ul>"
|
@ -105,7 +105,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.ALLERGY_INTOLERANCE)
|
||||
.withTitle("Allergies and Intolerances")
|
||||
.withSectionCode("48765-2")
|
||||
.withSectionDisplay("Allergies and Adverse Reactions")
|
||||
.withSectionDisplay("Allergies and adverse reactions Document")
|
||||
.withResourceTypes(ResourceType.AllergyIntolerance.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAllergies")
|
||||
@ -117,7 +117,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.MEDICATION_SUMMARY)
|
||||
.withTitle("Medication List")
|
||||
.withSectionCode("10160-0")
|
||||
.withSectionDisplay("Medication List")
|
||||
.withSectionDisplay("History of Medication use Narrative")
|
||||
.withResourceTypes(
|
||||
ResourceType.MedicationStatement.name(),
|
||||
ResourceType.MedicationRequest.name(),
|
||||
@ -133,7 +133,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.PROBLEM_LIST)
|
||||
.withTitle("Problem List")
|
||||
.withSectionCode("11450-4")
|
||||
.withSectionDisplay("Problem List")
|
||||
.withSectionDisplay("Problem list - Reported")
|
||||
.withResourceTypes(ResourceType.Condition.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProblems")
|
||||
@ -145,7 +145,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.IMMUNIZATIONS)
|
||||
.withTitle("History of Immunizations")
|
||||
.withSectionCode("11369-6")
|
||||
.withSectionDisplay("History of Immunizations")
|
||||
.withSectionDisplay("History of Immunization Narrative")
|
||||
.withResourceTypes(ResourceType.Immunization.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionImmunizations")
|
||||
@ -156,7 +156,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.PROCEDURES)
|
||||
.withTitle("History of Procedures")
|
||||
.withSectionCode("47519-4")
|
||||
.withSectionDisplay("History of Procedures")
|
||||
.withSectionDisplay("History of Procedures Document")
|
||||
.withResourceTypes(ResourceType.Procedure.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProceduresHx")
|
||||
@ -166,8 +166,8 @@ public class SectionRegistry {
|
||||
protected void addSectionMedicalDevices() {
|
||||
addSection(IpsSectionEnum.MEDICAL_DEVICES)
|
||||
.withTitle("Medical Devices")
|
||||
.withSectionCode("46240-8")
|
||||
.withSectionDisplay("Medical Devices")
|
||||
.withSectionCode("46264-8")
|
||||
.withSectionDisplay("History of medical device use")
|
||||
.withResourceTypes(ResourceType.DeviceUseStatement.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionMedicalDevices")
|
||||
@ -178,7 +178,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.DIAGNOSTIC_RESULTS)
|
||||
.withTitle("Diagnostic Results")
|
||||
.withSectionCode("30954-2")
|
||||
.withSectionDisplay("Diagnostic Results")
|
||||
.withSectionDisplay("Relevant diagnostic tests/laboratory data Narrative")
|
||||
.withResourceTypes(ResourceType.DiagnosticReport.name(), ResourceType.Observation.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionResults")
|
||||
@ -189,7 +189,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.VITAL_SIGNS)
|
||||
.withTitle("Vital Signs")
|
||||
.withSectionCode("8716-3")
|
||||
.withSectionDisplay("Vital Signs")
|
||||
.withSectionDisplay("Vital signs")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionVitalSigns")
|
||||
@ -200,7 +200,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.PREGNANCY)
|
||||
.withTitle("Pregnancy Information")
|
||||
.withSectionCode("10162-6")
|
||||
.withSectionDisplay("Pregnancy Information")
|
||||
.withSectionDisplay("History of pregnancies Narrative")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPregnancyHx")
|
||||
@ -211,7 +211,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.SOCIAL_HISTORY)
|
||||
.withTitle("Social History")
|
||||
.withSectionCode("29762-2")
|
||||
.withSectionDisplay("Social History")
|
||||
.withSectionDisplay("Social history Narrative")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionSocialHistory")
|
||||
@ -222,7 +222,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.ILLNESS_HISTORY)
|
||||
.withTitle("History of Past Illness")
|
||||
.withSectionCode("11348-0")
|
||||
.withSectionDisplay("History of Past Illness")
|
||||
.withSectionDisplay("History of Past illness Narrative")
|
||||
.withResourceTypes(ResourceType.Condition.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPastIllnessHx")
|
||||
@ -233,7 +233,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.FUNCTIONAL_STATUS)
|
||||
.withTitle("Functional Status")
|
||||
.withSectionCode("47420-5")
|
||||
.withSectionDisplay("Functional Status")
|
||||
.withSectionDisplay("Functional status assessment note")
|
||||
.withResourceTypes(ResourceType.ClinicalImpression.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionFunctionalStatus")
|
||||
@ -244,7 +244,7 @@ public class SectionRegistry {
|
||||
addSection(IpsSectionEnum.PLAN_OF_CARE)
|
||||
.withTitle("Plan of Care")
|
||||
.withSectionCode("18776-5")
|
||||
.withSectionDisplay("Plan of Care")
|
||||
.withSectionDisplay("Plan of care note")
|
||||
.withResourceTypes(ResourceType.CarePlan.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPlanOfCare")
|
||||
@ -254,8 +254,8 @@ public class SectionRegistry {
|
||||
protected void addSectionAdvanceDirectives() {
|
||||
addSection(IpsSectionEnum.ADVANCE_DIRECTIVES)
|
||||
.withTitle("Advance Directives")
|
||||
.withSectionCode("42349-0")
|
||||
.withSectionDisplay("Advance Directives")
|
||||
.withSectionCode("42348-3")
|
||||
.withSectionDisplay("Advance directives")
|
||||
.withResourceTypes(ResourceType.Consent.name())
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAdvanceDirectives")
|
||||
|
@ -24,6 +24,8 @@ import ca.uhn.fhir.jpa.ips.api.IpsContext;
|
||||
import ca.uhn.fhir.jpa.ips.api.SectionRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import com.google.common.collect.Lists;
|
||||
@ -109,12 +111,14 @@ public class DefaultIpsGenerationStrategy implements IIpsGenerationStrategy {
|
||||
switch (theIpsSectionContext.getSection()) {
|
||||
case ALLERGY_INTOLERANCE:
|
||||
case PROBLEM_LIST:
|
||||
case IMMUNIZATIONS:
|
||||
case PROCEDURES:
|
||||
case MEDICAL_DEVICES:
|
||||
case ILLNESS_HISTORY:
|
||||
case FUNCTIONAL_STATUS:
|
||||
return;
|
||||
case IMMUNIZATIONS:
|
||||
theSearchParameterMap.setSort(new SortSpec(Immunization.SP_DATE).setOrder(SortOrderEnum.DESC));
|
||||
return;
|
||||
case VITAL_SIGNS:
|
||||
if (theIpsSectionContext.getResourceType().equals(ResourceType.Observation.name())) {
|
||||
theSearchParameterMap.add(
|
||||
|
@ -22,7 +22,7 @@ Date: Consent.dateTime
|
||||
<th:block th:with="extension=${entry.getResource().getExtensionByUrl('http://hl7.org/fhir/StructureDefinition/narrativeLink').getValue().getValue()}">
|
||||
<tr th:id="${#strings.arraySplit(extension, '#')[1]}">
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getScope()},attr='display')">Scope</td>
|
||||
<td th:text="*{getStatus().getCode()}">Status</td>
|
||||
<td th:text="*{getStatus().getDisplay()}">Status</td>
|
||||
<td th:insert="IpsUtilityFragments :: concatCodeableConcept (list=*{getProvision().getAction()})">Action Controlled</td>
|
||||
<td th:text="*{getDateTimeElement().getValue()}">Date</td>
|
||||
</tr>
|
||||
|
@ -26,12 +26,22 @@ Comments: AllergyIntolerance.note[x].text (separated by <br />)
|
||||
<th:block th:with="extension=${entry.getResource().getExtensionByUrl('http://hl7.org/fhir/StructureDefinition/narrativeLink').getValue().getValue()}">
|
||||
<tr th:id="${#strings.arraySplit(extension, '#')[1]}">
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getCode()},attr='display')">Allergen</td>
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')">Status</td>
|
||||
<td th:insert="~{IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')}">Status</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getCategory()},attr='value')">Category</td>
|
||||
<td th:insert="IpsUtilityFragments :: concatReactionManifestation (list=*{getReaction()})">Reaction</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getReaction()},attr='severity')">Severity</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getNote()},attr='text')">Comments</td>
|
||||
<td th:text="*{getOnsetDateTimeType().getValue()}">Onset</td>
|
||||
|
||||
<th:block th:if="*{hasOnsetDateTimeType()}">
|
||||
<td th:text="*{getOnsetDateTimeType().getValue()}">Onset</td>
|
||||
</th:block>
|
||||
<th:block th:if="*{hasOnsetStringType()}">
|
||||
<td th:text="*{getOnsetStringType().getValue()}">Onset</td>
|
||||
</th:block>
|
||||
<th:block th:if="*{!hasOnsetDateTimeType() && !hasOnsetStringType()}">
|
||||
<td></td>
|
||||
</th:block>
|
||||
|
||||
</tr>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
@ -21,7 +21,7 @@ Date: Procedure.performedDateTime || Procedure.performedPeriod.start && “-“
|
||||
<tr th:id="${#strings.arraySplit(extension, '#')[1]}">
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getCode()},attr='display')">Procedure</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getNote()},attr='text')">Comments</td>
|
||||
<td th:insert=":: renderPerformed (performed=*{getPerformed()})">Date</td>
|
||||
<td th:insert="IpsUtilityFragments :: renderPerformed (performed=*{getPerformed()})">Date</td>
|
||||
</tr>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
@ -22,7 +22,7 @@ Onset Date: Condition.onsetDateTime || Condition.onsetPeriod.start && “-“ &&
|
||||
<th:block th:with="extension=${entry.getResource().getExtensionByUrl('http://hl7.org/fhir/StructureDefinition/narrativeLink').getValue().getValue()}">
|
||||
<tr th:id="${#strings.arraySplit(extension, '#')[1]}">
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getCode()},attr='display')">Medical Problem</td>
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')">Status</td>
|
||||
<td th:insert="~{IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')}">Status</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getNote()},attr='text')">Comments</td>
|
||||
<td th:insert="IpsUtilityFragments :: renderOnset (onset=*{getOnset()})">Onset Date</td>
|
||||
</tr>
|
||||
|
@ -22,7 +22,7 @@ Onset Date: Condition.onsetDateTime || Condition.onsetPeriod.start && “-“ &&
|
||||
<th:block th:with="extension=${entry.getResource().getExtensionByUrl('http://hl7.org/fhir/StructureDefinition/narrativeLink').getValue().getValue()}">
|
||||
<tr th:id="${#strings.arraySplit(extension, '#')[1]}">
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getCode()},attr='display')">Medical Problems</td>
|
||||
<td th:insert="IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')">Status</td>
|
||||
<td th:insert="~{IpsUtilityFragments :: codeableConcept (cc=*{getClinicalStatus()},attr='code')}">Status</td>
|
||||
<td th:insert="IpsUtilityFragments :: concat (list=*{getNote()},attr='text')">Comments</td>
|
||||
<td th:insert="IpsUtilityFragments :: renderOnset (onset=*{getOnset()})">Onset Date</td>
|
||||
</tr>
|
||||
|
@ -23,7 +23,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="renderMedication (medicationType)">
|
||||
<th:block th:object="${medicationType}">
|
||||
<th:block th:if="${medicationType} != null" th:object="${medicationType}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'CodeableConcept'">
|
||||
<th:block th:replace=":: codeableConcept (cc=${medicationType}, attr='display')">Medication</th:block>
|
||||
@ -44,13 +44,15 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${medication}" th:fragment="renderMedicationCode (medication)">
|
||||
<th:block th:replace=":: codeableConcept (cc=${medication.getCode()},attr='display')">Medication</th:block>
|
||||
<th:block th:if="${medication} != null">
|
||||
<th:block th:replace=":: codeableConcept (cc=${medication.getCode()},attr='display')">Medication</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<!--/* Dose Number */-->
|
||||
|
||||
<th:block th:if="${doseNumber}" th:fragment="renderDoseNumber (doseNumber)">
|
||||
<th:block th:object="${doseNumber}">
|
||||
<th:block th:if="${doseNumber} != null" th:object="${doseNumber}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'PositiveIntType'" th:text="*{getValue()}">Dose Number</th:block>
|
||||
<th:block th:case="'StringType'" th:text="*{getValue()}">Dose Number</th:block>
|
||||
@ -61,7 +63,7 @@
|
||||
<!--/* Value */-->
|
||||
|
||||
<th:block th:if="${value}" th:fragment="renderValue (value)">
|
||||
<th:block th:object="${value}">
|
||||
<th:block th:if="${value} != null" th:object="${value}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'Quantity'" th:text="*{getValue()}">Result</th:block>
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Result</th:block>
|
||||
@ -74,7 +76,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${value}" th:fragment="renderValueUnit (value)">
|
||||
<th:block th:object="${value}">
|
||||
<th:block th:if="${value} != null" th:object="${value}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'Quantity'" th:text="*{getUnit()}">Unit</th:block>
|
||||
</th:block>
|
||||
@ -84,7 +86,7 @@
|
||||
<!--/* Dates */-->
|
||||
|
||||
<th:block th:if="${effective}" th:fragment="renderEffective (effective)">
|
||||
<th:block th:object="${effective}">
|
||||
<th:block th:if="${effective} != null" th:object="${effective}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Date</th:block>
|
||||
<th:block th:case="'Period'" th:text="*{getStartElement().getValue()}">Date</th:block>
|
||||
@ -93,7 +95,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${onset}" th:fragment="renderOnset (onset)">
|
||||
<th:block th:object="${onset}">
|
||||
<th:block th:if="${onset} != null" th:object="${onset}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Date</th:block>
|
||||
<th:block th:case="'Period'"
|
||||
@ -110,7 +112,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${performed}" th:fragment="renderPerformed (performed)">
|
||||
<th:block th:object="${performed}">
|
||||
<th:block th:if="${performed} != null" th:object="${performed}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Date</th:block>
|
||||
<th:block th:case="'Period'"
|
||||
@ -127,7 +129,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${occurrence}" th:fragment="renderOccurrence (occurrence)">
|
||||
<th:block th:object="${occurrence}">
|
||||
<th:block th:if="${occurrence} != null" th:object="${occurrence}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Date</th:block>
|
||||
<th:block th:case="'StringType'" th:text="*{getValue()}">Date</th:block>
|
||||
@ -136,7 +138,7 @@
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${recorded}" th:fragment="renderRecorded (recorded)">
|
||||
<th:block th:object="${recorded}">
|
||||
<th:block th:if="${recorded} != null" th:object="${recorded}">
|
||||
<th:block th:switch="*{getClass().getSimpleName()}">
|
||||
<th:block th:case="'DateTimeType'" th:text="*{getValue()}">Date Recorded</th:block>
|
||||
</th:block>
|
||||
@ -146,19 +148,21 @@
|
||||
<!--/* CodeableConcept */-->
|
||||
|
||||
<th:block th:if="${cc}" th:fragment="codeableConcept (cc, attr)">
|
||||
<th:block th:if="${!cc.getTextElement().empty}" th:text="${cc.getText()}"/>
|
||||
<th:block th:if="${cc.getTextElement().empty}" th:switch="${attr} ?: 'display'">
|
||||
<th:block th:case="'display'">
|
||||
<th:block th:replace=":: concat (list=${cc.getCoding()},attr='display')"/>
|
||||
</th:block>
|
||||
<th:block th:case="'code'">
|
||||
<th:block th:replace=":: concat (list=${cc.getCoding()},attr='code')"/>
|
||||
<th:block th:if="${cc} != null">
|
||||
<th:block th:if="${!cc.getTextElement().empty}" th:text="${cc.getText()}"/>
|
||||
<th:block th:if="${cc.getTextElement().empty}" th:switch="${attr} ?: 'display'">
|
||||
<th:block th:case="'display'">
|
||||
<th:block th:replace=":: concat (list=${cc.getCoding()},attr='display')"/>
|
||||
</th:block>
|
||||
<th:block th:case="'code'">
|
||||
<th:block th:replace=":: concat (list=${cc.getCoding()},attr='code')"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${list}" th:fragment="firstFromCodeableConceptList (list)">
|
||||
<th:block th:if="${!list.empty}" with="${attr} ?: 'display'">
|
||||
<th:block th:if="${list} != null AND ${!list.empty}" with="${attr} ?: 'display'">
|
||||
<th:block th:replace=":: codeableConcept (cc=${list.get(0)},attr=${attr})">Interpretation</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
@ -181,7 +185,9 @@
|
||||
<th:block th:replace=":: concatItem (listItem=${item}, iter=${iter}, separator='')"/>
|
||||
</th:block>
|
||||
<th:block th:case="'severity'">
|
||||
<th:block th:replace=":: concatItem (listItem=${item.getSeverity().toCode()}, iter=${iter}, separator='')"/>
|
||||
<th:block th:if="${item.getSeverity() != null}">
|
||||
<th:block th:replace=":: concatItem (listItem=${item.getSeverity().toCode()}, iter=${iter}, separator='')"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
@ -206,21 +212,21 @@
|
||||
<th:block th:if="${!item.hasDescription()}">
|
||||
<th:block th:replace=":: concatCodeableConcept (list=${item.getManifestation()})">Reaction</th:block>
|
||||
</th:block>
|
||||
<th:block th:if="${!iter.last}" th:text=", "/>
|
||||
<th:block th:if="${!iter.last}" th:text="', '"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${list}" th:fragment="concatCodeableConcept (list)">
|
||||
<th:block th:each="item,iter : ${list}" th:if="${!list.empty}" with="attr=${attr} ?: 'display'">
|
||||
<th:block th:replace=":: codeableConcept (cc=${item},attr=${attr})"/>
|
||||
<th:block th:if="${!iter.last}" th:text=", "/>
|
||||
<th:block th:if="${!iter.last}" th:text="', '"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${list}" th:fragment="concatDosageRoute (list)">
|
||||
<th:block th:each="item,iter : ${list}" th:if="${!list.empty}" with="attr=${attr} ?: 'display'">
|
||||
<th:block th:replace=":: codeableConcept (cc=${item.getRoute()},attr=${attr})"/>
|
||||
<th:block th:if="${!iter.last}" th:text=", "/>
|
||||
<th:block th:if="${!iter.last}" th:text="', '"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
@ -238,6 +244,6 @@
|
||||
th:text="${#strings.concatReplaceNulls('', item.getLow().getValue(), '-', item.getHigh().getValue() )}">
|
||||
Reference Range
|
||||
</th:block>
|
||||
<th:block th:if="${!iter.last}" th:text=", "/>
|
||||
<th:block th:if="${!iter.last}" th:text="', '"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
@ -20,11 +20,15 @@ import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Composition;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.Immunization;
|
||||
import org.hl7.fhir.r4.model.MedicationStatement;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -37,10 +41,12 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -102,6 +108,58 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
|
||||
assertThat(sectionTitles.toString(), sectionTitles, contains("Allergies and Intolerances", "Medication List", "Problem List", "History of Immunizations", "Diagnostic Results"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateLargePatientSummary2() {
|
||||
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
|
||||
|
||||
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-2.json.gz");
|
||||
sourceData.setType(Bundle.BundleType.TRANSACTION);
|
||||
for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
|
||||
nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
|
||||
nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
|
||||
ourLog.info("Created {} resources", outcome.getEntry().size());
|
||||
|
||||
Bundle output = myClient
|
||||
.operation()
|
||||
.onInstance("Patient/11439250")
|
||||
.named(JpaConstants.OPERATION_SUMMARY)
|
||||
.withNoParameters(Parameters.class)
|
||||
.returnResourceType(Bundle.class)
|
||||
.execute();
|
||||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
assertEquals(74, output.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateLargePatientSummary3() {
|
||||
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
|
||||
|
||||
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-3.json.gz");
|
||||
sourceData.setType(Bundle.BundleType.TRANSACTION);
|
||||
for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
|
||||
nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
|
||||
nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
|
||||
ourLog.info("Created {} resources", outcome.getEntry().size());
|
||||
|
||||
Bundle output = myClient
|
||||
.operation()
|
||||
.onInstance("Patient/nl-core-Patient-01")
|
||||
.named(JpaConstants.OPERATION_SUMMARY)
|
||||
.withNoParameters(Parameters.class)
|
||||
.returnResourceType(Bundle.class)
|
||||
.execute();
|
||||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
assertEquals(80, output.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateTinyPatientSummary() {
|
||||
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
|
||||
@ -136,6 +194,74 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
|
||||
assertThat(sectionTitles.toString(), sectionTitles, contains("Allergies and Intolerances", "Medication List", "Problem List"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Default strategy should order immunizations alphabetically
|
||||
*/
|
||||
@Test
|
||||
public void testImmunizationOrder() {
|
||||
// Setup
|
||||
|
||||
createPatient(withId("PT1"), withFamily("Simpson"), withGiven("Homer"));
|
||||
|
||||
// Create some immunizations out of order
|
||||
Immunization i;
|
||||
i = new Immunization();
|
||||
i.setPatient(new Reference("Patient/PT1"));
|
||||
i.setOccurrence(new DateTimeType("2010-01-01T00:00:00Z"));
|
||||
i.setVaccineCode(new CodeableConcept().setText("Vax 2010"));
|
||||
myImmunizationDao.create(i, mySrd);
|
||||
i = new Immunization();
|
||||
i.setPatient(new Reference("Patient/PT1"));
|
||||
i.setOccurrence(new DateTimeType("2005-01-01T00:00:00Z"));
|
||||
i.setVaccineCode(new CodeableConcept().setText("Vax 2005"));
|
||||
myImmunizationDao.create(i, mySrd);
|
||||
i = new Immunization();
|
||||
i.setPatient(new Reference("Patient/PT1"));
|
||||
i.setOccurrence(new DateTimeType("2015-01-01T00:00:00Z"));
|
||||
i.setVaccineCode(new CodeableConcept().setText("Vax 2015"));
|
||||
myImmunizationDao.create(i, mySrd);
|
||||
|
||||
// Test
|
||||
|
||||
Bundle output = myClient
|
||||
.operation()
|
||||
.onInstance("Patient/PT1")
|
||||
.named(JpaConstants.OPERATION_SUMMARY)
|
||||
.withNoParameters(Parameters.class)
|
||||
.returnResourceType(Bundle.class)
|
||||
.execute();
|
||||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
Composition composition = findCompositionSectionByDisplay(output, "History of Immunization Narrative");
|
||||
// Should be newest first
|
||||
assertThat(composition.getText().getDivAsString(), stringContainsInOrder(
|
||||
"Vax 2015", "Vax 2010", "Vax 2005"
|
||||
));
|
||||
|
||||
List<String> resourceDates = output
|
||||
.getEntry()
|
||||
.stream()
|
||||
.filter(t -> t.getResource() instanceof Immunization)
|
||||
.map(t -> (Immunization) t.getResource())
|
||||
.map(t -> t.getOccurrenceDateTimeType().getValueAsString().substring(0, 4))
|
||||
.collect(Collectors.toList());
|
||||
assertThat(resourceDates, contains("2015", "2010", "2005"));
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
private static Composition findCompositionSectionByDisplay(Bundle output, String theDisplay) {
|
||||
Composition composition = (Composition) output.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = composition
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getCode().getCoding().get(0).getDisplay().equals(theDisplay))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
return composition;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
private static List<String> extractSectionTitles(Bundle outcome) {
|
||||
Composition composition = (Composition) outcome.getEntry().get(0).getResource();
|
||||
|
@ -15,10 +15,40 @@ import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.test.utilities.HtmlUtil;
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
import com.gargoylesoftware.htmlunit.html.*;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.DomNodeList;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlTable;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlTableRow;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
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.Composition;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.Device;
|
||||
import org.hl7.fhir.r4.model.DeviceUseStatement;
|
||||
import org.hl7.fhir.r4.model.DiagnosticReport;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Immunization;
|
||||
import org.hl7.fhir.r4.model.Medication;
|
||||
import org.hl7.fhir.r4.model.MedicationAdministration;
|
||||
import org.hl7.fhir.r4.model.MedicationDispense;
|
||||
import org.hl7.fhir.r4.model.MedicationRequest;
|
||||
import org.hl7.fhir.r4.model.MedicationStatement;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
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.Reference;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -29,17 +59,22 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.ips.generator.IpsGenerationR4Test.findEntryResource;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* This test verifies various IPS generation logic without using a full
|
||||
@ -76,37 +111,6 @@ public class IpsGeneratorSvcImplTest {
|
||||
private IIpsGeneratorSvc mySvc;
|
||||
private DefaultIpsGenerationStrategy myStrategy;
|
||||
|
||||
@Nonnull
|
||||
private static List<String> toEntryResourceTypeStrings(Bundle outcome) {
|
||||
return outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.map(t -> t.getResource().getResourceType().name())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static Medication createSecondaryMedication(String medicationId) {
|
||||
Medication medication = new Medication();
|
||||
medication.setId(new IdType(medicationId));
|
||||
medication.getCode().addCoding().setDisplay("Tylenol");
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(medication, BundleEntrySearchModeEnum.INCLUDE);
|
||||
return medication;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static MedicationStatement createPrimaryMedicationStatement(String medicationId, String medicationStatementId) {
|
||||
MedicationStatement medicationStatement = new MedicationStatement();
|
||||
medicationStatement.setId(medicationStatementId);
|
||||
medicationStatement.setMedication(new Reference(medicationId));
|
||||
medicationStatement.setStatus(MedicationStatement.MedicationStatementStatus.ACTIVE);
|
||||
medicationStatement.getDosageFirstRep().getRoute().addCoding().setDisplay("Oral");
|
||||
medicationStatement.getDosageFirstRep().setText("DAW");
|
||||
medicationStatement.setEffective(new DateTimeType("2023-01-01T11:22:33Z"));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(medicationStatement, BundleEntrySearchModeEnum.MATCH);
|
||||
return medicationStatement;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
myDaoRegistry.setResourceDaos(Collections.emptyList());
|
||||
@ -153,6 +157,83 @@ public class IpsGeneratorSvcImplTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllergyIntolerance_OnsetTypes() throws IOException {
|
||||
// Setup Patient
|
||||
registerPatientDaoWithRead();
|
||||
|
||||
AllergyIntolerance allergy1 = new AllergyIntolerance();
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(allergy1, BundleEntrySearchModeEnum.MATCH);
|
||||
allergy1.setId("AllergyIntolerance/1");
|
||||
allergy1.getCode().addCoding().setCode("123").setDisplay("Some Code");
|
||||
allergy1.addReaction().addNote().setTime(new Date());
|
||||
allergy1.setOnset(new DateTimeType("2020-02-03T11:22:33Z"));
|
||||
AllergyIntolerance allergy2 = new AllergyIntolerance();
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(allergy2, BundleEntrySearchModeEnum.MATCH);
|
||||
allergy2.setId("AllergyIntolerance/2");
|
||||
allergy2.getCode().addCoding().setCode("123").setDisplay("Some Code");
|
||||
allergy2.addReaction().addNote().setTime(new Date());
|
||||
allergy2.setOnset(new StringType("Some Onset"));
|
||||
AllergyIntolerance allergy3 = new AllergyIntolerance();
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(allergy3, BundleEntrySearchModeEnum.MATCH);
|
||||
allergy3.setId("AllergyIntolerance/3");
|
||||
allergy3.getCode().addCoding().setCode("123").setDisplay("Some Code");
|
||||
allergy3.addReaction().addNote().setTime(new Date());
|
||||
allergy3.setOnset(null);
|
||||
IFhirResourceDao<AllergyIntolerance> allergyDao = registerResourceDaoWithNoData(AllergyIntolerance.class);
|
||||
when(allergyDao.search(any(), any())).thenReturn(new SimpleBundleProvider(Lists.newArrayList(allergy1, allergy2, allergy3)));
|
||||
|
||||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.ALLERGY_INTOLERANCE);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
||||
DomNodeList<DomElement> tables = narrativeHtml.getElementsByTagName("table");
|
||||
assertEquals(1, tables.size());
|
||||
HtmlTable table = (HtmlTable) tables.get(0);
|
||||
int onsetIndex = 6;
|
||||
assertEquals("Onset", table.getHeader().getRows().get(0).getCell(onsetIndex).asNormalizedText());
|
||||
assertEquals(new DateTimeType("2020-02-03T11:22:33Z").getValue().toString(), table.getBodies().get(0).getRows().get(0).getCell(onsetIndex).asNormalizedText());
|
||||
assertEquals("Some Onset", table.getBodies().get(0).getRows().get(1).getCell(onsetIndex).asNormalizedText());
|
||||
assertEquals("", table.getBodies().get(0).getRows().get(2).getCell(onsetIndex).asNormalizedText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllergyIntolerance_MissingElements() throws IOException {
|
||||
// Setup Patient
|
||||
registerPatientDaoWithRead();
|
||||
|
||||
AllergyIntolerance allergy = new AllergyIntolerance();
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(allergy, BundleEntrySearchModeEnum.MATCH);
|
||||
allergy.setId("AllergyIntolerance/1");
|
||||
allergy.getCode().addCoding().setCode("123").setDisplay("Some Code");
|
||||
allergy.addReaction().addNote().setTime(new Date());
|
||||
IFhirResourceDao<AllergyIntolerance> allergyDao = registerResourceDaoWithNoData(AllergyIntolerance.class);
|
||||
when(allergyDao.search(any(), any())).thenReturn(new SimpleBundleProvider(Lists.newArrayList(allergy)));
|
||||
|
||||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.ALLERGY_INTOLERANCE);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
||||
DomNodeList<DomElement> tables = narrativeHtml.getElementsByTagName("table");
|
||||
assertEquals(1, tables.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMedicationSummary_MedicationStatementWithMedicationReference() throws IOException {
|
||||
// Setup Patient
|
||||
@ -196,6 +277,41 @@ public class IpsGeneratorSvcImplTest {
|
||||
assertThat(row.getCell(4).asNormalizedText(), containsString("2023"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMedicationSummary_MedicationRequestWithNoMedication() throws IOException {
|
||||
// Setup Patient
|
||||
registerPatientDaoWithRead();
|
||||
|
||||
// Setup Medication + MedicationStatement
|
||||
MedicationRequest medicationRequest = new MedicationRequest();
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(medicationRequest, BundleEntrySearchModeEnum.MATCH);
|
||||
medicationRequest.setId(MEDICATION_STATEMENT_ID);
|
||||
medicationRequest.setStatus(MedicationRequest.MedicationRequestStatus.ACTIVE);
|
||||
IFhirResourceDao<MedicationRequest> medicationRequestDao = registerResourceDaoWithNoData(MedicationRequest.class);
|
||||
when(medicationRequestDao.search(any(), any())).thenReturn(new SimpleBundleProvider(Lists.newArrayList(medicationRequest)));
|
||||
|
||||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.MEDICATION_SUMMARY);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
||||
DomNodeList<DomElement> tables = narrativeHtml.getElementsByTagName("table");
|
||||
assertEquals(2, tables.size());
|
||||
HtmlTable table = (HtmlTable) tables.get(0);
|
||||
HtmlTableRow row = table.getBodies().get(0).getRows().get(0);
|
||||
assertEquals("", row.getCell(0).asNormalizedText());
|
||||
assertEquals("Active", row.getCell(1).asNormalizedText());
|
||||
assertEquals("", row.getCell(2).asNormalizedText());
|
||||
assertEquals("", row.getCell(3).asNormalizedText());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Composition.SectionComponent findSection(Composition compositions, IpsSectionEnum sectionEnum) {
|
||||
Composition.SectionComponent section = compositions
|
||||
@ -543,4 +659,35 @@ public class IpsGeneratorSvcImplTest {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static List<String> toEntryResourceTypeStrings(Bundle outcome) {
|
||||
return outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.map(t -> t.getResource().getResourceType().name())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static Medication createSecondaryMedication(String medicationId) {
|
||||
Medication medication = new Medication();
|
||||
medication.setId(new IdType(medicationId));
|
||||
medication.getCode().addCoding().setDisplay("Tylenol");
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(medication, BundleEntrySearchModeEnum.INCLUDE);
|
||||
return medication;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static MedicationStatement createPrimaryMedicationStatement(String medicationId, String medicationStatementId) {
|
||||
MedicationStatement medicationStatement = new MedicationStatement();
|
||||
medicationStatement.setId(medicationStatementId);
|
||||
medicationStatement.setMedication(new Reference(medicationId));
|
||||
medicationStatement.setStatus(MedicationStatement.MedicationStatementStatus.ACTIVE);
|
||||
medicationStatement.getDosageFirstRep().getRoute().addCoding().setDisplay("Oral");
|
||||
medicationStatement.getDosageFirstRep().setText("DAW");
|
||||
medicationStatement.setEffective(new DateTimeType("2023-01-01T11:22:33Z"));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(medicationStatement, BundleEntrySearchModeEnum.MATCH);
|
||||
return medicationStatement;
|
||||
}
|
||||
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@ -61,7 +61,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -182,6 +182,6 @@
|
||||
|
||||
</form>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer"></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -28,6 +28,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -129,6 +129,6 @@
|
||||
|
||||
</form>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -246,6 +246,6 @@
|
||||
|
||||
</form>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -612,7 +612,7 @@
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
|
||||
<!--
|
||||
<script type="text/javascript">
|
||||
|
@ -210,6 +210,6 @@
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
<div th:replace="~{tmpl-footer :: footer}" ></div>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
x
Reference in New Issue
Block a user