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

EA-206 - Support automatic closing of inpatient visits after a certai… #249

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -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
Loading