Skip to content

Commit

Permalink
EA-206 - Support automatic closing of inpatient visits after a certai…
Browse files Browse the repository at this point in the history
…n period of inactivity (#249)
  • Loading branch information
mseaton authored Oct 23, 2024
1 parent 36e524e commit 0cc6ecc
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ public class EmrApiConstants {

public static final int DEFAULT_VISIT_EXPIRE_HOURS = 12;

public static final String GP_INPATIENT_VISIT_EXPIRE_HOURS = "emrapi.inpatientVisitExpireHours";

/*public static final String CONCEPT_CODE_DISPOSITION = "Disposition";
public static final String CONCEPTDISPOSITION_ANSWER_ADMIT = "Admit";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ public int getVisitExpireHours() {
return NumberUtils.toInt(getGlobalProperty(EmrApiConstants.GP_VISIT_EXPIRE_HOURS, false), EmrApiConstants.DEFAULT_VISIT_EXPIRE_HOURS);
}

public Integer getInpatientVisitExpireHours() {
String gpVal = getGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS, false);
return StringUtils.hasText(gpVal) ? NumberUtils.toInt(gpVal) : null;
}

public VisitType getAtFacilityVisitType() {
return getEmrApiMetadataByCode(VisitType.class, EmrApiConstants.GP_AT_FACILITY_VISIT_TYPE);
}
Expand Down
45 changes: 28 additions & 17 deletions api/src/main/java/org/openmrs/module/emrapi/adt/AdtServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

package org.openmrs.module.emrapi.adt;

import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.BooleanUtils;
import org.joda.time.DateTime;
import org.openmrs.Concept;
import org.openmrs.Encounter;
Expand Down Expand Up @@ -73,6 +73,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;


public class AdtServiceImpl extends BaseOpenmrsService implements AdtService {
Expand Down Expand Up @@ -187,31 +188,41 @@ public boolean shouldBeClosed(Visit visit) {

VisitDomainWrapper visitDomainWrapper = domainWrapperFactory.newVisitDomainWrapper(visit);

if (visitDomainWrapper.isAdmitted() || visitDomainWrapper.isAwaitingAdmission()) {
return false; // don't close the visit if patient is admitted or waiting admission
}
Date now = new Date();
Date lastActivity = getLastActivityDate(visit);
long hoursInactive = TimeUnit.HOURS.convert(Math.abs(lastActivity.getTime() - now.getTime()), TimeUnit.MILLISECONDS);

Disposition mostRecentDisposition = visitDomainWrapper.getMostRecentDisposition();
if (mostRecentDisposition != null && mostRecentDisposition.getKeepsVisitOpen() != null && mostRecentDisposition.getKeepsVisitOpen()) {
return false; // don't close the visit if the most recent disposition is one that keeps visit opens
boolean inpatient = (visitDomainWrapper.isAdmitted() || visitDomainWrapper.isAwaitingAdmission());
if (!inpatient) {
Disposition mostRecentDisposition = visitDomainWrapper.getMostRecentDisposition();
inpatient = mostRecentDisposition != null && BooleanUtils.isTrue(mostRecentDisposition.getKeepsVisitOpen());
}

Date now = new Date();
Date mustHaveSomethingAfter = DateUtils.addHours(now, -emrApiProperties.getVisitExpireHours());

if (OpenmrsUtil.compare(visit.getStartDatetime(), mustHaveSomethingAfter) >= 0) {
return false;
if (inpatient) {
Integer inpatientVisitExpireHours = emrApiProperties.getInpatientVisitExpireHours();
return (inpatientVisitExpireHours != null && inpatientVisitExpireHours <= hoursInactive);
}
return emrApiProperties.getVisitExpireHours() <= hoursInactive;
}

/**
* Returns the last activity date for the given visit
* Currently this checks the Visit startDatetime, and the encounterDatetime for each Encounter in the Visit
* @param visit the Visit to check
* @return the number of minutes since the last activity
*/
protected Date getLastActivityDate(Visit visit) {
Date lastActivityDate = visit.getStartDatetime();
if (visit.getEncounters() != null) {
for (Encounter candidate : visit.getEncounters()) {
if (!candidate.isVoided() && OpenmrsUtil.compare(candidate.getEncounterDatetime(), mustHaveSomethingAfter) >= 0) {
return false;
for (Encounter e : visit.getEncounters()) {
if (BooleanUtils.isNotTrue(e.getVoided())) {
if (lastActivityDate.before(e.getEncounterDatetime())) {
lastActivityDate = e.getEncounterDatetime();
}
}
}
}

return true;
return lastActivityDate;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.openmrs.api.ConceptService;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
Expand Down Expand Up @@ -48,6 +49,24 @@ public void visitExpireHours_shouldBeDefaultValueWhenNotConfiguredAsNonInteger()

assertEquals(EmrApiConstants.DEFAULT_VISIT_EXPIRE_HOURS, emrApiProperties.getVisitExpireHours());
}

@Test
public void inpatientVisitExpireHours_shouldBeConfiguredValueFromGlobalProperty(){
when(administrationService.getGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS)).thenReturn("72");
assertEquals(72, emrApiProperties.getInpatientVisitExpireHours().intValue());
}

@Test
public void inpatientVisitExpireHours_shouldBeNullWhenBlank(){
when(administrationService.getGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS)).thenReturn(" ");
assertNull(emrApiProperties.getInpatientVisitExpireHours());
}

@Test
public void inpatientVisitExpireHours_shouldBeNullWhenNull(){
when(administrationService.getGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS)).thenReturn(null);
assertNull(emrApiProperties.getInpatientVisitExpireHours());
}

@Test
public void getConceptSourcesForDiagnosisSearch_shouldNotReturnNull(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.openmrs.Patient;
import org.openmrs.Provider;
import org.openmrs.Visit;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.ConceptService;
import org.openmrs.api.EncounterService;
import org.openmrs.api.LocationService;
Expand All @@ -45,8 +46,8 @@
import org.openmrs.module.emrapi.disposition.DispositionService;
import org.openmrs.module.emrapi.test.ContextSensitiveMetadataTestUtils;
import org.openmrs.module.emrapi.visit.VisitDomainWrapper;
import org.openmrs.test.BaseModuleContextSensitiveTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -64,7 +65,11 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.openmrs.module.emrapi.TestUtils.hasProviders;
import static org.openmrs.module.emrapi.adt.AdtAction.Type.ADMISSION;
import static org.openmrs.module.emrapi.adt.AdtAction.Type.DISCHARGE;
Expand Down Expand Up @@ -105,9 +110,14 @@ public boolean evaluate(Object o) {
@Autowired
EmrConceptService emrConceptService;

@Autowired
@Qualifier("adminService")
AdministrationService administrationService;

@Before
public void setUp() throws Exception {
executeDataSet("baseTestDataset.xml");
administrationService.setGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS, "");
}

@Test
Expand Down Expand Up @@ -465,6 +475,16 @@ public void test_shouldNotCloseVisitIfMostRecentDispositionKeepsVisitOpen() thro

activeVisit = service.getActiveVisit(patient, location);
assertNotNull(activeVisit);

administrationService.setGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS, "15");
service.closeInactiveVisits();
activeVisit = service.getActiveVisit(patient, location);
assertNotNull(activeVisit);

administrationService.setGlobalProperty(EmrApiConstants.GP_INPATIENT_VISIT_EXPIRE_HOURS, "14");
service.closeInactiveVisits();
activeVisit = service.getActiveVisit(patient, location);
assertNull(activeVisit);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void shouldGetAsJson() throws Exception {
@Test
public void shouldGetDefaultRepresentation() {
SimpleObject config = emrApiConfigurationController.getEmrApiConfiguration(request, response);
assertEquals(50, config.keySet().size());
assertEquals(51, config.keySet().size());
assertEquals("org.openmrs.module.emrapi", config.get("metadataSourceName"));
assertEquals("50", config.get("lastViewedPatientSizeLimit").toString());
Map<String, Object> unknownLocation = mapNode(config, "unknownLocation");
Expand Down

0 comments on commit 0cc6ecc

Please sign in to comment.