Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

O3-3193: REST API for EMR API ADT functionality #231

Merged
merged 3 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -344,5 +344,14 @@ VisitDomainWrapper createRetrospectiveVisit(Patient patient, Location location,
* @param visitIds - if non-null, only returns matches for visits with the given ids
* @return List<Visit></Visit> of the matching visits
*/
// TODO expand this to take in an admissionLocation parameter and limit to admissions at that location
List<Visit> getVisitsAwaitingAdmission(Location location, Collection<Integer> patientIds, Collection<Integer> visitIds);

/**
* Returns all patient awaiting transfer
* @param location - if non-null, only checks awaiting transfers at the visit location associated with this location TODO do we need this?
* @param transferLocation - if non-null, only returns matches for patients awaiting transfer to this location
* @return List<Visit> of the matching visits<
*/
List<Visit> getVisitsAwaitingTransfer(Location location, Location transferLocation);
}
Original file line number Diff line number Diff line change
Expand Up @@ -917,4 +917,11 @@ public List<Visit> getVisitsAwaitingAdmission(Location location, Collection<Inte
parameters.put("visitIds", visitIds);
return emrApiDAO.executeHqlFromResource("hql/visits_awaiting_admission.hql", parameters, Visit.class);
}

@Override
@Transactional(readOnly = true)
public List<Visit> getVisitsAwaitingTransfer(Location location, Location transferLocation) {
// TODO implement!
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -54,6 +56,7 @@
import static java.util.Collections.EMPTY_LIST;
import static java.util.Collections.reverseOrder;
import static java.util.Collections.sort;
import static org.apache.commons.collections.CollectionUtils.filter;
import static org.apache.commons.collections.CollectionUtils.find;
import static org.apache.commons.collections.CollectionUtils.select;

Expand Down Expand Up @@ -532,6 +535,35 @@ public Location getInpatientLocation(Date onDate) {
return null;
}

public Integer timeSinceAdmissionInMinutes() {
if (getAdmissionEncounter() == null) {
return null;
} else {
return Minutes.minutesBetween(new DateTime(getAdmissionEncounter().getEncounterDatetime()), new DateTime()).getMinutes();
}
}

public Integer timeAtLocationInMinutes() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename this "timeAtInpatientLocationInMinutes". This basically correspondes to the Location returned by the getInpatientLocation method

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, make sense!

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)) {
time = Minutes.minutesBetween(new DateTime(encounter.getEncounterDatetime()), new DateTime()).getMinutes();
Copy link
Member

@mseaton mseaton Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting time here doesn't seem right, as you are setting the time before you are comparing the ward to the encounter location. So this will actually end up with the time since the encounter right before the encounter at the current location. You should only set the time if ward == null || ward.equals(encounter.getLocation()) (eg. after the if /else statement, not before it)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just did it like that to make sure I had something to test and fail against... :) no, duh, will add the tests and fix...

if (ward == null) {
ward = encounter.getLocation();
}
else if (!ward.equals(encounter.getLocation())) {
break;
}
}
}
return time;
}

public Date getStartDatetime() {
return visit.getStartDatetime();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<SimpleObject> getInpatientVisits(@RequestParam(value = "currentLocation") Location currentLocation) {
mseaton marked this conversation as resolved.
Show resolved Hide resolved

// TODO expand to allow null current location

// TODO handle null response if possible
// TODO this getInpatentVisits method is almost certainly not performant enough for production use and will likely need to be refactored into a HQL query
List<VisitDomainWrapper> visits = adtService.getInpatientVisits(adtService.getLocationThatSupportsVisits(currentLocation), currentLocation);

// TODO type this?
List<SimpleObject> response = new ArrayList<SimpleObject>();

for (VisitDomainWrapper visit : visits) {
SimpleObject inpatientVisit = new SimpleObject();
inpatientVisit.put("visit", ConversionUtil.convertToRepresentation(visit.getVisit(), Representation.DEFAULT));
mseaton marked this conversation as resolved.
Show resolved Hide resolved
inpatientVisit.put("patient", ConversionUtil.convertToRepresentation(visit.getVisit().getPatient(), Representation.DEFAULT));
inpatientVisit.put("currentLocation", ConversionUtil.convertToRepresentation(currentLocation, Representation.DEFAULT));
inpatientVisit.put("timeSinceAdmissionInMinutes", visit.timeSinceAdmissionInMinutes());
inpatientVisit.put("timeAtLocationdInMinutes", visit.timeAtLocationInMinutes());
response.add(inpatientVisit);
}

return response;
}

@RequestMapping(method = RequestMethod.GET, value = "/admissionRequests")
@ResponseBody
public List<SimpleObject> getVisitsAwaitingAdmission(@RequestParam("admissionLocation") Location admissionLocation) {
return getVisitsAwaitingAdmissionHelper(admissionLocation);
}

@RequestMapping(method = RequestMethod.GET, value = "/transferRequests")
@ResponseBody
public List<SimpleObject> getVisitsAwaitingTransfer(@RequestParam("transferLocation") Location transferLocation) {
return getVisitsAwaitingTransferHelper(transferLocation);
}

@RequestMapping(method = RequestMethod.GET, value = "/admissionAndTransferRequests")
@ResponseBody
public List<SimpleObject> getVisitsAwaitingAdminstOrTransfer(@RequestParam("location") Location location) {
List<SimpleObject> response = getVisitsAwaitingAdmissionHelper(location);
response.addAll(getVisitsAwaitingTransferHelper(location));
return response;
}


private List<SimpleObject> getVisitsAwaitingAdmissionHelper(Location admissionLocation) {
// TODO note that this service method *only* returns admission requests, while we will need to expand this to include transfer requests (which will be slightly non-trivial)
// 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
List<Visit> visits = adtService.getVisitsAwaitingAdmission(admissionLocation, null, null);
List<SimpleObject> visitObjects = new ArrayList<SimpleObject>();
for (Visit visit : visits) {
SimpleObject inpatientVisit = new SimpleObject();
inpatientVisit.put("visit", ConversionUtil.convertToRepresentation(visit, Representation.DEFAULT));
mseaton marked this conversation as resolved.
Show resolved Hide resolved
inpatientVisit.put("patient", ConversionUtil.convertToRepresentation(visit.getPatient(), Representation.DEFAULT));
inpatientVisit.put("type", AdtAction.Type.ADMISSION);
visitObjects.add(inpatientVisit);
}
return visitObjects;
}

private List<SimpleObject> getVisitsAwaitingTransferHelper(Location transferLocation) {
List<Visit> visits = adtService.getVisitsAwaitingTransfer(null, transferLocation);
List<SimpleObject> visitObjects = new ArrayList<SimpleObject>();
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;
}

}



Loading