IPS Connectathon Fixes (#4834)
* IPS Connectathon Fixes * Fix changelog * Cleanup
This commit is contained in:
parent
53ceb7cac4
commit
e14bbec83b
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
type: change
|
||||
issue: 4834
|
||||
title: "Several enhancements were made to the IPS generator:<ul>
|
||||
<li>Generated IPS documents will no longer include sections that contain no contents.</li>
|
||||
<li>NarrativeLink extensions now use the correct datatype (url instead of uri)</li>
|
||||
<li>Section profile URLs have been updated to no longer use an unknown URL</li>
|
||||
<li>Some resources added to the generated IPS did not have their FHIR server IDs replaced with a placeholder UUID.</li>
|
||||
<li>Immunization manufacturer was not fetched from the server</li>
|
||||
</ul>
|
||||
Thanks to Rio Bennin for all of the feedback!"
|
|
@ -48,7 +48,7 @@ The narrative properties file should contain definitions using the profile URL o
|
|||
|
||||
```properties
|
||||
ips-allergyintolerance.resourceType=Bundle
|
||||
ips-allergyintolerance.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/AllergiesAndIntolerances-uv-ips
|
||||
ips-allergyintolerance.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAllergies
|
||||
ips-allergyintolerance.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/allergyintolerance.html
|
||||
```
|
||||
|
||||
|
|
|
@ -107,7 +107,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("48765-2")
|
||||
.withSectionDisplay("Allergies and Adverse Reactions")
|
||||
.withResourceTypes(ResourceType.AllergyIntolerance.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/AllergiesAndIntolerances-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAllergies")
|
||||
.withNoInfoGenerator(new AllergyIntoleranceNoInfoR4Generator())
|
||||
.build();
|
||||
}
|
||||
|
@ -122,7 +123,8 @@ public class SectionRegistry {
|
|||
ResourceType.MedicationRequest.name(),
|
||||
ResourceType.MedicationAdministration.name(),
|
||||
ResourceType.MedicationDispense.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/MedicationSummary-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionMedications")
|
||||
.withNoInfoGenerator(new MedicationNoInfoR4Generator())
|
||||
.build();
|
||||
}
|
||||
|
@ -133,7 +135,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("11450-4")
|
||||
.withSectionDisplay("Problem List")
|
||||
.withResourceTypes(ResourceType.Condition.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/ProblemList-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProblems")
|
||||
.withNoInfoGenerator(new ProblemNoInfoR4Generator())
|
||||
.build();
|
||||
}
|
||||
|
@ -144,7 +147,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("11369-6")
|
||||
.withSectionDisplay("History of Immunizations")
|
||||
.withResourceTypes(ResourceType.Immunization.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/Immunizations-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionImmunizations")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -154,7 +158,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("47519-4")
|
||||
.withSectionDisplay("History of Procedures")
|
||||
.withResourceTypes(ResourceType.Procedure.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/HistoryOfProcedures-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProceduresHx")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -164,7 +169,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("46240-8")
|
||||
.withSectionDisplay("Medical Devices")
|
||||
.withResourceTypes(ResourceType.DeviceUseStatement.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/MedicalDevices-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionMedicalDevices")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -174,7 +180,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("30954-2")
|
||||
.withSectionDisplay("Diagnostic Results")
|
||||
.withResourceTypes(ResourceType.DiagnosticReport.name(), ResourceType.Observation.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/DiagnosticResults-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionResults")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -184,7 +191,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("8716-3")
|
||||
.withSectionDisplay("Vital Signs")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/VitalSigns-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionVitalSigns")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -194,7 +202,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("10162-6")
|
||||
.withSectionDisplay("Pregnancy Information")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/Pregnancy-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPregnancyHx")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -204,7 +213,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("29762-2")
|
||||
.withSectionDisplay("Social History")
|
||||
.withResourceTypes(ResourceType.Observation.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/SocialHistory-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionSocialHistory")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -214,7 +224,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("11348-0")
|
||||
.withSectionDisplay("History of Past Illness")
|
||||
.withResourceTypes(ResourceType.Condition.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/PastHistoryOfIllnesses-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPastIllnessHx")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -224,7 +235,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("47420-5")
|
||||
.withSectionDisplay("Functional Status")
|
||||
.withResourceTypes(ResourceType.ClinicalImpression.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/FunctionalStatus-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionFunctionalStatus")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -234,7 +246,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("18776-5")
|
||||
.withSectionDisplay("Plan of Care")
|
||||
.withResourceTypes(ResourceType.CarePlan.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/PlanOfCare-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPlanOfCare")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -244,7 +257,8 @@ public class SectionRegistry {
|
|||
.withSectionCode("42349-0")
|
||||
.withSectionDisplay("Advance Directives")
|
||||
.withResourceTypes(ResourceType.Consent.name())
|
||||
.withProfile("http://hl7.org/fhir/uv/ips/StructureDefinition/AdvanceDirectives-uv-ips")
|
||||
.withProfile(
|
||||
"https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAdvanceDirectives")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -218,16 +218,16 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
|
||||
for (IBaseResource nextCandidate : resources) {
|
||||
|
||||
boolean include;
|
||||
|
||||
if (ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextCandidate)
|
||||
== BundleEntrySearchModeEnum.INCLUDE) {
|
||||
include = true;
|
||||
boolean candidateIsSearchInclude = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextCandidate)
|
||||
== BundleEntrySearchModeEnum.INCLUDE;
|
||||
boolean addResourceToBundle;
|
||||
if (candidateIsSearchInclude) {
|
||||
addResourceToBundle = true;
|
||||
} else {
|
||||
include = myGenerationStrategy.shouldInclude(ipsSectionContext, nextCandidate);
|
||||
addResourceToBundle = myGenerationStrategy.shouldInclude(ipsSectionContext, nextCandidate);
|
||||
}
|
||||
|
||||
if (include) {
|
||||
if (addResourceToBundle) {
|
||||
|
||||
String originalResourceId = nextCandidate
|
||||
.getIdElement()
|
||||
|
@ -249,13 +249,19 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
nextCandidate = previouslyExistingResource;
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(nextCandidate, originalResourceId);
|
||||
} else if (theGlobalResourcesToInclude.hasResourceWithReplacementId(originalResourceId)) {
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(nextCandidate, originalResourceId);
|
||||
if (!candidateIsSearchInclude) {
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(
|
||||
nextCandidate, originalResourceId);
|
||||
}
|
||||
} else {
|
||||
IIdType id = myGenerationStrategy.massageResourceId(theIpsContext, nextCandidate);
|
||||
nextCandidate.setId(id);
|
||||
theGlobalResourcesToInclude.addResourceIfNotAlreadyPresent(
|
||||
nextCandidate, originalResourceId);
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(nextCandidate, originalResourceId);
|
||||
if (!candidateIsSearchInclude) {
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(
|
||||
nextCandidate, originalResourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +287,7 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
* the summary, so we need to also update the references to those
|
||||
* resources.
|
||||
*/
|
||||
for (IBaseResource nextResource : sectionResourcesToInclude.getResources()) {
|
||||
for (IBaseResource nextResource : theGlobalResourcesToInclude.getResources()) {
|
||||
List<ResourceReferenceInfo> references = myFhirContext.newTerser().getAllResourceReferences(nextResource);
|
||||
for (ResourceReferenceInfo nextReference : references) {
|
||||
String existingReference = nextReference
|
||||
|
@ -307,6 +313,10 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
}
|
||||
}
|
||||
|
||||
if (sectionResourcesToInclude.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
addSection(theSection, theCompositionBuilder, sectionResourcesToInclude, theGlobalResourcesToInclude);
|
||||
}
|
||||
|
||||
|
@ -336,7 +346,7 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
+ "-"
|
||||
+ next.getIdElement().getValue();
|
||||
IPrimitiveType<String> narrativeLinkUri = (IPrimitiveType<String>)
|
||||
myFhirContext.getElementDefinition("uri").newInstance();
|
||||
myFhirContext.getElementDefinition("url").newInstance();
|
||||
narrativeLinkUri.setValueAsString(narrativeLinkValue);
|
||||
narrativeLink.setValue(narrativeLinkUri);
|
||||
|
||||
|
@ -417,152 +427,6 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
return generator;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static HashMap<PatientSummary.IPSSection, List<Resource>> hashPrimaries(List<Resource> resourceList) {
|
||||
HashMap<PatientSummary.IPSSection, List<Resource>> iPSResourceMap = new HashMap<PatientSummary.IPSSection, List<Resource>>();
|
||||
|
||||
for (Resource resource : resourceList) {
|
||||
for (PatientSummary.IPSSection iPSSection : PatientSummary.IPSSection.values()) {
|
||||
if ( SectionTypes.get(iPSSection).contains(resource.getResourceType()) ) {
|
||||
if ( !(resource.getResourceType() == ResourceType.Observation) || isObservationinSection(iPSSection, (Observation) resource)) {
|
||||
if (iPSResourceMap.get(iPSSection) == null) {
|
||||
iPSResourceMap.put(iPSSection, new ArrayList<Resource>());
|
||||
}
|
||||
iPSResourceMap.get(iPSSection).add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iPSResourceMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static HashMap<PatientSummary.IPSSection, List<Resource>> filterPrimaries(HashMap<PatientSummary.IPSSection, List<Resource>> sectionPrimaries) {
|
||||
HashMap<PatientSummary.IPSSection, List<Resource>> filteredPrimaries = new HashMap<PatientSummary.IPSSection, List<Resource>>();
|
||||
for ( PatientSummary.IPSSection section : sectionPrimaries.keySet() ) {
|
||||
List<Resource> filteredList = new ArrayList<Resource>();
|
||||
for (Resource resource : sectionPrimaries.get(section)) {
|
||||
if (passesFilter(section, resource)) {
|
||||
filteredList.add(resource);
|
||||
}
|
||||
}
|
||||
if (filteredList.size() > 0) {
|
||||
filteredPrimaries.put(section, filteredList);
|
||||
}
|
||||
}
|
||||
return filteredPrimaries;
|
||||
}
|
||||
|
||||
private static List<Resource> pruneResources(Patient patient, List<Resource> resources, HashMap<PatientSummary.IPSSection, List<Resource>> sectionPrimaries, FhirContext ctx) {
|
||||
List<String> resourceIds = new ArrayList<String>();
|
||||
List<String> followedIds = new ArrayList<String>();
|
||||
|
||||
HashMap<String, Resource> resourcesById = new HashMap<String, Resource>();
|
||||
for (Resource resource : resources) {
|
||||
resourcesById.put(resource.getIdElement().getIdPart(), resource);
|
||||
}
|
||||
String patientId = patient.getIdElement().getIdPart();
|
||||
resourcesById.put(patientId, patient);
|
||||
|
||||
recursivePrune(patientId, resourceIds, followedIds, resourcesById, ctx);
|
||||
|
||||
for (PatientSummary.IPSSection section : sectionPrimaries.keySet()) {
|
||||
for (Resource resource : sectionPrimaries.get(section)) {
|
||||
String resourceId = resource.getIdElement().getIdPart();
|
||||
recursivePrune(resourceId, resourceIds, followedIds, resourcesById, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
List<Resource> prunedResources = new ArrayList<Resource>();
|
||||
|
||||
for (Resource resource : resources) {
|
||||
if (resourceIds.contains(resource.getIdElement().getIdPart())) {
|
||||
prunedResources.add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return prunedResources;
|
||||
}
|
||||
|
||||
private static Void recursivePrune(String resourceId, List<String> resourceIds, List<String> followedIds, HashMap<String, Resource> resourcesById, FhirContext ctx) {
|
||||
if (!resourceIds.contains(resourceId)) {
|
||||
resourceIds.add(resourceId);
|
||||
}
|
||||
|
||||
Resource resource = resourcesById.get(resourceId);
|
||||
if (resource != null) {
|
||||
ctx.newTerser().getAllResourceReferences(resource).stream()
|
||||
.map( r -> r.getResourceReference().getReferenceElement().getIdPart() )
|
||||
.forEach( id -> {
|
||||
if (!followedIds.contains(id)) {
|
||||
followedIds.add(id);
|
||||
recursivePrune(id, resourceIds, followedIds, resourcesById, ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<Resource> addLinkToResources(List<Resource> resources, HashMap<PatientSummary.IPSSection, List<Resource>> sectionPrimaries, Composition composition) {
|
||||
List<Resource> linkedResources = new ArrayList<Resource>();
|
||||
HashMap<String, String> valueUrls = new HashMap<String, String>();
|
||||
|
||||
String url = "http://hl7.org/fhir/StructureDefinition/narrativeLink";
|
||||
String valueUrlBase = composition.getId() + "#";
|
||||
|
||||
for (PatientSummary.IPSSection section : sectionPrimaries.keySet()) {
|
||||
String profile = SectionProfiles.get(section);
|
||||
String[] arr = profile.split("/");
|
||||
String profileName = arr[arr.length - 1];
|
||||
String sectionValueUrlBase = valueUrlBase + profileName.split("-uv-")[0];
|
||||
|
||||
for (Resource resource : sectionPrimaries.get(section)) {
|
||||
String valueUrl = sectionValueUrlBase + "-" + resource.getIdElement().getIdPart();
|
||||
valueUrls.put(resource.getIdElement().getIdPart(), valueUrl);
|
||||
}
|
||||
}
|
||||
|
||||
for (Resource resource : resources) {
|
||||
if (valueUrls.containsKey(resource.getIdElement().getIdPart())) {
|
||||
String valueUrl = valueUrls.get(resource.getIdElement().getIdPart());
|
||||
Extension extension = new Extension();
|
||||
extension.setUrl(url);
|
||||
extension.setValue(new UriType(valueUrl));
|
||||
DomainResource domainResource = (DomainResource) resource;
|
||||
domainResource.addExtension(extension);
|
||||
resource = (Resource) domainResource;
|
||||
}
|
||||
linkedResources.add(resource);
|
||||
}
|
||||
|
||||
return linkedResources;
|
||||
}
|
||||
|
||||
private static HashMap<PatientSummary.IPSSection, String> createNarratives(HashMap<PatientSummary.IPSSection, List<Resource>> sectionPrimaries, List<Resource> resources, FhirContext ctx) {
|
||||
HashMap<PatientSummary.IPSSection, String> hashedNarratives = new HashMap<PatientSummary.IPSSection, String>();
|
||||
|
||||
for (PatientSummary.IPSSection section : sectionPrimaries.keySet()) {
|
||||
String narrative = createSectionNarrative(section, resources, ctx);
|
||||
hashedNarratives.put(section, narrative);
|
||||
}
|
||||
|
||||
return hashedNarratives;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
private static class ResourceInclusionCollection {
|
||||
|
||||
private final List<IBaseResource> myResources = new ArrayList<>();
|
||||
|
|
|
@ -44,6 +44,9 @@ public class IpsOperationProvider {
|
|||
|
||||
/**
|
||||
* Patient/123/$summary
|
||||
* <p>
|
||||
* Note that not all parameters from the official specification are yet supported. See
|
||||
* <a href="http://build.fhir.org/ig/HL7/fhir-ips/OperationDefinition-summary.html>http://build.fhir.org/ig/HL7/fhir-ips/OperationDefinition-summary.html</a>
|
||||
*/
|
||||
@Operation(
|
||||
name = JpaConstants.OPERATION_SUMMARY,
|
||||
|
@ -58,6 +61,9 @@ public class IpsOperationProvider {
|
|||
|
||||
/**
|
||||
* /Patient/$summary?identifier=foo|bar
|
||||
* <p>
|
||||
* Note that not all parameters from the official specification are yet supported. See
|
||||
* <a href="http://build.fhir.org/ig/HL7/fhir-ips/OperationDefinition-summary.html>http://build.fhir.org/ig/HL7/fhir-ips/OperationDefinition-summary.html</a>
|
||||
*/
|
||||
@Operation(
|
||||
name = JpaConstants.OPERATION_SUMMARY,
|
||||
|
|
|
@ -293,9 +293,13 @@ public class DefaultIpsGenerationStrategy implements IIpsGenerationStrategy {
|
|||
return Sets.newHashSet(DeviceUseStatement.INCLUDE_DEVICE);
|
||||
}
|
||||
break;
|
||||
case IMMUNIZATIONS:
|
||||
if (ResourceType.Immunization.name().equals(theIpsSectionContext.getResourceType())) {
|
||||
return Sets.newHashSet(Immunization.INCLUDE_MANUFACTURER);
|
||||
}
|
||||
break;
|
||||
case ALLERGY_INTOLERANCE:
|
||||
case PROBLEM_LIST:
|
||||
case IMMUNIZATIONS:
|
||||
case PROCEDURES:
|
||||
case DIAGNOSTIC_RESULTS:
|
||||
case VITAL_SIGNS:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!--/* AdvanceDirectives -->
|
||||
<!--
|
||||
Scope: Consent.scope.text || Consent.scope.coding[x].display
|
||||
Scope: Consent.scope.text || Consent.scope.coding[x].display (separated by <br />)
|
||||
Status: Consent.status.code
|
||||
Action Controlled: Consent.provision.action[x].coding[x].display (concatenate items separated by comma, e.g. x, y, z)
|
||||
Action Controlled: Consent.provision.action[x].{ text || coding[x].display (separated by <br />)} (concatenate with comma, e.g. x, y, z)
|
||||
Date: Consent.dateTime
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
|
@ -23,7 +23,6 @@ Date: Consent.dateTime
|
|||
<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="*{getdateTimeType().getValue()}">Action Controlled</td>
|
||||
<td th:insert="IpsUtilityFragments :: concatCodeableConcept (list=*{getProvision().getAction()})">Action Controlled</td>
|
||||
<td th:text="*{getDateTimeElement().getValue()}">Date</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
<!--/* AllergiesAndIntolerances -->
|
||||
<!--
|
||||
Allergen: AllergyIntolerance.code.text || AllergyIntolerance.code.coding[x].display
|
||||
Status: AllergyIntolerance.clinicalStatus.coding[x].display
|
||||
Category: AllergyIntolerance.code[x]
|
||||
Reaction: AllergyIntolerance.reaction.manifestation.text || AllergyIntolerance.reaction.manifestation.coding[x].display *** What about getReaction().getDescription() ***
|
||||
Severity: AllergyIntolerance.reaction.severity.code
|
||||
Comments: AllergyIntolerance.note[x].text (display all notes separated by <br /> )
|
||||
Onset: AllergyIntolerance.onsetDateTime
|
||||
Allergen: AllergyIntolerance.code.text || AllergyIntolerance.code.coding[x].display (separated by <br />)
|
||||
Status: AllergyIntolerance.clinicalStatus.text || AllergyIntolerance.clinicalStatus.coding[x].code (separated by <br />)
|
||||
Category: AllergyIntolerance.category[x] (separated by <br />)
|
||||
Reaction: AllergyIntolerance.reaction.manifestation.description || AllergyIntolerance.reaction.manifestation.text || AllergyIntolerance.reaction.manifestation.coding[x].display (separated by <br />)
|
||||
Severity: AllergyIntolerance.reaction.severity[x].code (separated by <br />)
|
||||
Comments: AllergyIntolerance.note[x].text (separated by <br />)
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<!--/* DiagnosticResults -->
|
||||
<!--
|
||||
TABLE 1: Observation
|
||||
Code: Observation.code.text || Observation.code.coding[x].display
|
||||
Result: Observation.valueQuantity.value || Observation.valueCodeableConcept.coding[x].display || Observation.valueString
|
||||
TABLE 1: Observations
|
||||
Code: Observation.code.text || Observation.code.coding[x].display (separated by <br />)
|
||||
Result: Observation.valueQuantity || Observation.valueDateTime || Observation.valueCodeableConcept.text || Observation.valueCodeableConcept.coding[x].display (separated by <br />) || Observation.valueString
|
||||
Unit: Observation.valueQuantity.unit
|
||||
Interpretation: Observation.interpretation.text || Observation. interpretation.coding[x].display
|
||||
Reference Range: Observation.referenceRange.low.value && “-“ && Observation.referenceRange.high.value
|
||||
Comments: Observation.note[x].text (display all notes separated by <br /> )
|
||||
Date: Observation.effectiveDateTime
|
||||
Interpretation: Observation.interpretation[0].text || Observation.interpretation[0].coding[x].display (separated by <br />)
|
||||
Reference Range: Observation.referenceRange[x]{ text || low.value && “-“ && high.value} (concatenate with comma, e.g. x, y, z)
|
||||
Comments: Observation.note[x].text (separated by <br />)
|
||||
Date: Observation.effectiveDateTime || Observation.effectivePeriod.start
|
||||
|
||||
TABLE 2: DiagnosticReport
|
||||
Code: DiagnosticReport.code.text || DiagnosticReport.code.coding[x].display
|
||||
Date: DiagnosticReport.effectiveDateTime
|
||||
TABLE 2: Diagnostic Reports
|
||||
Code: DiagnosticReport.code.text || DiagnosticReport.code.coding[x].display (separated by <br />)
|
||||
Date: DiagnosticReport.effectiveDateTime || DiagnosticReport.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<!--/* FunctionalStatus -->
|
||||
<!--
|
||||
Assessment: ClinicalImpression.code.text || ClinicalImpression.code[x].display
|
||||
Assessment: ClinicalImpression.code.text || ClinicalImpression.code[x].display (separated by <br />)
|
||||
Status: ClinicalImpression.status.code
|
||||
Finding: ClinicalImpression.summary
|
||||
Comments: ClinicalImpression.note[x].text (display all notes separated by <br /> )
|
||||
Date: ClinicalImpression.effectiveDateTime
|
||||
Finding: ClinicalImpression.summary
|
||||
Comments: ClinicalImpression.note[x].text (separated by <br />)
|
||||
Date: ClinicalImpression.effectiveDateTime || ClinicalImpression.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!--/* HistoryOfProcedures -->
|
||||
<!--
|
||||
Procedure: Procedure.code.text || Procedure.code.coding[x].display
|
||||
Comments: Procedure.note[x].text(display all notes separated by <br /> )
|
||||
Date: Procedure.performedDateTime
|
||||
Procedure: Procedure.code.text || Procedure.code.coding[x].display (separated by <br />)
|
||||
Comments: Procedure.note[x].text(separated by <br />)
|
||||
Date: Procedure.performedDateTime || Procedure.performedPeriod.start && “-“ && Procedure.performedPeriod.end || Procedure.performedAge || Procedure.performedRange.low && “-“ && Procedure.performedRange.high || Procedure.performedString
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!--/* Immunizations -->
|
||||
<!--
|
||||
Immunization: Immunization.vaccineCode.text || Immunization.vaccineCode.coding[x].display
|
||||
Status: Immunization.status.code
|
||||
Dose Number: Immunization.doseNumberPositiveInt || Immunization.doseNumberString
|
||||
Immunization: Immunization.vaccineCode.text || Immunization.vaccineCode.coding[x].display (separated by <br />)
|
||||
Status: Immunization.status
|
||||
Dose Number: Immunization.protocolApplied[x]{doseNumberPositiveInt || doseNumberString} (concatenate with comma, e.g. x, y, z)
|
||||
Manufacturer: Organization.name
|
||||
Lot Number: Immunization.lotNumber
|
||||
Comments: Immunization.note[x].text (display all notes separated by <br /> )
|
||||
Date: Immunization.occurrenceDateTime
|
||||
Comments: Immunization.note[x].text (separated by <br />)
|
||||
Date: Immunization.occurrenceDateTime || Immunization.occurrenceString
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -3,43 +3,43 @@
|
|||
################################################
|
||||
|
||||
ips-allergyintolerance.resourceType=Bundle
|
||||
ips-allergyintolerance.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/AllergiesAndIntolerances-uv-ips
|
||||
ips-allergyintolerance.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAllergies
|
||||
ips-allergyintolerance.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/allergyintolerance.html
|
||||
|
||||
ips-medicationsummary.resourceType=Bundle
|
||||
ips-medicationsummary.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/MedicationSummary-uv-ips
|
||||
ips-medicationsummary.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionMedications
|
||||
ips-medicationsummary.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/medicationsummary.html
|
||||
|
||||
ips-problemlist.resourceType=Bundle
|
||||
ips-problemlist.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/ProblemList-uv-ips
|
||||
ips-problemlist.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProblems
|
||||
ips-problemlist.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/problemlist.html
|
||||
|
||||
ips-immunizations.resourceType=Bundle
|
||||
ips-immunizations.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/Immunizations-uv-ips
|
||||
ips-immunizations.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionImmunizations
|
||||
ips-immunizations.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/immunizations.html
|
||||
|
||||
ips-historyofprocedures.resourceType=Bundle
|
||||
ips-historyofprocedures.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/HistoryOfProcedures-uv-ips
|
||||
ips-historyofprocedures.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionProceduresHx
|
||||
ips-historyofprocedures.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/historyofprocedures.html
|
||||
|
||||
ips-medicaldevices.resourceType=Bundle
|
||||
ips-medicaldevices.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/MedicalDevices-uv-ips
|
||||
ips-medicaldevices.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionMedicalDevices
|
||||
ips-medicaldevices.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/medicaldevices.html
|
||||
|
||||
ips-diagnosticresults.resourceType=Bundle
|
||||
ips-diagnosticresults.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/DiagnosticResults-uv-ips
|
||||
ips-diagnosticresults.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionResults
|
||||
ips-diagnosticresults.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/diagnosticresults.html
|
||||
|
||||
ips-vitalsigns.resourceType=Bundle
|
||||
ips-vitalsigns.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/VitalSigns-uv-ips
|
||||
ips-vitalsigns.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionVitalSigns
|
||||
ips-vitalsigns.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/vitalsigns.html
|
||||
|
||||
ips-pregnancy.resourceType=Bundle
|
||||
ips-pregnancy.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/Pregnancy-uv-ips
|
||||
ips-pregnancy.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPregnancyHx
|
||||
ips-pregnancy.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/pregnancy.html
|
||||
|
||||
ips-socialhistory.resourceType=Bundle
|
||||
ips-socialhistory.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/SocialHistory-uv-ips
|
||||
ips-socialhistory.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionSocialHistory
|
||||
ips-socialhistory.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/socialhistory.html
|
||||
|
||||
ips-pasthistoryofillness.resourceType=Bundle
|
||||
|
@ -47,15 +47,15 @@ ips-pasthistoryofillness.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/
|
|||
ips-pasthistoryofillness.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/pasthistoryofillness.html
|
||||
|
||||
ips-functionalstatus.resourceType=Bundle
|
||||
ips-functionalstatus.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/FunctionalStatus-uv-ips
|
||||
ips-functionalstatus.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionFunctionalStatus
|
||||
ips-functionalstatus.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/functionalstatus.html
|
||||
|
||||
ips-planofcare.resourceType=Bundle
|
||||
ips-planofcare.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/PlanOfCare-uv-ips
|
||||
ips-planofcare.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionPlanOfCare
|
||||
ips-planofcare.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/planofcare.html
|
||||
|
||||
ips-advancedirectives.resourceType=Bundle
|
||||
ips-advancedirectives.profile=http://hl7.org/fhir/uv/ips/StructureDefinition/AdvanceDirectives-uv-ips
|
||||
ips-advancedirectives.profile=https://hl7.org/fhir/uv/ips/StructureDefinition-Composition-uv-ips-definitions.html#Composition.section:sectionAdvanceDirectives
|
||||
ips-advancedirectives.narrative=classpath:ca/uhn/fhir/jpa/ips/narrative/advancedirectives.html
|
||||
|
||||
################################################
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<!--/* MedicalDevices -->
|
||||
<!--
|
||||
Device: Device.type.coding.text || Device.type.coding[x].display
|
||||
Status: DeviceUseStatement.status.code
|
||||
Comments: DeviceUseStatement.note[x].text (display all notes separated by <br /> )
|
||||
Date Recorded: DeviceUseStatement.recordedOn
|
||||
Device: Device.type.text || Device.type.coding[x].display (separated by <br />)
|
||||
Status: DeviceUseStatement.status
|
||||
Comments: DeviceUseStatement.note[x].text (separated by <br />)
|
||||
Date Recorded: DeviceUseStatement.recordedDateTime
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<!--/* MedicationSummary -->
|
||||
<!--
|
||||
Table 1 MedicationRequest
|
||||
Medication: MedicationRequest.medicationCodeableConcept.coding[x].display || Medication.code.coding.text || Medication.code.coding.code[x].display
|
||||
Table 1 Medication Requests
|
||||
Medication: MedicationRequest.medicationCodeableConcept.text || MedicationRequest.medicationCodeableConcept.coding[x].display (separated by <br />) || Medication.code.text || Medication.code.coding[x].display (separated by <br />)
|
||||
Status: MedicationRequest.status.display
|
||||
Route: MedicationRequest.dosageInstruction[x].route.coding[x].display
|
||||
Sig: MedicationRequest.dosageInstruction[x].text (display all sigs separated by <br /> )
|
||||
Comments: MedicationRequest.note[x].text (display all notes separated by <br /> )
|
||||
Authored Date: MedicationRequest.DateTime
|
||||
Route: MedicationRequest.dosageInstruction[x].{ route.text || route.coding[x].display (separated by <br />) } (concatenate with comma, e.g. x, y, z)
|
||||
Sig: MedicationRequest.dosageInstruction[x].text (display all sigs separated by <br />)
|
||||
Comments: MedicationRequest.note[x].text (separated by <br />)
|
||||
Authored Date: MedicationRequest.authoredOn
|
||||
|
||||
Table 2 MedicationStatement
|
||||
Medication: MedicationStatement.medicationCodeableConcept.coding[x].display || Medication.code.coding.text || Medication.code.coding.code[x].display
|
||||
Table 2 Medication Statements
|
||||
Medication: MedicationStatement.medicationCodeableConcept.text || MedicationStatement.medicationCodeableConcept.coding[x].display (separated by <br />) || Medication.code.text || Medication.code.coding[x].display (separated by <br />)
|
||||
Status: MedicationStatement.status.display
|
||||
Route: MedicationStatement.dosage[x].route.coding[x].display
|
||||
Sig: MedicationStatement.dosage[x].text (display all sigs separated by <br /> )
|
||||
Date: MedicationStatement.effectiveDateTime
|
||||
Route: MedicationStatement.dosage[x].{ route.text || route.coding[x].display (separated by <br />) } (concatenate with comma, e.g. x, y, z)
|
||||
Sig: MedicationStatement.dosage[x].text (display all sigs separated by <br />)
|
||||
Date: MedicationStatement.effectiveDateTime || MedicationStatement.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<!--/* PastHistoryOfIllnesses -->
|
||||
<!--
|
||||
Medical Problem: Condition.code.text || Condition.code.coding[x].display
|
||||
Status: Condition.clinicalStatus.coding[x].display
|
||||
Comments: Condition.note[x].text (display all notes separated by <br /> )
|
||||
Onset Date: Condition.onsetDateTime
|
||||
Medical Problems: Condition.code.text || Condition.code.coding[x].display (separated by <br />)
|
||||
Status: Condition.clinicalStatus.text || Condition.clinicalStatus.coding[x].display (separated by <br />)
|
||||
Comments: Condition.note[x].text (separated by <br />)
|
||||
Onset Date: Condition.onsetDateTime || Condition.onsetPeriod.start && “-“ && Condition.onsetPeriod.end || Condition.onsetAge || Condition.onsetRange.low && “-“ && Condition.onsetRange.high || Condition.onsetString
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<!--
|
||||
Activity: CarePlan.description
|
||||
Intent: CarePlan.intent.code
|
||||
Comments: CarePlan.dosage [x].text // Not dosaage but note... right?
|
||||
Comments: CarePlan.note[x].text (separated by <br />)
|
||||
Planned Start: CarePlan.period.start
|
||||
Planned End: CarePlan.period.end
|
||||
*/-->
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<!--/* Pregnancy -->
|
||||
<!--
|
||||
Code: Observation.code.text || Observation.code.coding[x].display
|
||||
Result: Observation.valueQuantity.value || Observation.valueDateTime || Observation.valueCodeableConcept.coding[x].display || Observation.valueString
|
||||
Comments: Observation.note[x].text (display all notes separated by <br /> )
|
||||
Date: Observation.effectiveDateTime
|
||||
Code: Observation.code.text || Observation.code.coding[x].display (separated by <br />)
|
||||
Result: Observation.valueQuantity || Observation.valueDateTime || Observation.valueCodeableConcept.text || Observation.valueCodeableConcept.coding[x].display (separated by <br />) || Observation.valueString
|
||||
Comments: Observation.note[x].text (separated by <br />)
|
||||
Date: Observation.effectiveDateTime || Observation.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<!--/* ProblemList -->
|
||||
<!--
|
||||
Medical Problem: Condition.code.text || Condition.code.coding[x].display
|
||||
Status: Condition.clinicalStatus.coding[x].display
|
||||
Comments: Condition.note[x].text (display all notes separated by <br /> )
|
||||
Onset Date: Condition.onsetDateTime
|
||||
Medical Problems: Condition.code.text || Condition.code.coding[x].display (separated by <br />)
|
||||
Status: Condition.clinicalStatus.text || Condition.clinicalStatus.coding[x].display (separated by <br />)
|
||||
Comments: Condition.note[x].text (separated by <br />)
|
||||
Onset Date: Condition.onsetDateTime || Condition.onsetPeriod.start && “-“ && Condition.onsetPeriod.end || Condition.onsetAge || Condition.onsetRange.low && “-“ && Condition.onsetRange.high || Condition.onsetString
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<!--/* SocialHistory -->
|
||||
<!--
|
||||
Code: Observation.code.text || Observation.code.coding[x].display
|
||||
Result: Observation.valueQuantity.value || Observation.valueCodeableConcept.coding[x].display || Observation.valueString
|
||||
Code: Observation.code.text || Observation.code.coding[x].display (separated by <br />)
|
||||
Result: Observation.valueQuantity || Observation.valueDateTime || Observation.valueCodeableConcept.text || Observation.valueCodeableConcept.coding[x].display (separated by <br />) || Observation.valueString
|
||||
Unit: Observation.valueQuantity.unit
|
||||
Comments: Observation.note[x].text (display all notes separated by <br /> )
|
||||
Date: Observation.effectiveDateTime
|
||||
Comments: Observation.note[x].text (separated by <br />)
|
||||
Date: Observation.effectiveDateTime || Observation.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<!--/* VitalSigns -->
|
||||
<!--
|
||||
Code: Observation.code.text || Observation.code.coding[x].display
|
||||
Result: Observation.valueQuantity.value || Observation.valueCodeableConcept.coding[x].display || Observation.valueString
|
||||
Code: Observation.code.text || Observation.code.coding[x].display (separated by <br />)
|
||||
Result: Observation.valueQuantity || Observation.valueDateTime || Observation.valueCodeableConcept.text || Observation.valueCodeableConcept.coding[x].display (separated by <br />) || Observation.valueString
|
||||
Unit: Observation.valueQuantity.unit
|
||||
Interpretation: Observation.interpretation.text || Observation. interpretation.coding[x].display
|
||||
Comments: Observation.note[x].text (display all notes separated by <br /> )
|
||||
Date: Observation.effectiveDateTime
|
||||
Interpretation: Observation.interpretation[0].text || Observation.interpretation[0].coding[x].display (separated by <br />)
|
||||
Comments: Observation.note[x].text (separated by <br />)
|
||||
Date: Observation.effectiveDateTime || Observation.effectivePeriod.start
|
||||
*/-->
|
||||
<div xmlns:th="http://www.thymeleaf.org">
|
||||
<table class="hapiPropertyTable">
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.ips.generator;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.ips.api.IIpsGenerationStrategy;
|
||||
|
@ -9,11 +12,15 @@ import ca.uhn.fhir.jpa.ips.strategy.DefaultIpsGenerationStrategy;
|
|||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||
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.Composition;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.MedicationStatement;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
|
@ -27,16 +34,25 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@ContextConfiguration(classes = {IpsGenerationTest.IpsConfig.class})
|
||||
public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
||||
/**
|
||||
* This test uses a complete R4 JPA server as a backend and wires the
|
||||
* {@link IpsOperationProvider} into the REST server to test the end-to-end
|
||||
* IPS generation flow.
|
||||
*/
|
||||
@ContextConfiguration(classes = {IpsGenerationR4Test.IpsConfig.class})
|
||||
public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
@Autowired
|
||||
private IpsOperationProvider myIpsOperationProvider;
|
||||
|
@ -74,13 +90,16 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
validateDocument(outcome);
|
||||
validateDocument(output);
|
||||
assertEquals(117, output.getEntry().size());
|
||||
String patientId = findFirstEntryResource(output, Patient.class, 1).getId();
|
||||
assertThat(patientId, matchesPattern("urn:uuid:.*"));
|
||||
MedicationStatement medicationStatement = findFirstEntryResource(output, MedicationStatement.class, 2);
|
||||
assertEquals(patientId, medicationStatement.getSubject().getReference());
|
||||
assertNull(medicationStatement.getInformationSource().getReference());
|
||||
|
||||
List<String> sectionTitles = extractSectionTitles(output);
|
||||
assertThat(sectionTitles.toString(), sectionTitles, contains("Allergies and Intolerances", "Medication List", "Problem List", "History of Immunizations", "Diagnostic Results"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -106,19 +125,46 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
validateDocument(outcome);
|
||||
validateDocument(output);
|
||||
assertEquals(7, output.getEntry().size());
|
||||
String patientId = findFirstEntryResource(output, Patient.class, 1).getId();
|
||||
assertThat(patientId, matchesPattern("urn:uuid:.*"));
|
||||
assertEquals(patientId, findEntryResource(output, Condition.class, 0, 2).getSubject().getReference());
|
||||
assertEquals(patientId, findEntryResource(output, Condition.class, 1, 2).getSubject().getReference());
|
||||
|
||||
List<String> sectionTitles = extractSectionTitles(output);
|
||||
assertThat(sectionTitles.toString(), sectionTitles, contains("Allergies and Intolerances", "Medication List", "Problem List"));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static List<String> extractSectionTitles(Bundle outcome) {
|
||||
Composition composition = (Composition) outcome.getEntry().get(0).getResource();
|
||||
List<String> sectionTitles = composition
|
||||
.getSection()
|
||||
.stream()
|
||||
.map(Composition.SectionComponent::getTitle)
|
||||
.toList();
|
||||
return sectionTitles;
|
||||
}
|
||||
|
||||
private void validateDocument(Bundle theOutcome) {
|
||||
FhirValidator validator = myFhirContext.newValidator();
|
||||
validator.registerValidatorModule(new FhirInstanceValidator(myFhirContext));
|
||||
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(myFhirContext);
|
||||
instanceValidator.setValidationSupport(new ValidationSupportChain(new IpsTerminologySvc(), myFhirContext.getValidationSupport()));
|
||||
validator.registerValidatorModule(instanceValidator);
|
||||
ValidationResult validation = validator.validateWithResult(theOutcome);
|
||||
assertTrue(validation.isSuccessful(), () -> myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(validation.toOperationOutcome()));
|
||||
|
||||
// Make sure that all refs have been replaced with UUIDs
|
||||
List<ResourceReferenceInfo> references = myFhirContext.newTerser().getAllResourceReferences(theOutcome);
|
||||
for (IBaseResource next : myFhirContext.newTerser().getAllEmbeddedResources(theOutcome, true)) {
|
||||
references.addAll(myFhirContext.newTerser().getAllResourceReferences(next));
|
||||
}
|
||||
for (ResourceReferenceInfo next : references) {
|
||||
if (!next.getResourceReference().getReferenceElement().getValue().startsWith("urn:uuid:")) {
|
||||
fail(next.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -159,4 +205,51 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
return (T) resources.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a little fake terminology server that hardcodes the IPS terminology
|
||||
* needed to validate these documents. This way we don't need to depend on a huge
|
||||
* package.
|
||||
*/
|
||||
private class IpsTerminologySvc implements IValidationSupport {
|
||||
@Override
|
||||
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||
if ("http://loinc.org".equals(theCodeSystem)) {
|
||||
if ("60591-5".equals(theCode)) {
|
||||
return new CodeValidationResult().setCode(theCode);
|
||||
}
|
||||
}
|
||||
if ("http://snomed.info/sct".equals(theCodeSystem)) {
|
||||
if ("14657009".equals(theCode) || "255604002".equals(theCode)) {
|
||||
return new CodeValidationResult().setCode(theCode);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBaseResource fetchCodeSystem(String theSystem) {
|
||||
if ("http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips".equals(theSystem)) {
|
||||
CodeSystem cs = new CodeSystem();
|
||||
cs.setUrl("http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips");
|
||||
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||
cs.addConcept().setCode("no-allergy-info");
|
||||
cs.addConcept().setCode("no-medication-info");
|
||||
cs.addConcept().setCode("no-known-allergies");
|
||||
return cs;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FhirContext getFhirContext() {
|
||||
return myFhirContext;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,40 +14,10 @@ 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.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.gargoylesoftware.htmlunit.html.*;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
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.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -61,17 +31,19 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.ips.generator.IpsGenerationTest.findEntryResource;
|
||||
import static ca.uhn.fhir.jpa.ips.generator.IpsGenerationR4Test.findEntryResource;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
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.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* This test verifies various IPS generation logic without using a full
|
||||
* JPA backend.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class IpsGeneratorSvcImplTest {
|
||||
|
||||
|
@ -103,6 +75,37 @@ 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());
|
||||
|
@ -124,7 +127,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
assertThat(contentResourceTypes.toString(), contentResourceTypes,
|
||||
Matchers.contains("Composition", "Patient", "AllergyIntolerance", "MedicationStatement", "MedicationStatement", "MedicationStatement", "Condition", "Condition", "Condition", "Organization"));
|
||||
contains("Composition", "Patient", "AllergyIntolerance", "MedicationStatement", "MedicationStatement", "MedicationStatement", "Condition", "Condition", "Condition", "Organization"));
|
||||
|
||||
Composition composition = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section;
|
||||
|
@ -145,7 +148,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
String compositionNarrative = composition.getText().getDivAsString();
|
||||
ourLog.info("Composition narrative: {}", compositionNarrative);
|
||||
assertThat(compositionNarrative, containsString("Allergies and Intolerances"));
|
||||
assertThat(compositionNarrative, containsString("Pregnancy"));
|
||||
assertThat(compositionNarrative, not(containsString("Pregnancy")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -168,7 +171,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
assertThat(contentResourceTypes.toString(), contentResourceTypes,
|
||||
Matchers.contains("Composition", "Patient", "AllergyIntolerance", "MedicationStatement", "Medication", "Condition", "Organization"));
|
||||
contains("Composition", "Patient", "AllergyIntolerance", "MedicationStatement", "Medication", "Condition", "Organization"));
|
||||
MedicationStatement actualMedicationStatement = (MedicationStatement) outcome.getEntry().get(3).getResource();
|
||||
Medication actualMedication = (Medication) outcome.getEntry().get(4).getResource();
|
||||
assertThat(actualMedication.getId(), startsWith("urn:uuid:"));
|
||||
|
@ -226,7 +229,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
assertThat(contentResourceTypes.toString(), contentResourceTypes,
|
||||
Matchers.contains(
|
||||
contains(
|
||||
"Composition",
|
||||
"Patient",
|
||||
"MedicationStatement",
|
||||
|
@ -265,7 +268,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
assertThat(contentResourceTypes.toString(), contentResourceTypes,
|
||||
Matchers.contains(
|
||||
contains(
|
||||
"Composition",
|
||||
"Patient",
|
||||
"MedicationStatement",
|
||||
|
@ -337,7 +340,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
// Setup Medication + MedicationStatement
|
||||
Organization org = new Organization();
|
||||
org.setId(new IdType("Organization/pfizer"));
|
||||
org.setName("Pfizer");
|
||||
org.setName("Pfizer Inc");
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(org, BundleEntrySearchModeEnum.INCLUDE);
|
||||
|
||||
Immunization immunization = new Immunization();
|
||||
|
@ -374,13 +377,12 @@ public class IpsGeneratorSvcImplTest {
|
|||
assertEquals("SpikeVax", row.getCell(0).asNormalizedText());
|
||||
assertEquals("COMPLETED", row.getCell(1).asNormalizedText());
|
||||
assertEquals("2 , 4", row.getCell(2).asNormalizedText());
|
||||
assertEquals("Pfizer", row.getCell(3).asNormalizedText());
|
||||
assertEquals("Pfizer Inc", row.getCell(3).asNormalizedText());
|
||||
assertEquals("35", row.getCell(4).asNormalizedText());
|
||||
assertEquals("Hello World", row.getCell(5).asNormalizedText());
|
||||
assertThat(row.getCell(6).asNormalizedText(), containsString("2023"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReferencesUpdatedInSecondaryInclusions() {
|
||||
// Setup Patient
|
||||
|
@ -422,6 +424,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
|
||||
// Verify cross-references
|
||||
Patient addedPatient = findEntryResource(outcome, Patient.class, 0, 1);
|
||||
|
@ -452,6 +455,46 @@ public class IpsGeneratorSvcImplTest {
|
|||
assertEquals(1, illnessHistorySection.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatientIsReturnedAsAnIncludeResource() {
|
||||
// Setup Patient
|
||||
registerPatientDaoWithRead();
|
||||
|
||||
// Setup Condition
|
||||
Condition conditionActive = new Condition();
|
||||
conditionActive.setId("Condition/conditionActive");
|
||||
conditionActive.getClinicalStatus().addCoding()
|
||||
.setSystem("http://terminology.hl7.org/CodeSystem/condition-clinical")
|
||||
.setCode("active");
|
||||
conditionActive.setSubject(new Reference(PATIENT_ID));
|
||||
conditionActive.setEncounter(new Reference(ENCOUNTER_ID));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(conditionActive, BundleEntrySearchModeEnum.MATCH);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId(PATIENT_ID);
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(patient, BundleEntrySearchModeEnum.INCLUDE);
|
||||
|
||||
IFhirResourceDao<Condition> conditionDao = registerResourceDaoWithNoData(Condition.class);
|
||||
when(conditionDao.search(any(), any())).thenReturn(
|
||||
new SimpleBundleProvider(Lists.newArrayList(conditionActive, patient)),
|
||||
new SimpleBundleProvider()
|
||||
);
|
||||
|
||||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
List<String> resources = outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.map(t -> t.getResource().getResourceType().name())
|
||||
.collect(Collectors.toList());
|
||||
assertThat(resources.toString(), resources, contains(
|
||||
"Composition", "Patient", "AllergyIntolerance", "MedicationStatement", "Condition", "Organization"
|
||||
));
|
||||
}
|
||||
|
||||
private void registerPatientDaoWithRead() {
|
||||
IFhirResourceDao<Patient> patientDao = registerResourceDaoWithNoData(Patient.class);
|
||||
Patient patient = new Patient();
|
||||
|
@ -499,35 +542,4 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
Binary file not shown.
Loading…
Reference in New Issue