From 9f434e3602f53468d428f6c58d3c57bbd5a81843 Mon Sep 17 00:00:00 2001 From: k4pran Date: Wed, 3 Apr 2024 09:39:10 +0100 Subject: [PATCH] FM2-608: Add EpisodeOfCare FHIR2 Module with Mapping of Patient Program --- .../fhir2/api/FhirEpisodeOfCareService.java | 20 +++ .../fhir2/api/dao/FhirEpisodeOfCareDao.java | 23 +++ .../dao/impl/FhirEpisodeOfCareDaoImpl.java | 22 +++ .../impl/FhirEpisodeOfCareServiceImpl.java | 35 ++++ .../translators/EpisodeOfCareTranslator.java | 46 +++++ .../impl/EpisodeOfCareTranslatorImpl.java | 98 ++++++++++ .../r3/EpisodeOfCareFhirResourceProvider.java | 49 +++++ .../r4/EpisodeOfCareFhirResourceProvider.java | 48 +++++ .../impl/FhirEpisodeOfCareDaoImplTest.java | 64 +++++++ .../FhirEpisodeOfCareServiceImplTest.java | 69 ++++++++ .../impl/EpisodeOfCareTranslatorImplTest.java | 167 ++++++++++++++++++ ...EpisodeOfCareFhirResourceProviderTest.java | 81 +++++++++ ...EpisodeOfCareFhirResourceProviderTest.java | 81 +++++++++ .../module/fhir2/narratives.properties | 3 + .../fhir2/narratives/EpisodeOfCare.html | 46 +++++ ...sodeOfCareDaoImpl_2_2Test_initial_data.xml | 22 +++ 16 files changed, 874 insertions(+) create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/FhirEpisodeOfCareService.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/dao/FhirEpisodeOfCareDao.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImpl.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/translators/EpisodeOfCareTranslator.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImpl.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProvider.java create mode 100644 api/src/main/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProvider.java create mode 100644 api/src/test/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImplTest.java create mode 100644 api/src/test/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImplTest.java create mode 100644 api/src/test/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImplTest.java create mode 100644 api/src/test/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProviderTest.java create mode 100644 api/src/test/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProviderTest.java create mode 100644 omod/src/main/resources/org/openmrs/module/fhir2/narratives/EpisodeOfCare.html create mode 100644 test-data/src/main/resources/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl_2_2Test_initial_data.xml diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/FhirEpisodeOfCareService.java b/api/src/main/java/org/openmrs/module/fhir2/api/FhirEpisodeOfCareService.java new file mode 100644 index 0000000000..6eaba5237c --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/FhirEpisodeOfCareService.java @@ -0,0 +1,20 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api; + +import javax.annotation.Nonnull; + +import org.hl7.fhir.r4.model.EpisodeOfCare; + +public interface FhirEpisodeOfCareService extends FhirService { + + @Override + EpisodeOfCare get(@Nonnull String uuid); +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/FhirEpisodeOfCareDao.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/FhirEpisodeOfCareDao.java new file mode 100644 index 0000000000..89c12335d6 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/FhirEpisodeOfCareDao.java @@ -0,0 +1,23 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.dao; + +import javax.annotation.Nonnull; + +import org.openmrs.PatientProgram; +import org.openmrs.annotation.Authorized; +import org.openmrs.util.PrivilegeConstants; + +public interface FhirEpisodeOfCareDao extends FhirDao { + + @Override + @Authorized(PrivilegeConstants.GET_PATIENT_PROGRAMS) + PatientProgram get(@Nonnull String uuid); +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl.java new file mode 100644 index 0000000000..74b1ff7fb8 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl.java @@ -0,0 +1,22 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.dao.impl; + +import lombok.AccessLevel; +import lombok.Setter; +import org.openmrs.PatientProgram; +import org.openmrs.module.fhir2.api.dao.FhirEpisodeOfCareDao; +import org.springframework.stereotype.Component; + +@Component +@Setter(AccessLevel.PACKAGE) +public class FhirEpisodeOfCareDaoImpl extends BaseFhirDao implements FhirEpisodeOfCareDao { + +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImpl.java new file mode 100644 index 0000000000..4be95c18d3 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImpl.java @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.impl; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.openmrs.PatientProgram; +import org.openmrs.module.fhir2.api.FhirEpisodeOfCareService; +import org.openmrs.module.fhir2.api.dao.FhirEpisodeOfCareDao; +import org.openmrs.module.fhir2.api.translators.EpisodeOfCareTranslator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional +@Setter(AccessLevel.PACKAGE) +@Getter(AccessLevel.PROTECTED) +public class FhirEpisodeOfCareServiceImpl extends BaseFhirService implements FhirEpisodeOfCareService { + + @Autowired + private FhirEpisodeOfCareDao dao; + + @Autowired + private EpisodeOfCareTranslator translator; +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/translators/EpisodeOfCareTranslator.java b/api/src/main/java/org/openmrs/module/fhir2/api/translators/EpisodeOfCareTranslator.java new file mode 100644 index 0000000000..cadff27929 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/translators/EpisodeOfCareTranslator.java @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.translators; + +import javax.annotation.Nonnull; + +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.openmrs.PatientProgram; + +public interface EpisodeOfCareTranslator extends OpenmrsFhirUpdatableTranslator { + + /** + * Maps a {@link org.openmrs.PatientProgram} to a {@link EpisodeOfCare} + * + * @param patientProgram the PatientProgram to translate + * @return the corresponding FHIR EpisodeOfCare + */ + @Override + EpisodeOfCare toFhirResource(@Nonnull PatientProgram patientProgram); + + /** + * Maps a {@link EpisodeOfCare} to a {@link org.openmrs.PatientProgram} + * + * @param episodeOfCare the FHIR EpisodeOfCare to map + * @return the corresponding OpenMRS PatientProgram + */ + @Override + PatientProgram toOpenmrsType(@Nonnull EpisodeOfCare episodeOfCare); + + /** + * Maps a {@link EpisodeOfCare} to an existing {@link org.openmrs.PatientProgram} + * + * @param patientProgram the PatientProgram to update + * @param episodeOfCare the FHIR EpisodeOfCare to map + * @return the updated OpenMRS PatientProgram + */ + @Override + PatientProgram toOpenmrsType(@Nonnull PatientProgram patientProgram, @Nonnull EpisodeOfCare episodeOfCare); +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImpl.java new file mode 100644 index 0000000000..f030283dc6 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImpl.java @@ -0,0 +1,98 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.translators.impl; + +import static org.apache.commons.lang3.Validate.notNull; + +import javax.annotation.Nonnull; + +import java.util.Collections; +import java.util.List; + +import lombok.AccessLevel; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.hl7.fhir.r4.model.Period; +import org.openmrs.PatientProgram; +import org.openmrs.module.fhir2.api.translators.ConceptTranslator; +import org.openmrs.module.fhir2.api.translators.EpisodeOfCareTranslator; +import org.openmrs.module.fhir2.api.translators.PatientReferenceTranslator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Setter(AccessLevel.PACKAGE) +public class EpisodeOfCareTranslatorImpl implements EpisodeOfCareTranslator { + + @Autowired + private PatientReferenceTranslator patientReferenceTranslator; + + @Autowired + private ConceptTranslator conceptTranslator; + + @Override + public EpisodeOfCare toFhirResource(@Nonnull PatientProgram patientProgram) { + notNull(patientProgram, "The Openmrs PatientProgram object should not be null"); + + EpisodeOfCare episodeOfCare = new EpisodeOfCare(); + + episodeOfCare.setId(patientProgram.getUuid()); + episodeOfCare.setPeriod(getPeriod(patientProgram)); + episodeOfCare.setPatient(patientReferenceTranslator.toFhirResource(patientProgram.getPatient())); + episodeOfCare.setType(getType(patientProgram)); + + episodeOfCare.setStatus(getStatus(patientProgram)); + + return episodeOfCare; + } + + @Override + public PatientProgram toOpenmrsType(@Nonnull EpisodeOfCare episodeOfCare) { + notNull(episodeOfCare, "The EpisodeOfCare object should not be null"); + return this.toOpenmrsType(new PatientProgram(), episodeOfCare); + } + + @Override + public PatientProgram toOpenmrsType(@Nonnull PatientProgram patientProgram, @Nonnull EpisodeOfCare episodeOfCare) { + throw new UnsupportedOperationException("Translation from FHIR resource EpisodeOfCare to OpenMRS object PatientProgram is not supported."); + } + + private List getType(PatientProgram patientProgram) { + if (patientProgram.getProgram() == null) { + return Collections.emptyList(); + } + + CodeableConcept codeableConcept = conceptTranslator.toFhirResource(patientProgram.getProgram().getConcept()); + if (codeableConcept == null) { + return Collections.emptyList(); + } + return Collections.singletonList(codeableConcept); + } + + private EpisodeOfCare.EpisodeOfCareStatus getStatus(PatientProgram patientProgram) { + if (patientProgram.getActive()) { + return EpisodeOfCare.EpisodeOfCareStatus.ACTIVE; + } else { + return EpisodeOfCare.EpisodeOfCareStatus.FINISHED; + } + } + + private Period getPeriod(PatientProgram program) { + Period period = new Period(); + + period.setStart(program.getDateEnrolled()); + period.setEnd(program.getDateCompleted()); + + return period; + } +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProvider.java b/api/src/main/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProvider.java new file mode 100644 index 0000000000..46e03bf6c0 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProvider.java @@ -0,0 +1,49 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.providers.r3; + +import static lombok.AccessLevel.PACKAGE; + +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import lombok.Setter; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40; +import org.hl7.fhir.dstu3.model.EpisodeOfCare; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.openmrs.module.fhir2.api.FhirEpisodeOfCareService; +import org.openmrs.module.fhir2.api.annotations.R3Provider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("episodeOfCareFhirR3ResourceProvider") +@R3Provider +@Setter(PACKAGE) +public class EpisodeOfCareFhirResourceProvider implements IResourceProvider { + + @Autowired + private FhirEpisodeOfCareService episodeOfCareService; + + @Override + public Class getResourceType() { + return EpisodeOfCare.class; + } + + @Read + public EpisodeOfCare getEpisodeOfCareById(@IdParam IdType id) { + org.hl7.fhir.r4.model.EpisodeOfCare episodeOfCare = episodeOfCareService.get(id.getIdPart()); + if (episodeOfCare == null) { + throw new ResourceNotFoundException("Could not find EpisodeOfCare with Id " + id.getIdPart()); + } + return (EpisodeOfCare) VersionConvertorFactory_30_40.convertResource(episodeOfCare); + } +} diff --git a/api/src/main/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProvider.java b/api/src/main/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProvider.java new file mode 100644 index 0000000000..8d0569b9cd --- /dev/null +++ b/api/src/main/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProvider.java @@ -0,0 +1,48 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.providers.r4; + +import static lombok.AccessLevel.PACKAGE; + +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import lombok.Setter; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.hl7.fhir.r4.model.IdType; +import org.openmrs.module.fhir2.api.FhirEpisodeOfCareService; +import org.openmrs.module.fhir2.api.annotations.R4Provider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("episodeOfCareFhirR4ResourceProvider") +@R4Provider +@Setter(PACKAGE) +public class EpisodeOfCareFhirResourceProvider implements IResourceProvider { + + @Autowired + private FhirEpisodeOfCareService episodeOfCareService; + + @Override + public Class getResourceType() { + return EpisodeOfCare.class; + } + + @Read + public EpisodeOfCare getEpisodeOfCareById(@IdParam IdType id) { + EpisodeOfCare episodeOfCare = episodeOfCareService.get(id.getIdPart()); + if (episodeOfCare == null) { + throw new ResourceNotFoundException("Could not find EpisodeOfCare with Id " + id.getIdPart()); + } + return episodeOfCare; + } +} diff --git a/api/src/test/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImplTest.java b/api/src/test/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImplTest.java new file mode 100644 index 0000000000..65813cbd2a --- /dev/null +++ b/api/src/test/java/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImplTest.java @@ -0,0 +1,64 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.dao.impl; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.hibernate.SessionFactory; +import org.junit.Before; +import org.junit.Test; +import org.openmrs.PatientProgram; +import org.openmrs.module.fhir2.TestFhirSpringConfiguration; +import org.openmrs.test.BaseModuleContextSensitiveTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration(classes = TestFhirSpringConfiguration.class, inheritLocations = false) +public class FhirEpisodeOfCareDaoImplTest extends BaseModuleContextSensitiveTest { + + private static final String ENCOUNTER_INITIAL_DATA_XML = "org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl_2_2Test_initial_data.xml"; + + private static final String EPISODE_OF_CARE_UUID = "9119b9f8-af3d-4ad8-9e2e-2317c3de91c6"; + + private static final String UNKNOWN_EPISODE_OF_CARE_UUID = "911xx9f8-ax3d-4ad8-9e2e-2317cxde91c6"; + + @Autowired + @Qualifier("sessionFactory") + private SessionFactory sessionFactory; + + private FhirEpisodeOfCareDaoImpl dao; + + @Before + public void setUp() throws Exception { + dao = new FhirEpisodeOfCareDaoImpl(); + dao.setSessionFactory(sessionFactory); + + executeDataSet(ENCOUNTER_INITIAL_DATA_XML); + } + + @Test + public void shouldReturnMatchingPatientProgram() { + PatientProgram patientProgram = dao.get(EPISODE_OF_CARE_UUID); + + assertThat(patientProgram, notNullValue()); + assertThat(patientProgram.getUuid(), notNullValue()); + assertThat(patientProgram.getUuid(), equalTo(EPISODE_OF_CARE_UUID)); + } + + @Test + public void shouldReturnNullWithUnknownPatientProgram() { + PatientProgram encounter = dao.get(UNKNOWN_EPISODE_OF_CARE_UUID); + assertThat(encounter, nullValue()); + } +} diff --git a/api/src/test/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImplTest.java b/api/src/test/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImplTest.java new file mode 100644 index 0000000000..f0774c2216 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/fhir2/api/impl/FhirEpisodeOfCareServiceImplTest.java @@ -0,0 +1,69 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.impl; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; + +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.openmrs.PatientProgram; +import org.openmrs.module.fhir2.api.dao.FhirEpisodeOfCareDao; +import org.openmrs.module.fhir2.api.translators.EpisodeOfCareTranslator; + +@RunWith(MockitoJUnitRunner.class) +public class FhirEpisodeOfCareServiceImplTest { + + private static final String EPISODE_OF_CARE_UUID = "9119b9f8-af3d-4ad8-9e2e-2317c3de91c6"; + + @Mock + private FhirEpisodeOfCareDao dao; + + @Mock + private EpisodeOfCareTranslator episodeOfCareTranslator; + + private FhirEpisodeOfCareServiceImpl episodeOfCareService; + + private PatientProgram patientProgram; + + private EpisodeOfCare episodeOfCare; + + @Before + public void setUp() { + episodeOfCareService = new FhirEpisodeOfCareServiceImpl(); + + episodeOfCareService.setDao(dao); + episodeOfCareService.setTranslator(episodeOfCareTranslator); + + patientProgram = new PatientProgram(); + patientProgram.setUuid(EPISODE_OF_CARE_UUID); + + episodeOfCare = new EpisodeOfCare(); + episodeOfCare.setId(EPISODE_OF_CARE_UUID); + } + + @Test + public void get_shouldGetEncounterByUuid() { + when(dao.get(EPISODE_OF_CARE_UUID)).thenReturn(patientProgram); + when(episodeOfCareTranslator.toFhirResource(patientProgram)).thenReturn(episodeOfCare); + + EpisodeOfCare actualEpisodeOfCare = episodeOfCareService.get(EPISODE_OF_CARE_UUID); + + assertThat(actualEpisodeOfCare, notNullValue()); + assertThat(actualEpisodeOfCare.getId(), notNullValue()); + assertThat(actualEpisodeOfCare.getId(), equalTo(EPISODE_OF_CARE_UUID)); + } +} diff --git a/api/src/test/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImplTest.java b/api/src/test/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImplTest.java new file mode 100644 index 0000000000..813dbb2306 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/fhir2/api/translators/impl/EpisodeOfCareTranslatorImplTest.java @@ -0,0 +1,167 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.api.translators.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import java.time.Instant; +import java.util.Date; + +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.Reference; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.openmrs.Concept; +import org.openmrs.PatientIdentifier; +import org.openmrs.PatientProgram; +import org.openmrs.Program; +import org.openmrs.module.fhir2.FhirConstants; +import org.openmrs.module.fhir2.FhirTestConstants; +import org.openmrs.module.fhir2.api.translators.ConceptTranslator; +import org.openmrs.module.fhir2.api.translators.PatientReferenceTranslator; + +@RunWith(MockitoJUnitRunner.class) +public class EpisodeOfCareTranslatorImplTest { + + private static final String PATIENT_UUID = "8549f706-7e85-4c1d-9424-217d50a2988b"; + + private static final String PATIENT_URI = FhirConstants.PATIENT + "/" + PATIENT_UUID; + + private static final String PATIENT_IDENTIFIER = "100024L"; + + @Mock + private PatientReferenceTranslator patientReferenceTranslator; + + @Mock + private ConceptTranslator conceptTranslator; + + private EpisodeOfCareTranslatorImpl episodeOfCareTranslator; + + @Before + public void setup() { + episodeOfCareTranslator = new EpisodeOfCareTranslatorImpl(); + episodeOfCareTranslator.setConceptTranslator(conceptTranslator); + episodeOfCareTranslator.setPatientReferenceTranslator(patientReferenceTranslator); + } + + @Test + public void shouldTranslateOpenmrsPatientToFhirPatient() { + PatientProgram patientProgram = new PatientProgram(); + + org.openmrs.Patient expectedPatient = new org.openmrs.Patient(); + expectedPatient.setUuid(PATIENT_UUID); + + PatientIdentifier patientIdentifier = new PatientIdentifier(); + patientIdentifier.setIdentifier(PATIENT_IDENTIFIER); + expectedPatient.addIdentifier(patientIdentifier); + + patientProgram.setPatient(expectedPatient); + + Reference patientReference = new Reference().setReference(PATIENT_URI).setType(FhirTestConstants.PATIENT) + .setIdentifier(new Identifier().setValue(PATIENT_IDENTIFIER)); + patientReference.setId(PATIENT_UUID); + + when(patientReferenceTranslator.toFhirResource(expectedPatient)).thenReturn(patientReference); + + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(episodeOfCare.getPatient(), notNullValue()); + assertThat(episodeOfCare.getPatient().getId(), equalTo(expectedPatient.getUuid())); + assertThat(episodeOfCare.getPatient().getIdentifier().getValue(), + equalTo(expectedPatient.getPatientIdentifier().getIdentifier())); + } + + @Test + public void shouldTranslateProgramConceptToEpisodeOfCareType() { + PatientProgram patientProgram = new PatientProgram(); + Program program = new Program(); + Concept concept = new Concept(); + CodeableConcept codeableConcept = new CodeableConcept(); + + program.setConcept(concept); + patientProgram.setProgram(program); + + when(conceptTranslator.toFhirResource(concept)).thenReturn(codeableConcept); + + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(episodeOfCare.getType().size(), is(1)); + assertThat(episodeOfCare.getType().get(0), is(codeableConcept)); + } + + @Test + public void shouldHandleNullProgram() { + PatientProgram patientProgram = new PatientProgram(); + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(episodeOfCare.getType().size(), is(0)); + } + + @Test + public void shouldHandleNullCodeableConcept() { + PatientProgram patientProgram = new PatientProgram(); + Program program = new Program(); + Concept concept = new Concept(); + + program.setConcept(concept); + patientProgram.setProgram(program); + + when(conceptTranslator.toFhirResource(concept)).thenReturn(null); + + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(episodeOfCare.getType().size(), is(0)); + } + + @Test + public void shouldTranslateOpenmrsActivePatientProgramToFhirActiveStatus() { + PatientProgram patientProgram = new PatientProgram(); + patientProgram.setDateEnrolled(Date.from(Instant.now())); + + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(patientProgram.getActive(), is(true)); + assertThat(episodeOfCare.getStatus(), is(EpisodeOfCare.EpisodeOfCareStatus.ACTIVE)); + } + + @Test + public void shouldTranslateVoidedPatientProgramToFinishesStatus() { + PatientProgram patientProgram = new PatientProgram(); + patientProgram.setDateEnrolled(Date.from(Instant.now())); + patientProgram.setVoided(true); + + EpisodeOfCare episodeOfCare = episodeOfCareTranslator.toFhirResource(patientProgram); + + assertThat(episodeOfCare, notNullValue()); + assertThat(episodeOfCare.getStatus(), is(EpisodeOfCare.EpisodeOfCareStatus.FINISHED)); + assertThat(patientProgram.getActive(), is(false)); + } + + @Test + public void shouldThrowsUnsupportedExceptionForTranslationToOpenmrsType() { + EpisodeOfCare episodeOfCare = new EpisodeOfCare(); + assertThrows(UnsupportedOperationException.class, () -> episodeOfCareTranslator.toOpenmrsType(episodeOfCare)); + } +} diff --git a/api/src/test/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProviderTest.java b/api/src/test/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProviderTest.java new file mode 100644 index 0000000000..a61d8251d3 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/fhir2/providers/r3/EpisodeOfCareFhirResourceProviderTest.java @@ -0,0 +1,81 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.providers.r3; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.when; + +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import org.hl7.fhir.dstu3.model.EpisodeOfCare; +import org.hl7.fhir.dstu3.model.IdType; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.openmrs.module.fhir2.api.FhirEpisodeOfCareService; + +@RunWith(MockitoJUnitRunner.class) +public class EpisodeOfCareFhirResourceProviderTest { + + private static final String EPISODE_OF_CARE_UUID = "8a849d5e-6011-4279-a124-40ada5a687de"; + + private static final String WRONG_EPISODE_OF_CARE_UUID = "b0a4b94e-cf7d-4a61-a3a1-4ca647580e2f"; + + @Mock + private FhirEpisodeOfCareService episodeOfCareService; + + private EpisodeOfCareFhirResourceProvider resourceProvider; + + private org.hl7.fhir.r4.model.EpisodeOfCare episodeOfCare; + + @Before + public void setup() { + resourceProvider = new EpisodeOfCareFhirResourceProvider(); + resourceProvider.setEpisodeOfCareService(episodeOfCareService); + } + + @Before + public void initEpisodeOfCare() { + episodeOfCare = new org.hl7.fhir.r4.model.EpisodeOfCare(); + episodeOfCare.setId(EPISODE_OF_CARE_UUID); + } + + @Test + public void getResourceType_shouldReturnResourceType() { + assertThat(resourceProvider.getResourceType(), equalTo(EpisodeOfCare.class)); + assertThat(resourceProvider.getResourceType().getName(), equalTo(EpisodeOfCare.class.getName())); + } + + @Test + public void getEpisodeOfCareById_shouldReturnEpisodeOfCare() { + IdType id = new IdType(); + id.setValue(EPISODE_OF_CARE_UUID); + when(episodeOfCareService.get(EPISODE_OF_CARE_UUID)).thenReturn(episodeOfCare); + + EpisodeOfCare result = resourceProvider.getEpisodeOfCareById(id); + assertThat(result.isResource(), is(true)); + assertThat(result, notNullValue()); + assertThat(result.getId(), notNullValue()); + assertThat(result.getId(), equalTo(EPISODE_OF_CARE_UUID)); + } + + @Test(expected = ResourceNotFoundException.class) + public void getEpisodeOfCareByWrongId_shouldThrowResourceNotFoundException() { + IdType idType = new IdType(); + idType.setValue(WRONG_EPISODE_OF_CARE_UUID); + assertThat(resourceProvider.getEpisodeOfCareById(idType).isResource(), is(true)); + assertThat(resourceProvider.getEpisodeOfCareById(idType), nullValue()); + } +} diff --git a/api/src/test/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProviderTest.java b/api/src/test/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProviderTest.java new file mode 100644 index 0000000000..55ab9245c6 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/fhir2/providers/r4/EpisodeOfCareFhirResourceProviderTest.java @@ -0,0 +1,81 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.fhir2.providers.r4; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.when; + +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.hl7.fhir.r4.model.IdType; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.openmrs.module.fhir2.api.FhirEpisodeOfCareService; + +@RunWith(MockitoJUnitRunner.class) +public class EpisodeOfCareFhirResourceProviderTest { + + private static final String EPISODE_OF_CARE_UUID = "8a849d5e-6011-4279-a124-40ada5a687de"; + + private static final String WRONG_EPISODE_OF_CARE_UUID = "b0a4b94e-cf7d-4a61-a3a1-4ca647580e2f"; + + @Mock + private FhirEpisodeOfCareService episodeOfCareService; + + private EpisodeOfCareFhirResourceProvider resourceProvider; + + private EpisodeOfCare episodeOfCare; + + @Before + public void setup() { + resourceProvider = new EpisodeOfCareFhirResourceProvider(); + resourceProvider.setEpisodeOfCareService(episodeOfCareService); + } + + @Before + public void initEpisodeOfCare() { + episodeOfCare = new EpisodeOfCare(); + episodeOfCare.setId(EPISODE_OF_CARE_UUID); + } + + @Test + public void getResourceType_shouldReturnResourceType() { + assertThat(resourceProvider.getResourceType(), equalTo(EpisodeOfCare.class)); + assertThat(resourceProvider.getResourceType().getName(), equalTo(EpisodeOfCare.class.getName())); + } + + @Test + public void getEpisodeOfCareById_shouldReturnEpisodeOfCare() { + IdType id = new IdType(); + id.setValue(EPISODE_OF_CARE_UUID); + when(episodeOfCareService.get(EPISODE_OF_CARE_UUID)).thenReturn(episodeOfCare); + + EpisodeOfCare result = resourceProvider.getEpisodeOfCareById(id); + assertThat(result.isResource(), is(true)); + assertThat(result, notNullValue()); + assertThat(result.getId(), notNullValue()); + assertThat(result.getId(), equalTo(EPISODE_OF_CARE_UUID)); + } + + @Test(expected = ResourceNotFoundException.class) + public void getEpisodeOfCareByWrongId_shouldThrowResourceNotFoundException() { + IdType idType = new IdType(); + idType.setValue(WRONG_EPISODE_OF_CARE_UUID); + assertThat(resourceProvider.getEpisodeOfCareById(idType).isResource(), is(true)); + assertThat(resourceProvider.getEpisodeOfCareById(idType), nullValue()); + } +} diff --git a/omod/src/main/resources/org/openmrs/module/fhir2/narratives.properties b/omod/src/main/resources/org/openmrs/module/fhir2/narratives.properties index 58b8c02399..2cfcb6b396 100644 --- a/omod/src/main/resources/org/openmrs/module/fhir2/narratives.properties +++ b/omod/src/main/resources/org/openmrs/module/fhir2/narratives.properties @@ -55,6 +55,9 @@ diagnosticReport.narrative=classpath:org/openmrs/module/fhir2/narratives/Diagnos encounter.resourceType=Encounter encounter.narrative=classpath:org/openmrs/module/fhir2/narratives/Encounter.html +episodeOfCare.resourceType=EpisodeOfCare +episodeOfCare.narrative=classpath:org/openmrs/module/fhir2/narratives/EpisodeOfCare.html + location.resourceType=Location location.narrative=classpath:org/openmrs/module/fhir2/narratives/Location.html diff --git a/omod/src/main/resources/org/openmrs/module/fhir2/narratives/EpisodeOfCare.html b/omod/src/main/resources/org/openmrs/module/fhir2/narratives/EpisodeOfCare.html new file mode 100644 index 0000000000..26acb66c3b --- /dev/null +++ b/omod/src/main/resources/org/openmrs/module/fhir2/narratives/EpisodeOfCare.html @@ -0,0 +1,46 @@ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + \ No newline at end of file diff --git a/test-data/src/main/resources/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl_2_2Test_initial_data.xml b/test-data/src/main/resources/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl_2_2Test_initial_data.xml new file mode 100644 index 0000000000..490e3e8f36 --- /dev/null +++ b/test-data/src/main/resources/org/openmrs/module/fhir2/api/dao/impl/FhirEpisodeOfCareDaoImpl_2_2Test_initial_data.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + +