From ca566d7c517c3e9add550368e3901bf50513f070 Mon Sep 17 00:00:00 2001 From: Michael Seaton Date: Mon, 18 Nov 2024 11:43:21 -0500 Subject: [PATCH] Add mechanism to migrate a patient's visit locations if needed --- .../migrations/VisitLocationMigrator.java | 81 +++++++++++++++++++ .../MigrateVisitLocationsPageController.java | 57 +++++++++++++ .../pages/patient/migrateVisitLocations.gsp | 57 +++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 api/src/main/java/org/openmrs/module/imbemr/migrations/VisitLocationMigrator.java create mode 100644 omod/src/main/java/org/openmrs/module/imbemr/page/controller/patient/MigrateVisitLocationsPageController.java create mode 100644 omod/src/main/webapp/pages/patient/migrateVisitLocations.gsp diff --git a/api/src/main/java/org/openmrs/module/imbemr/migrations/VisitLocationMigrator.java b/api/src/main/java/org/openmrs/module/imbemr/migrations/VisitLocationMigrator.java new file mode 100644 index 0000000..a2373b4 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/imbemr/migrations/VisitLocationMigrator.java @@ -0,0 +1,81 @@ +package org.openmrs.module.imbemr.migrations; + +import org.openmrs.Location; +import org.openmrs.Patient; +import org.openmrs.Visit; +import org.openmrs.api.VisitService; +import org.openmrs.module.emrapi.adt.AdtService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class exists to migrate visit locations where possible to ensure the locations + * associated with Visits are valid Visit Locations + */ +@Component +public class VisitLocationMigrator { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final VisitService visitService; + + private final AdtService adtService; + + public VisitLocationMigrator(@Autowired VisitService visitService, @Autowired AdtService adtService) { + this.visitService = visitService; + this.adtService = adtService; + } + + public Map getVisitsThatRequireLocationMigration(Patient patient) { + Map ret = new HashMap<>(); + List visitLocations = adtService.getAllLocationsThatSupportVisits(); + List visits = visitService.getVisitsByPatient(patient); + for (Visit visit : visits) { + Location existingVisitLocation = visit.getLocation(); + Location correctVisitLocation = getVisitLocation(existingVisitLocation, visitLocations); + if (correctVisitLocation != null && !correctVisitLocation.equals(existingVisitLocation)) { + ret.put(visit, correctVisitLocation); + } + } + return ret; + } + + public void migrateVisitLocationsForPatient(Patient patient) { + Map migrationRequired = getVisitsThatRequireLocationMigration(patient); + if (migrationRequired.isEmpty()) { + log.debug("Patient " + patient.getUuid() + " does not have any visits that require migration"); + return; + } + log.warn("Patient " + patient.getUuid() + " has " + migrationRequired.size() + " visits that require migration"); + for (Visit visit : migrationRequired.keySet()) { + migrationVisitLocation(visit, migrationRequired.get(visit)); + } + log.warn("Migration completed for patient"); + } + + public void migrationVisitLocation(Visit visit, Location correctLocation) { + log.warn("Updating location for visit " + visit.getUuid() + " from " + getLocationName(visit.getLocation()) + " to " + getLocationName(correctLocation)); + visit.setLocation(correctLocation); + visitService.saveVisit(visit); + } + + public Location getVisitLocation(Location location, List allowedLocations) { + if (allowedLocations.contains(location)) { + return location; + } + if (location.getParentLocation() != null) { + return getVisitLocation(location.getParentLocation(), allowedLocations); + } + return null; + } + + private String getLocationName(Location location) { + return location == null ? "null" : location.getName(); + } +} diff --git a/omod/src/main/java/org/openmrs/module/imbemr/page/controller/patient/MigrateVisitLocationsPageController.java b/omod/src/main/java/org/openmrs/module/imbemr/page/controller/patient/MigrateVisitLocationsPageController.java new file mode 100644 index 0000000..b24b21f --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/imbemr/page/controller/patient/MigrateVisitLocationsPageController.java @@ -0,0 +1,57 @@ +package org.openmrs.module.imbemr.page.controller.patient; + +import org.openmrs.Patient; +import org.openmrs.api.context.Context; +import org.openmrs.module.emrapi.patient.PatientDomainWrapper; +import org.openmrs.module.imbemr.migrations.VisitLocationMigrator; +import org.openmrs.ui.framework.UiUtils; +import org.openmrs.ui.framework.annotation.InjectBeans; +import org.openmrs.ui.framework.annotation.SpringBean; +import org.openmrs.ui.framework.page.PageModel; +import org.openmrs.util.PrivilegeConstants; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +public class MigrateVisitLocationsPageController { + + public String get(PageModel model, + @InjectBeans PatientDomainWrapper patientDomainWrapper, + @RequestParam(value = "patientId") Patient patient, + @SpringBean VisitLocationMigrator visitLocationMigrator) { + + if (!Context.hasPrivilege(PrivilegeConstants.EDIT_VISITS)) { + return "redirect:/index.htm"; + } + + patientDomainWrapper.setPatient(patient); + model.addAttribute("patient", patientDomainWrapper); + model.addAttribute("visitsToMigrate", visitLocationMigrator.getVisitsThatRequireLocationMigration(patient)); + return "patient/migrateVisitLocations"; + } + + public String post(PageModel model, UiUtils ui, HttpServletRequest request, + @InjectBeans PatientDomainWrapper patientDomainWrapper, + @RequestParam(value = "patientId") Patient patient, + @SpringBean VisitLocationMigrator visitLocationMigrator) { + + patientDomainWrapper.setPatient(patient); + + try { + visitLocationMigrator.migrateVisitLocationsForPatient(patient); + } + catch (Exception e) { + request.getSession().setAttribute("emr.errorMessage", e.getMessage()); + model.addAttribute("patient", patientDomainWrapper); + model.addAttribute("visitsToMigrate", visitLocationMigrator.getVisitsThatRequireLocationMigration(patient)); + return "patient/migrateVisitLocations"; + } + request.getSession().setAttribute("emr.infoMessage", "Visits migrated successfully"); + request.getSession().setAttribute("emr.toastMessage", "true"); + Map params = new HashMap<>(); + params.put("patientId", patient.getUuid()); + return "redirect:" + ui.pageLink("coreapps", "clinicianfacing/patient", params); + } +} diff --git a/omod/src/main/webapp/pages/patient/migrateVisitLocations.gsp b/omod/src/main/webapp/pages/patient/migrateVisitLocations.gsp new file mode 100644 index 0000000..2e806c0 --- /dev/null +++ b/omod/src/main/webapp/pages/patient/migrateVisitLocations.gsp @@ -0,0 +1,57 @@ +<% + ui.decorateWith("appui", "standardEmrPage") +%> + +${ ui.includeFragment("coreapps", "patientHeader", [ patient: patient.patient ]) } + +

Migrate Visit Locations

+ +<% if (visitsToMigrate.size() == 0) { %> + + This patient has no visits that need to be migrated + +<% } else { %> + + + + + + + + + + + + + <% visitsToMigrate.keySet().each { visit -> %> + + + + + + + <% } %> + +
Visit DateEncountersCurrent LocationCorrect Location
+ ${ ui.format(visit.startDatetime) } + + <% visit.encounters.eachWithIndex{ encounter, index -> %> + ${index == 0 ? "" : "
"} + ${ui.format(encounter.encounterDatetime)}: + ${ui.format(encounter.encounterType)} at ${ui.format(encounter.location)} + <% } %> +
+ ${ ui.format(visit.location) } + + ${ ui.format(visitsToMigrate.get(visit)) } +
+
+
+ + +
+
+<% } %> + + +