diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/FhirEpisodeOfCareService.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/FhirEpisodeOfCareService.java new file mode 100644 index 00000000..2e136e0f --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/FhirEpisodeOfCareService.java @@ -0,0 +1,26 @@ +/* + * 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.ugandaemrsync.api; + +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.ReferenceAndListParam; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.openmrs.module.fhir2.api.FhirService; + +import javax.annotation.Nonnull; +import java.util.HashSet; + +public interface FhirEpisodeOfCareService extends FhirService { + IBundleProvider searchForEpisodeOfCares(ReferenceAndListParam patient, ReferenceAndListParam type, TokenAndListParam id, + DateRangeParam lastUpdated, HashSet includes, HashSet revIncludes); +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/FhirEpisodeOfCareDao.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/FhirEpisodeOfCareDao.java new file mode 100644 index 00000000..f9fa9c86 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/FhirEpisodeOfCareDao.java @@ -0,0 +1,38 @@ +/* + * 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.ugandaemrsync.api.dao; + +import org.openmrs.PatientProgram; +import org.openmrs.annotation.Authorized; +import org.openmrs.module.fhir2.api.dao.FhirDao; +import org.openmrs.module.fhir2.api.search.param.SearchParameterMap; +import org.openmrs.util.PrivilegeConstants; + +import javax.annotation.Nonnull; +import java.util.List; + +public interface FhirEpisodeOfCareDao extends FhirDao { + + @Override + @Authorized(PrivilegeConstants.GET_PATIENT_PROGRAMS) + PatientProgram get(@Nonnull String uuid); + + @Override + @Authorized({ PrivilegeConstants.ADD_PATIENT_PROGRAMS, PrivilegeConstants.EDIT_PATIENT_PROGRAMS }) + PatientProgram createOrUpdate(@Nonnull PatientProgram newEntry); + + @Override + @Authorized(PrivilegeConstants.DELETE_PATIENT_PROGRAMS) + PatientProgram delete(@Nonnull String uuid); + + @Override + @Authorized(PrivilegeConstants.GET_PATIENT_PROGRAMS) + List getSearchResults(@Nonnull SearchParameterMap theParams, @Nonnull List resourceIds); +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/impl/FhirEpisodeOfCareDaoImpl.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/impl/FhirEpisodeOfCareDaoImpl.java new file mode 100644 index 00000000..5470d558 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/dao/impl/FhirEpisodeOfCareDaoImpl.java @@ -0,0 +1,61 @@ +/* + * 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.ugandaemrsync.api.dao.impl; + +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.ReferenceAndListParam; +import lombok.AccessLevel; +import lombok.Setter; +import org.hibernate.Criteria; + +import org.openmrs.Encounter; +import org.openmrs.PatientProgram; +import org.openmrs.annotation.Authorized; +import org.openmrs.module.fhir2.FhirConstants; +import org.openmrs.module.fhir2.api.dao.FhirEncounterDao; +import org.openmrs.module.fhir2.api.dao.impl.BaseFhirDao; +import org.openmrs.module.fhir2.api.search.param.SearchParameterMap; +import org.openmrs.module.ugandaemrsync.api.dao.FhirEpisodeOfCareDao; +import org.openmrs.util.PrivilegeConstants; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.List; + +@Component +@Setter(AccessLevel.PACKAGE) +public class FhirEpisodeOfCareDaoImpl extends BaseFhirDao implements FhirEpisodeOfCareDao { + @Override + protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams) { + theParams.getParameters().forEach(entry -> { + switch (entry.getKey()) { + case FhirConstants.DATE_RANGE_SEARCH_HANDLER: + entry.getValue().forEach(param -> handleDateRange("dateEnrolled", (DateRangeParam) param.getParam()) + .ifPresent(criteria::add)); + break; + case FhirConstants.LOCATION_REFERENCE_SEARCH_HANDLER: + entry.getValue().forEach(param -> handleLocationReference("l", (ReferenceAndListParam) param.getParam()) + .ifPresent(l -> criteria.createAlias("location", "l").add(l))); + break; + case FhirConstants.PARTICIPANT_REFERENCE_SEARCH_HANDLER: + entry.getValue().forEach( + param -> handleParticipantReference(criteria, (ReferenceAndListParam) param.getParam())); + break; + case FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER: + entry.getValue() + .forEach(param -> handlePatientReference(criteria, (ReferenceAndListParam) param.getParam())); + break; + case FhirConstants.COMMON_SEARCH_HANDLER: + handleCommonSearchParameters(entry.getValue()).ifPresent(criteria::add); + break; + } + }); + } +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/impl/FhirEpisodeOfCareServiceImpl.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/impl/FhirEpisodeOfCareServiceImpl.java new file mode 100644 index 00000000..3fd08c2b --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/impl/FhirEpisodeOfCareServiceImpl.java @@ -0,0 +1,104 @@ +/* + * 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.ugandaemrsync.api.impl; + +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.ReferenceAndListParam; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.apache.poi.ss.formula.functions.T; +import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.openmrs.PatientProgram; +import org.openmrs.api.ProgramWorkflowService; +import org.openmrs.module.fhir2.FhirConstants; +import org.openmrs.module.fhir2.api.dao.FhirDao; +import org.openmrs.module.fhir2.api.impl.BaseFhirService; +import org.openmrs.module.fhir2.api.search.SearchQuery; +import org.openmrs.module.fhir2.api.search.SearchQueryInclude; +import org.openmrs.module.fhir2.api.search.param.SearchParameterMap; +import org.openmrs.module.fhir2.api.translators.OpenmrsFhirTranslator; +import org.openmrs.module.ugandaemrsync.api.FhirEpisodeOfCareService; +import org.openmrs.module.ugandaemrsync.api.dao.FhirEpisodeOfCareDao; +import org.openmrs.module.ugandaemrsync.api.translators.EpisodeOfCareTranslator; +import org.openmrs.module.ugandaemrsync.api.translators.impl.EpisodeOfCareTranslatorImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +@Transactional +@Setter(AccessLevel.PACKAGE) +@Getter(AccessLevel.PROTECTED) +public class FhirEpisodeOfCareServiceImpl extends BaseFhirService implements FhirEpisodeOfCareService { + + @Autowired + private FhirEpisodeOfCareDao dao; + + @Autowired + private EpisodeOfCareTranslator translator; + + @Autowired + private SearchQueryInclude searchQueryInclude; + + @Autowired + private SearchQuery, SearchQueryInclude> searchQuery; + + @Override + public EpisodeOfCare get(@Nonnull String uuid) { + + EpisodeOfCare result = null; + try { + result = super.get(uuid); + } catch (ResourceNotFoundException e) { + + } + + return result; + } + + @Override + protected FhirDao getDao() { + return this.dao; + } + + + @Override + protected OpenmrsFhirTranslator getTranslator() { + return this.translator; + } + + + @Override + @Transactional(readOnly = true) + public IBundleProvider searchForEpisodeOfCares(ReferenceAndListParam patient, ReferenceAndListParam type, TokenAndListParam id, + DateRangeParam lastUpdated, HashSet includes, HashSet revIncludes) { + SearchParameterMap theParams = new SearchParameterMap().addParameter(FhirConstants.DATE_RANGE_SEARCH_HANDLER, lastUpdated) + .addParameter(FhirConstants.PARTICIPANT_REFERENCE_SEARCH_HANDLER, patient) + .addParameter(FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER, type) + .addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.ID_PROPERTY, id) + .addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.LAST_UPDATED_PROPERTY, lastUpdated) + .addParameter(FhirConstants.INCLUDE_SEARCH_HANDLER, includes) + .addParameter(FhirConstants.REVERSE_INCLUDE_SEARCH_HANDLER, revIncludes); + return searchQuery.getQueryResults(theParams, dao, translator, searchQueryInclude); + } +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/EpisodeOfCareTranslator.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/EpisodeOfCareTranslator.java new file mode 100644 index 00000000..17f370cf --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/EpisodeOfCareTranslator.java @@ -0,0 +1,28 @@ +/* + * 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.ugandaemrsync.api.translators; + + +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.openmrs.module.fhir2.api.translators.OpenmrsFhirUpdatableTranslator; + +import javax.annotation.Nonnull; + +public interface EpisodeOfCareTranslator extends OpenmrsFhirUpdatableTranslator { + + /** + * Maps {@link org.openmrs.PatientProgram} to a {@link org.hl7.fhir.r4.model.EpisodeOfCare} resource + * + * @param patientProgram the OpenMRS patientProgram to translate + * @return the corresponding FHIR EpisodeOfCare resource + */ + @Override + EpisodeOfCare toFhirResource(@Nonnull T patientProgram); +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/impl/EpisodeOfCareTranslatorImpl.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/impl/EpisodeOfCareTranslatorImpl.java new file mode 100644 index 00000000..d7d0308a --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/api/translators/impl/EpisodeOfCareTranslatorImpl.java @@ -0,0 +1,115 @@ +/* + * 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.ugandaemrsync.api.translators.impl; + +import lombok.AccessLevel; +import lombok.Setter; +import org.hl7.fhir.r4.model.EpisodeOfCare; +import org.hl7.fhir.r4.model.Period; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Identifier; +import org.openmrs.PatientIdentifier; +import org.openmrs.PatientProgram; +import org.openmrs.api.context.Context; +import org.openmrs.module.fhir2.FhirConstants; +import org.openmrs.module.fhir2.api.translators.ConceptTranslator; +import org.openmrs.module.fhir2.api.translators.PatientIdentifierTranslator; +import org.openmrs.module.fhir2.api.translators.PatientReferenceTranslator; +import org.openmrs.module.ugandaemrsync.api.translators.EpisodeOfCareTranslator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +import static org.openmrs.module.ugandaemrsync.server.SyncConstant.GP_DHIS2; + +@Component +@Setter(AccessLevel.PACKAGE) +public class EpisodeOfCareTranslatorImpl implements EpisodeOfCareTranslator { + + @Autowired + private PatientReferenceTranslator patientReferenceTranslator; + + @Autowired + private PatientIdentifierTranslator patientIdentifierTranslator; + + @Autowired + private ConceptTranslator conceptTranslator; + + + @Override + public EpisodeOfCare toFhirResource(@Nonnull PatientProgram patientProgram) { + + Period period = new Period(); + period.setStart(patientProgram.getDateEnrolled()); + period.setEnd(patientProgram.getDateCompleted()); + List type = new ArrayList<>(); + type.add(conceptTranslator.toFhirResource(patientProgram.getProgram().getConcept())); + + EpisodeOfCare episodeOfCare = new EpisodeOfCare(); + episodeOfCare.setId(patientProgram.getUuid()); + episodeOfCare.setStatus(getStatus(patientProgram)); + episodeOfCare.setIdentifier(getEpisodeOfCareIdentifer(patientProgram)); + episodeOfCare.setManagingOrganization(createOrganizationReference()); + episodeOfCare.setPatient(patientReferenceTranslator.toFhirResource(patientProgram.getPatient())); + episodeOfCare.setPeriod(period); + episodeOfCare.setType(type); + return episodeOfCare; + } + + @Override + public PatientProgram toOpenmrsType(@Nonnull EpisodeOfCare episodeOfCare) { + return null; + } + + @Override + public PatientProgram toOpenmrsType(@Nonnull PatientProgram existingEncounter, @Nonnull EpisodeOfCare episodeOfCare) { + return null; + } + + protected Reference createOrganizationReference() { + String healthCenterIdentifier = Context.getAdministrationService().getGlobalProperty(GP_DHIS2); + String healthCenterName = Context.getLocationService().getLocationByUuid("629d78e9-93e5-43b0-ad8a-48313fd99117").getName(); + + Reference reference = new Reference().setReference(FhirConstants.ORGANIZATION + "/" + healthCenterIdentifier) + .setType(FhirConstants.ORGANIZATION); + + Identifier identifier = new Identifier(); + identifier.setUse(Identifier.IdentifierUse.OFFICIAL); + identifier.setValue(healthCenterIdentifier); + identifier.setSystem("https://hmis.health.go.ug/"); + + reference.setDisplay(healthCenterName); + reference.setIdentifier(identifier); + return reference; + } + + private List getEpisodeOfCareIdentifer(PatientProgram patientProgram) { + List identifiers = new ArrayList<>(); + Identifier identifier = new Identifier(); + identifier.setUse(Identifier.IdentifierUse.USUAL); + identifier.setValue(patientProgram.getUuid()); + identifier.setSystem("https://ugandaemr/"); + identifiers.add(identifier); + + return identifiers; + } + + private EpisodeOfCare.EpisodeOfCareStatus getStatus(PatientProgram patientProgram) { + if (patientProgram.getActive()) { + return EpisodeOfCare.EpisodeOfCareStatus.ACTIVE; + } else { + return EpisodeOfCare.EpisodeOfCareStatus.FINISHED; + } + } +} diff --git a/api/src/main/java/org/openmrs/module/ugandaemrsync/providers/r4/EpisodeOfCareProvider.java b/api/src/main/java/org/openmrs/module/ugandaemrsync/providers/r4/EpisodeOfCareProvider.java new file mode 100644 index 00000000..030105a9 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/ugandaemrsync/providers/r4/EpisodeOfCareProvider.java @@ -0,0 +1,86 @@ +package org.openmrs.module.ugandaemrsync.providers.r4; + +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.rest.annotation.*; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.ReferenceAndListParam; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import org.apache.commons.collections.CollectionUtils; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.*; +import org.openmrs.module.fhir2.providers.util.FhirProviderUtils; +import org.openmrs.module.ugandaemrsync.api.FhirEpisodeOfCareService; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.List; + +public class EpisodeOfCareProvider implements IResourceProvider { + @Autowired + private FhirEpisodeOfCareService episodeOfCareService; + + @Override + public Class getResourceType() { + return EpisodeOfCare.class; + } + + @Read + public EpisodeOfCare getEpisodeOfCareByUuid(@IdParam @Nonnull IdType id) { + EpisodeOfCare episodeOfCare = episodeOfCareService.get(id.getIdPart()); + if (episodeOfCare == null) { + throw new ResourceNotFoundException("Could not find episodeOfCare with Id " + id.getIdPart()); + } + return episodeOfCare; + } + + @Create + @SuppressWarnings("unused") + public MethodOutcome createEpisodeOfCare(@ResourceParam EpisodeOfCare episodeOfCare) { + return FhirProviderUtils.buildCreate(episodeOfCareService.create(episodeOfCare)); + } + + @Update + @SuppressWarnings("unused") + public MethodOutcome updateEpisodeOfCare(@IdParam IdType id, @ResourceParam EpisodeOfCare episodeOfCare) { + if (id == null || id.getIdPart() == null) { + throw new InvalidRequestException("id must be specified to update"); + } + + return FhirProviderUtils.buildUpdate(episodeOfCareService.update(id.getIdPart(), episodeOfCare)); + } + + @Delete + @SuppressWarnings("unused") + public OperationOutcome deleteEpisodeOfCare(@IdParam @Nonnull IdType id) { + episodeOfCareService.delete(id.getIdPart()); + return FhirProviderUtils.buildDeleteR4(); + } + + @History + @SuppressWarnings("unused") + public List getEpisodeOfCareHistoryById(@IdParam @Nonnull IdType id) { + EpisodeOfCare episodeOfCare = episodeOfCareService.get(id.getIdPart()); + if (episodeOfCare == null) { + throw new ResourceNotFoundException("Could not find episodeOfCare with Id " + id.getIdPart()); + } + return episodeOfCare.getContained(); + } + + @Search + public IBundleProvider searchEpisodeOfCare(@OptionalParam(name = EpisodeOfCare.SP_CARE_MANAGER, chainWhitelist = {"", org.hl7.fhir.dstu3.model.Practitioner.SP_IDENTIFIER, + org.hl7.fhir.dstu3.model.Practitioner.SP_GIVEN, org.hl7.fhir.dstu3.model.Practitioner.SP_FAMILY, + org.hl7.fhir.dstu3.model.Practitioner.SP_NAME}, targetTypes = org.hl7.fhir.dstu3.model.Practitioner.class) ReferenceAndListParam participantReference, + + @OptionalParam(name = EpisodeOfCare.SP_DATE) DateRangeParam date, + @OptionalParam(name = EpisodeOfCare.SP_IDENTIFIER) TokenAndListParam identifier) { + + return episodeOfCareService.searchForEpisodeOfCares(participantReference,null ,identifier, date, null,null); + } + +}