diff --git a/api/src/main/java/org/openmrs/module/emrapi/adt/AdtService.java b/api/src/main/java/org/openmrs/module/emrapi/adt/AdtService.java
index d16be9fd..cdb9ecf6 100644
--- a/api/src/main/java/org/openmrs/module/emrapi/adt/AdtService.java
+++ b/api/src/main/java/org/openmrs/module/emrapi/adt/AdtService.java
@@ -344,5 +344,13 @@ VisitDomainWrapper createRetrospectiveVisit(Patient patient, Location location,
* @param visitIds - if non-null, only returns matches for visits with the given ids
* @return List of the matching visits
*/
+ // TODO expand this to take in an admissionLocation parameter and limit to admissions at that location
List getVisitsAwaitingAdmission(Location location, Collection patientIds, Collection visitIds);
+
+ /**
+ * Returns all patient awaiting transfer
+ * @param transferLocation - if non-null, only return matches for patients awaiting transfer to this location
+ * @return List of the matching visits<
+ */
+ List getVisitsAwaitingTransfer(Location transferLocation);
}
diff --git a/api/src/main/java/org/openmrs/module/emrapi/adt/AdtServiceImpl.java b/api/src/main/java/org/openmrs/module/emrapi/adt/AdtServiceImpl.java
index 08a0abf7..69e42265 100644
--- a/api/src/main/java/org/openmrs/module/emrapi/adt/AdtServiceImpl.java
+++ b/api/src/main/java/org/openmrs/module/emrapi/adt/AdtServiceImpl.java
@@ -917,4 +917,11 @@ public List getVisitsAwaitingAdmission(Location location, Collection getVisitsAwaitingTransfer(Location transferLocation) {
+ // TODO implement!
+ return Collections.emptyList();
+ }
}
diff --git a/api/src/main/java/org/openmrs/module/emrapi/visit/VisitDomainWrapper.java b/api/src/main/java/org/openmrs/module/emrapi/visit/VisitDomainWrapper.java
index 0de780e2..008aae90 100644
--- a/api/src/main/java/org/openmrs/module/emrapi/visit/VisitDomainWrapper.java
+++ b/api/src/main/java/org/openmrs/module/emrapi/visit/VisitDomainWrapper.java
@@ -18,6 +18,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateMidnight;
+import org.joda.time.DateTime;
+import org.joda.time.Minutes;
import org.openmrs.Encounter;
import org.openmrs.EncounterType;
import org.openmrs.Location;
@@ -532,6 +534,40 @@ public Location getInpatientLocation(Date onDate) {
return null;
}
+ public Integer getTimeSinceAdmissionInMinutes() {
+ if (!isAdmitted() || getAdmissionEncounter() == null) {
+ return null;
+ } else {
+ return Minutes.minutesBetween(new DateTime(getAdmissionEncounter().getEncounterDatetime()), new DateTime()).getMinutes();
+ }
+ }
+
+ public Integer getTimeAtCurrentInpatientLocationInMinutes() {
+
+ if (!isAdmitted()) {
+ return null;
+ }
+
+ EncounterType admissionEncounterType = emrApiProperties.getAdmissionEncounterType();
+ EncounterType transferEncounterType = emrApiProperties.getTransferWithinHospitalEncounterType();
+
+ Location ward = null;
+ Integer time = null;
+
+ for (Encounter encounter : getSortedEncounters(SortOrder.MOST_RECENT_FIRST)) {
+ if (encounter.getEncounterType().equals(admissionEncounterType) || encounter.getEncounterType().equals(transferEncounterType)) {
+ if (ward == null) {
+ ward = encounter.getLocation();
+ }
+ else if (!ward.equals(encounter.getLocation())) {
+ break;
+ }
+ time = Minutes.minutesBetween(new DateTime(encounter.getEncounterDatetime()), new DateTime()).getMinutes();
+ }
+ }
+ return time;
+ }
+
public Date getStartDatetime() {
return visit.getStartDatetime();
}
diff --git a/api/src/test/java/org/openmrs/module/emrapi/visit/VisitDomainWrapperTest.java b/api/src/test/java/org/openmrs/module/emrapi/visit/VisitDomainWrapperTest.java
index 4575a156..0ac0e5d4 100644
--- a/api/src/test/java/org/openmrs/module/emrapi/visit/VisitDomainWrapperTest.java
+++ b/api/src/test/java/org/openmrs/module/emrapi/visit/VisitDomainWrapperTest.java
@@ -1010,6 +1010,154 @@ public void shouldNotFailIfStopDatetimeNull() {
assertNull(visitDomainWrapper.getStopDate());
}
+ @Test
+ public void timeSinceAdmissionInMinutes_shouldReturnTimeSinceAdmissionInMinutes() {
+
+ EncounterType admitEncounterType = new EncounterType();
+ EncounterType transferEncounterType = new EncounterType();
+
+ Location icu = new Location();
+
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+
+ EmrApiProperties props = mock(EmrApiProperties.class);
+ when(props.getAdmissionEncounterType()).thenReturn(admitEncounterType);
+ when(props.getTransferWithinHospitalEncounterType()).thenReturn(transferEncounterType);
+ visitDomainWrapper.setEmrApiProperties(props);
+
+ Encounter admit = new Encounter();
+ admit.setEncounterType(admitEncounterType);
+ admit.setEncounterDatetime(DateUtils.addHours(new Date(), -3));
+ admit.setLocation(icu);
+
+ Encounter transfer = new Encounter();
+ transfer.setEncounterType(transferEncounterType);
+ transfer.setEncounterDatetime(DateUtils.addHours(new Date(), -2));
+ transfer.setLocation(icu);
+
+ Set encounters = new LinkedHashSet();
+ encounters.add(admit);
+ encounters.add(transfer);
+ when(visit.getEncounters()).thenReturn(encounters);
+
+ assertThat(visitDomainWrapper.getTimeSinceAdmissionInMinutes(), is(180));
+ }
+
+ @Test
+ public void timeSinceAdmissionInMinutes_shouldReturnNullIfPatientNeverAdmitted() {
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+ assertNull(visitDomainWrapper.getTimeSinceAdmissionInMinutes());
+ }
+
+ @Test
+ public void timeSinceAdmissionInMinutes_shouldReturnNullIfPatientNoLongerAdmitted() {
+
+ EncounterType admitEncounterType = new EncounterType();
+ EncounterType exitFromInpatientEncounterType = new EncounterType();
+
+ Location icu = new Location();
+
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+
+ EmrApiProperties props = mock(EmrApiProperties.class);
+ when(props.getAdmissionEncounterType()).thenReturn(admitEncounterType);
+ when(props.getExitFromInpatientEncounterType()).thenReturn(exitFromInpatientEncounterType);
+ visitDomainWrapper.setEmrApiProperties(props);
+
+ Encounter admit = new Encounter();
+ admit.setEncounterType(admitEncounterType);
+ admit.setEncounterDatetime(DateUtils.addHours(new Date(), -3));
+ admit.setLocation(icu);
+
+ Encounter discharge = new Encounter();
+ discharge.setEncounterType(exitFromInpatientEncounterType);
+ discharge.setEncounterDatetime(DateUtils.addHours(new Date(), -2));
+ discharge.setLocation(icu);
+
+ Set encounters = new LinkedHashSet();
+ encounters.add(admit);
+ encounters.add(discharge);
+ when(visit.getEncounters()).thenReturn(encounters);
+
+ assertNull(visitDomainWrapper.getTimeSinceAdmissionInMinutes());
+ }
+
+ @Test
+ public void timeAtCurrentInpatientLocationInMinutes_shouldReturnTimeAtCurrentInpatientLocationInMinutesEvenWhenMostRecentAdtEncounterDoesNotResultInLocationChange() {
+
+ EncounterType admitEncounterType = new EncounterType();
+ EncounterType transferEncounterType = new EncounterType();
+
+ Location icu = new Location();
+
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+
+ EmrApiProperties props = mock(EmrApiProperties.class);
+ when(props.getAdmissionEncounterType()).thenReturn(admitEncounterType);
+ when(props.getTransferWithinHospitalEncounterType()).thenReturn(transferEncounterType);
+ visitDomainWrapper.setEmrApiProperties(props);
+
+ Encounter admit = new Encounter();
+ admit.setEncounterType(admitEncounterType);
+ admit.setEncounterDatetime(DateUtils.addHours(new Date(), -3));
+ admit.setLocation(icu);
+
+ // not sure if this is a real use case, transfer to same location, but just in case
+ Encounter transfer = new Encounter();
+ transfer.setEncounterType(transferEncounterType);
+ transfer.setEncounterDatetime(DateUtils.addHours(new Date(), -2));
+ transfer.setLocation(icu);
+
+ Set encounters = new LinkedHashSet();
+ encounters.add(admit);
+ encounters.add(transfer);
+ when(visit.getEncounters()).thenReturn(encounters);
+
+ assertThat(visitDomainWrapper.getTimeAtCurrentInpatientLocationInMinutes(), is(180));
+ }
+
+
+
+ @Test
+ public void timeAtCurrentInpatientLocationInMinutes_shouldReturnNullIfPatientNeverAdmitted() {
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+ assertNull(visitDomainWrapper.getTimeAtCurrentInpatientLocationInMinutes());
+ }
+
+ @Test
+ public void timeAtCurrentInpatientLocationInMinutes_shouldReturnNullIfPatientNoLongerAdmitted() {
+
+ EncounterType admitEncounterType = new EncounterType();
+ EncounterType exitFromInpatientEncounterType = new EncounterType();
+
+ Location icu = new Location();
+
+ when(visit.getStartDatetime()).thenReturn(DateUtils.addHours(new Date(), -5));
+
+ EmrApiProperties props = mock(EmrApiProperties.class);
+ when(props.getAdmissionEncounterType()).thenReturn(admitEncounterType);
+ when(props.getExitFromInpatientEncounterType()).thenReturn(exitFromInpatientEncounterType);
+ visitDomainWrapper.setEmrApiProperties(props);
+
+ Encounter admit = new Encounter();
+ admit.setEncounterType(admitEncounterType);
+ admit.setEncounterDatetime(DateUtils.addHours(new Date(), -3));
+ admit.setLocation(icu);
+
+ Encounter discharge = new Encounter();
+ discharge.setEncounterType(exitFromInpatientEncounterType);
+ discharge.setEncounterDatetime(DateUtils.addHours(new Date(), -2));
+ discharge.setLocation(icu);
+
+ Set encounters = new LinkedHashSet();
+ encounters.add(admit);
+ encounters.add(discharge);
+ when(visit.getEncounters()).thenReturn(encounters);
+
+ assertNull(visitDomainWrapper.getTimeAtCurrentInpatientLocationInMinutes());
+ }
+
+
private class ExpectedDiagnosis extends ArgumentMatcher {
private Diagnosis expectedDiagnosis;
diff --git a/omod/src/main/java/org/openmrs/module/emrapi/web/controller/EmrApiConfigController.java b/omod/src/main/java/org/openmrs/module/emrapi/web/controller/EmrApiConfigController.java
new file mode 100644
index 00000000..4a355668
--- /dev/null
+++ b/omod/src/main/java/org/openmrs/module/emrapi/web/controller/EmrApiConfigController.java
@@ -0,0 +1,27 @@
+package org.openmrs.module.emrapi.web.controller;
+
+import org.openmrs.module.emrapi.EmrApiProperties;
+import org.openmrs.module.webservices.rest.SimpleObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping(value = "/rest/emrapi/configuration")
+public class EmrApiConfigController {
+
+ @Autowired
+ private EmrApiProperties emrApiProperties;
+ @RequestMapping(method = RequestMethod.GET)
+ @ResponseBody
+ public SimpleObject getEmrApiConfig() {
+ SimpleObject response = new SimpleObject();
+ response.put("admissionEncounterType", emrApiProperties.getAdmissionEncounterType().getUuid());
+ response.put("transferWithinHospitalEncounterType", emrApiProperties.getTransferWithinHospitalEncounterType().getUuid());
+ response.put("exitFromInpatientEncounterTpye", emrApiProperties.getExitFromInpatientEncounterType().getUuid());
+ return response;
+ }
+
+}
diff --git a/omod/src/main/java/org/openmrs/module/emrapi/web/controller/InpatientVisitsController.java b/omod/src/main/java/org/openmrs/module/emrapi/web/controller/InpatientVisitsController.java
new file mode 100644
index 00000000..069bafed
--- /dev/null
+++ b/omod/src/main/java/org/openmrs/module/emrapi/web/controller/InpatientVisitsController.java
@@ -0,0 +1,106 @@
+package org.openmrs.module.emrapi.web.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openmrs.Location;
+import org.openmrs.Visit;
+import org.openmrs.module.emrapi.adt.AdtAction;
+import org.openmrs.module.emrapi.adt.AdtService;
+import org.openmrs.module.emrapi.visit.VisitDomainWrapper;
+import org.openmrs.module.webservices.rest.SimpleObject;
+import org.openmrs.module.webservices.rest.web.ConversionUtil;
+import org.openmrs.module.webservices.rest.web.representation.Representation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping(value = "/rest/emrapi/inpatient")
+public class InpatientVisitsController {
+
+ @Autowired
+ private AdtService adtService;
+
+ @RequestMapping(method = RequestMethod.GET, value = "/visits")
+ @ResponseBody
+ public List getInpatientVisits(@RequestParam(value = "currentLocation") Location currentLocation) {
+
+ if (currentLocation == null) {
+ throw new IllegalArgumentException("currentLocation is required");
+ }
+
+ List visits = adtService.getInpatientVisits(adtService.getLocationThatSupportsVisits(currentLocation), currentLocation);
+ List response = new ArrayList();
+
+ if (visits == null) {
+ return response;
+ }
+
+ for (VisitDomainWrapper visit : visits) {
+ SimpleObject inpatientVisit = new SimpleObject();
+ inpatientVisit.put("visit", ConversionUtil.convertToRepresentation(visit.getVisit(), Representation.DEFAULT));
+ inpatientVisit.put("patient", ConversionUtil.convertToRepresentation(visit.getVisit().getPatient(), Representation.DEFAULT));
+ inpatientVisit.put("currentLocation", ConversionUtil.convertToRepresentation(currentLocation, Representation.DEFAULT));
+ inpatientVisit.put("timeSinceAdmissionInMinutes", visit.getTimeSinceAdmissionInMinutes());
+ inpatientVisit.put("timeAtInpatientLocationdInMinutes", visit.getTimeAtCurrentInpatientLocationInMinutes());
+ response.add(inpatientVisit);
+ }
+
+ return response;
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/admissionRequests")
+ @ResponseBody
+ public List getVisitsAwaitingAdmission(@RequestParam("admissionLocation") Location admissionLocation) {
+ return getVisitsAwaitingAdmissionHelper(admissionLocation);
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/transferRequests")
+ @ResponseBody
+ public List getVisitsAwaitingTransfer(@RequestParam("transferLocation") Location transferLocation) {
+ return getVisitsAwaitingTransferHelper(transferLocation);
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/admissionAndTransferRequests")
+ @ResponseBody
+ public List getVisitsAwaitingAdminstOrTransfer(@RequestParam("location") Location location) {
+ List response = getVisitsAwaitingAdmissionHelper(location);
+ response.addAll(getVisitsAwaitingTransferHelper(location));
+ return response;
+ }
+
+ private List getVisitsAwaitingAdmissionHelper(Location admissionLocation) {
+ // TODO note also that this service method does *not* actually limit by admission location; we will need to expand the underlying service method/hql query to do this, see: https://openmrs.atlassian.net/browse/O3-3464
+ List visits = adtService.getVisitsAwaitingAdmission(admissionLocation, null, null);
+ List visitObjects = new ArrayList();
+ for (Visit visit : visits) {
+ SimpleObject inpatientVisit = new SimpleObject();
+ inpatientVisit.put("visit", ConversionUtil.convertToRepresentation(visit, Representation.DEFAULT));
+ inpatientVisit.put("patient", ConversionUtil.convertToRepresentation(visit.getPatient(), Representation.DEFAULT));
+ inpatientVisit.put("type", AdtAction.Type.ADMISSION);
+ visitObjects.add(inpatientVisit);
+ }
+ return visitObjects;
+ }
+
+ private List getVisitsAwaitingTransferHelper(Location transferLocation) {
+ List visits = adtService.getVisitsAwaitingTransfer(transferLocation);
+ List visitObjects = new ArrayList();
+ for (Visit visit : visits) {
+ SimpleObject inpatientVisit = new SimpleObject();
+ inpatientVisit.put("visit", ConversionUtil.convertToRepresentation(visit, Representation.DEFAULT));
+ inpatientVisit.put("patient", ConversionUtil.convertToRepresentation(visit.getPatient(), Representation.DEFAULT));
+ inpatientVisit.put("type", AdtAction.Type.TRANSFER);
+ visitObjects.add(inpatientVisit);
+ }
+ return visitObjects;
+ }
+
+}
+
+
+