Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: openmrs/openmrs-core
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ae21c2c2749a
Choose a base ref
...
head repository: openmrs/openmrs-core
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bab6e3e35cf9
Choose a head ref
  • 3 commits
  • 8 files changed
  • 2 contributors

Commits on Feb 19, 2014

  1. Copy the full SHA
    749a495 View commit details

Commits on Mar 6, 2014

  1. Merge branch 'TRUNK-3963' of https://github.com/WolfSchlegel/openmrs-…

    …core into WolfSchlegel-TRUNK-3963
    dkayiwa committed Mar 6, 2014
    Copy the full SHA
    af097f2 View commit details
  2. Fixing failing tests for: Visit validator should prevent or allow

    overlapping of visits depending on global property - TRUNK-3963
    dkayiwa committed Mar 6, 2014
    Copy the full SHA
    bab6e3e View commit details
7 changes: 7 additions & 0 deletions api/src/main/java/org/openmrs/util/OpenmrsConstants.java
Original file line number Diff line number Diff line change
@@ -844,6 +844,8 @@ public static final Collection<String> AUTO_ROLES() {

public static final String GLOBAL_PROPERTY_ENABLE_VISITS = "visits.enabled";

public static final String GLOBAL_PROPERTY_ALLOW_OVERLAPPING_VISITS = "visits.allowOverlappingVisits";

public static final String GLOBAL_PROPERTY_DEFAULT_PATIENT_IDENTIFIER_VALIDATOR = "patient.defaultPatientIdentifierValidator";

public static final String GLOBAL_PROPERTY_PATIENT_IDENTIFIER_IMPORTANT_TYPES = "patient_identifier.importantTypes";
@@ -1550,6 +1552,11 @@ public static final List<GlobalProperty> CORE_GLOBAL_PROPERTIES() {
props.add(new GlobalProperty(GLOBAL_PROPERTY_USER_REQUIRE_EMAIL_AS_USERNAME, "false",
"Indicates whether a username must be a valid e-mail or not.", BooleanDatatype.class, null));

// TODO - understand how global properties work, what is defined in this class and what is stored in the DB?

// props.add(new GlobalProperty(GLOBAL_PROPERTY_ALLOW_OVERLAPPING_VISITS, "true",
// "true/false whether or not to allow visits of a given patient to overlap", BooleanDatatype.class, null));

for (GlobalProperty gp : ModuleFactory.getGlobalProperties()) {
props.add(gp);
}
72 changes: 72 additions & 0 deletions api/src/main/java/org/openmrs/validator/VisitValidator.java
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
import org.openmrs.Visit;
import org.openmrs.annotation.Handler;
import org.openmrs.api.context.Context;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
@@ -53,6 +54,16 @@ public boolean supports(Class<?> clazz) {
* @should fail if the startDatetime is after any encounter
* @should fail if the stopDatetime is before any encounter
* @should fail if an attribute is bad
*
* @should reject a visit if startDateTime is equal to startDateTime of another visit of the same patient
* @should reject a visit if startDateTime falls into another visit of the same patient
* @should reject a visit if stopDateTime falls into another visit of the same patient
* @should reject a visit if it contains another visit of the same patient
* @should accept a visit if startDateTime is equal to startDateTime of another voided visit of the same patient
* @should accept a visit if startDateTime falls into another voided visit of the same patient
* @should accept a visit if stopDateTime falls into another voided visit of the same patient
* @should accept a visit if it contains another voided visit of the same patient
*/
@Override
public void validate(Object target, Errors errors) {
@@ -86,6 +97,67 @@ public void validate(Object target, Errors errors) {

// check attributes
super.validateAttributes(visit, errors, Context.getVisitService().getAllVisitAttributeTypes());

// check start and end dates
if (disallowOverlappingVisits()) {
List<Visit> otherVisitList = Context.getVisitService().getVisitsByPatient(visit.getPatient());
for (Visit otherVisit : otherVisitList) {
validateStartDatetime(visit, otherVisit, errors);
validateStopDatetime(visit, otherVisit, errors);
}
}
}

/*
* Convenience method to make the code more readable.
*/
private boolean disallowOverlappingVisits() {
return !allowOverlappingVisits();
}

private boolean allowOverlappingVisits() {
return Boolean.parseBoolean(Context.getAdministrationService().getGlobalProperty(
OpenmrsConstants.GLOBAL_PROPERTY_ALLOW_OVERLAPPING_VISITS, "true"));
}

private void validateStartDatetime(Visit visit, Visit otherVisit, Errors errors) {

if (visit.getStartDatetime() != null && otherVisit.getStartDatetime() != null
&& visit.getStartDatetime().equals(otherVisit.getStartDatetime())) {
errors.rejectValue("startDatetime", "Visit.startCannotBeTheSameAsOtherStartDateOfTheSamePatient",
"This visit has the same start date and time as another visit of this patient.");
}

if (visit.getStartDatetime() != null && otherVisit.getStartDatetime() != null
&& otherVisit.getStopDatetime() != null && visit.getStartDatetime().after(otherVisit.getStartDatetime())
&& visit.getStartDatetime().before(otherVisit.getStopDatetime())) {
errors.rejectValue("startDatetime", "Visit.startDateCannotFallIntoAnotherVisitOfTheSamePatient",
"This visit has a start date that falls into another visit of the same patient.");
}
}

private void validateStopDatetime(Visit visit, Visit otherVisit, Errors errors) {

if (visit.getStopDatetime() != null && otherVisit.getStartDatetime() != null && otherVisit.getStopDatetime() != null
&& visit.getStopDatetime().after(otherVisit.getStartDatetime())
&& visit.getStopDatetime().before(otherVisit.getStopDatetime())) {
errors.rejectValue("stopDatetime", "Visit.stopDateCannotFallIntoAnotherVisitOfTheSamePatient",
"This visit has a stop date that falls into another visit of the same patient.");

}

if (visit.getStartDatetime() != null && visit.getStopDatetime() != null && otherVisit.getStartDatetime() != null
&& otherVisit.getStopDatetime() != null && visit.getStartDatetime().before(otherVisit.getStartDatetime())
&& visit.getStopDatetime().after(otherVisit.getStopDatetime())) {

StringBuilder messageBuilder = new StringBuilder();
messageBuilder.append("This visit contains another visit of the same patient, ");
messageBuilder.append("i.e. its start date is before the start date of the other visit ");
messageBuilder.append("and its stop date is after the stop date of the other visit.");

errors.rejectValue("stopDatetime", "Visit.visitCannotContainAnotherVisitOfTheSamePatient", messageBuilder
.toString());
}

}
}
94 changes: 53 additions & 41 deletions api/src/test/java/org/openmrs/api/VisitServiceTest.java
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@

import junit.framework.Assert;
import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openmrs.Concept;
@@ -30,6 +31,7 @@
import org.openmrs.test.BaseContextSensitiveTest;
import org.openmrs.test.TestUtil;
import org.openmrs.test.Verifies;
import org.openmrs.util.GlobalPropertiesTestHelper;
import org.openmrs.util.OpenmrsConstants;

import java.text.SimpleDateFormat;
@@ -57,11 +59,20 @@ public class VisitServiceTest extends BaseContextSensitiveTest {

protected static final String VISITS_ATTRIBUTES_XML = "org/openmrs/api/include/VisitServiceTest-visitAttributes.xml";

private VisitService service;
private GlobalPropertiesTestHelper globalPropertiesTestHelper;

private VisitService visitService;

@Before
public void before() {
service = Context.getVisitService();
visitService = Context.getVisitService();

// Allow overlapping visits. Ticket 3963 has introduced optional validation of start and stop dates
// based on concurrent visits of the same patient. Turning this validation on (i.e. not allowing
// overlapping visits) breaks existing tests of the visit service.
//
globalPropertiesTestHelper = new GlobalPropertiesTestHelper(Context.getAdministrationService());
globalPropertiesTestHelper.setGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ALLOW_OVERLAPPING_VISITS, "true");
}

@Test
@@ -354,14 +365,14 @@ public void voidVisit_shouldVoidTheVisitAndSetTheVoidReason() throws Exception {
public void voidVisit_shouldVoidEncountersWithVisit() throws Exception {
//given
executeDataSet(VISITS_WITH_DATES_XML);
Visit visit = service.getVisit(7);
Visit visit = visitService.getVisit(7);
Assert.assertFalse(visit.isVoided());

List<Encounter> encountersByVisit = Context.getEncounterService().getEncountersByVisit(visit, false);
Assert.assertFalse(encountersByVisit.isEmpty());

//when
visit = service.voidVisit(visit, "test reason");
visit = visitService.voidVisit(visit, "test reason");

//then
assertTrue(visit.isVoided());
@@ -397,19 +408,19 @@ public void unvoidVisit_shouldUnvoidTheVisitAndUnsetAllTheVoidRelatedFields() th
public void unvoidVisit_shouldUnvoidEncountersVoidedWithVisit() throws Exception {
//given
executeDataSet(VISITS_WITH_DATES_XML);
Visit visit = service.getVisit(7);
Visit visit = visitService.getVisit(7);

List<Encounter> encountersByVisit = Context.getEncounterService().getEncountersByVisit(visit, true);
assertEquals(2, encountersByVisit.size());

service.voidVisit(visit, "test reason");
visitService.voidVisit(visit, "test reason");
assertTrue(visit.isVoided());

encountersByVisit = Context.getEncounterService().getEncountersByVisit(visit, false);
assertTrue(encountersByVisit.isEmpty());

//when
visit = service.unvoidVisit(visit);
visit = visitService.unvoidVisit(visit);

//then
Assert.assertFalse(visit.isVoided());
@@ -579,7 +590,7 @@ public void saveVisitType_shouldThrowErrorWhenNameIsEmptyString() throws Excepti
@Test
public void getAllVisitAttributeTypes_shouldReturnAllVisitAttributeTypesIncludingRetiredOnes() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals(3, service.getAllVisitAttributeTypes().size());
assertEquals(3, visitService.getAllVisitAttributeTypes().size());
}

/**
@@ -589,7 +600,7 @@ public void getAllVisitAttributeTypes_shouldReturnAllVisitAttributeTypesIncludin
@Test
public void getVisitAttributeType_shouldReturnTheVisitAttributeTypeWithTheGivenId() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals("Audit Date", service.getVisitAttributeType(1).getName());
assertEquals("Audit Date", visitService.getVisitAttributeType(1).getName());
}

/**
@@ -599,7 +610,7 @@ public void getVisitAttributeType_shouldReturnTheVisitAttributeTypeWithTheGivenI
@Test
public void getVisitAttributeType_shouldReturnNullIfNoVisitAttributeTypeExistsWithTheGivenId() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Assert.assertNull(service.getVisitAttributeType(999));
Assert.assertNull(visitService.getVisitAttributeType(999));
}

/**
@@ -609,7 +620,8 @@ public void getVisitAttributeType_shouldReturnNullIfNoVisitAttributeTypeExistsWi
@Test
public void getVisitAttributeTypeByUuid_shouldReturnTheVisitAttributeTypeWithTheGivenUuid() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals("Audit Date", service.getVisitAttributeTypeByUuid("9516cc50-6f9f-11e0-8414-001e378eb67e").getName());
assertEquals("Audit Date", visitService.getVisitAttributeTypeByUuid("9516cc50-6f9f-11e0-8414-001e378eb67e")
.getName());
}

/**
@@ -619,7 +631,7 @@ public void getVisitAttributeTypeByUuid_shouldReturnTheVisitAttributeTypeWithThe
@Test
public void getVisitAttributeTypeByUuid_shouldReturnNullIfNoVisitAttributeTypeExistsWithTheGivenUuid() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Assert.assertNull(service.getVisitAttributeTypeByUuid("not-a-uuid"));
Assert.assertNull(visitService.getVisitAttributeTypeByUuid("not-a-uuid"));
}

/**
@@ -629,9 +641,9 @@ public void getVisitAttributeTypeByUuid_shouldReturnNullIfNoVisitAttributeTypeEx
@Test
public void purgeVisitAttributeType_shouldCompletelyRemoveAVisitAttributeType() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals(3, service.getAllVisitAttributeTypes().size());
service.purgeVisitAttributeType(service.getVisitAttributeType(2));
assertEquals(2, service.getAllVisitAttributeTypes().size());
assertEquals(3, visitService.getAllVisitAttributeTypes().size());
visitService.purgeVisitAttributeType(visitService.getVisitAttributeType(2));
assertEquals(2, visitService.getAllVisitAttributeTypes().size());
}

/**
@@ -641,10 +653,10 @@ public void purgeVisitAttributeType_shouldCompletelyRemoveAVisitAttributeType()
@Test
public void retireVisitAttributeType_shouldRetireAVisitAttributeType() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
VisitAttributeType vat = service.getVisitAttributeType(1);
VisitAttributeType vat = visitService.getVisitAttributeType(1);
Assert.assertFalse(vat.isRetired());
service.retireVisitAttributeType(vat, "for testing");
vat = service.getVisitAttributeType(1);
visitService.retireVisitAttributeType(vat, "for testing");
vat = visitService.getVisitAttributeType(1);
assertTrue(vat.isRetired());
assertNotNull(vat.getRetiredBy());
assertNotNull(vat.getDateRetired());
@@ -658,13 +670,13 @@ public void retireVisitAttributeType_shouldRetireAVisitAttributeType() throws Ex
@Test
public void saveVisitAttributeType_shouldCreateANewVisitAttributeType() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals(3, service.getAllVisitAttributeTypes().size());
assertEquals(3, visitService.getAllVisitAttributeTypes().size());
VisitAttributeType vat = new VisitAttributeType();
vat.setName("Another one");
vat.setDatatypeClassname(FreeTextDatatype.class.getName());
service.saveVisitAttributeType(vat);
visitService.saveVisitAttributeType(vat);
assertNotNull(vat.getId());
assertEquals(4, service.getAllVisitAttributeTypes().size());
assertEquals(4, visitService.getAllVisitAttributeTypes().size());
}

/**
@@ -674,12 +686,12 @@ public void saveVisitAttributeType_shouldCreateANewVisitAttributeType() throws E
@Test
public void saveVisitAttributeType_shouldEditAnExistingVisitAttributeType() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals(3, service.getAllVisitAttributeTypes().size());
VisitAttributeType vat = service.getVisitAttributeType(1);
assertEquals(3, visitService.getAllVisitAttributeTypes().size());
VisitAttributeType vat = visitService.getVisitAttributeType(1);
vat.setName("A new name");
service.saveVisitAttributeType(vat);
assertEquals(3, service.getAllVisitAttributeTypes().size());
assertEquals("A new name", service.getVisitAttributeType(1).getName());
visitService.saveVisitAttributeType(vat);
assertEquals(3, visitService.getAllVisitAttributeTypes().size());
assertEquals("A new name", visitService.getVisitAttributeType(1).getName());
}

/**
@@ -689,12 +701,12 @@ public void saveVisitAttributeType_shouldEditAnExistingVisitAttributeType() thro
@Test
public void unretireVisitAttributeType_shouldUnretireARetiredVisitAttributeType() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
VisitAttributeType vat = service.getVisitAttributeType(2);
VisitAttributeType vat = visitService.getVisitAttributeType(2);
assertTrue(vat.isRetired());
assertNotNull(vat.getDateRetired());
assertNotNull(vat.getRetiredBy());
assertNotNull(vat.getRetireReason());
service.unretireVisitAttributeType(vat);
visitService.unretireVisitAttributeType(vat);
Assert.assertFalse(vat.isRetired());
Assert.assertNull(vat.getDateRetired());
Assert.assertNull(vat.getRetiredBy());
@@ -708,7 +720,7 @@ public void unretireVisitAttributeType_shouldUnretireARetiredVisitAttributeType(
@Test
public void getVisitAttributeByUuid_shouldGetTheVisitAttributeWithTheGivenUuid() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
assertEquals("2011-04-25", service.getVisitAttributeByUuid("3a2bdb18-6faa-11e0-8414-001e378eb67e")
assertEquals("2011-04-25", visitService.getVisitAttributeByUuid("3a2bdb18-6faa-11e0-8414-001e378eb67e")
.getValueReference());
}

@@ -719,7 +731,7 @@ public void getVisitAttributeByUuid_shouldGetTheVisitAttributeWithTheGivenUuid()
@Test
public void getVisitAttributeByUuid_shouldReturnNullIfNoVisitAttributeHasTheGivenUuid() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Assert.assertNull(service.getVisitAttributeByUuid("not-a-uuid"));
Assert.assertNull(visitService.getVisitAttributeByUuid("not-a-uuid"));
}

/**
@@ -730,8 +742,8 @@ public void getVisitAttributeByUuid_shouldReturnNullIfNoVisitAttributeHasTheGive
public void getVisits_shouldGetAllVisitsWithGivenAttributeValues() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Map<VisitAttributeType, Object> attrs = new HashMap<VisitAttributeType, Object>();
attrs.put(service.getVisitAttributeType(1), new SimpleDateFormat("yyyy-MM-dd").parse("2011-04-25"));
List<Visit> visits = service.getVisits(null, null, null, null, null, null, null, null, attrs, true, false);
attrs.put(visitService.getVisitAttributeType(1), new SimpleDateFormat("yyyy-MM-dd").parse("2011-04-25"));
List<Visit> visits = visitService.getVisits(null, null, null, null, null, null, null, null, attrs, true, false);
assertEquals(1, visits.size());
assertEquals(Integer.valueOf(1), visits.get(0).getVisitId());
}
@@ -744,8 +756,8 @@ public void getVisits_shouldGetAllVisitsWithGivenAttributeValues() throws Except
public void getVisits_shouldNotFindAnyVisitsIfNoneHaveGivenAttributeValues() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Map<VisitAttributeType, Object> attrs = new HashMap<VisitAttributeType, Object>();
attrs.put(service.getVisitAttributeType(1), new SimpleDateFormat("yyyy-MM-dd").parse("1411-04-25"));
List<Visit> visits = service.getVisits(null, null, null, null, null, null, null, null, attrs, true, false);
attrs.put(visitService.getVisitAttributeType(1), new SimpleDateFormat("yyyy-MM-dd").parse("1411-04-25"));
List<Visit> visits = visitService.getVisits(null, null, null, null, null, null, null, null, attrs, true, false);
assertEquals(0, visits.size());
}

@@ -837,26 +849,26 @@ public void purgeVisit_shouldFailIfTheVisitHasEncountersAssociatedToIt() throws
@Test
public void saveVisit_shouldBeAbleToAddAnAttributeToAVisit() throws Exception {
Date now = new Date();
Visit visit = service.getVisit(1);
VisitAttributeType attrType = service.getVisitAttributeType(1);
Visit visit = visitService.getVisit(1);
VisitAttributeType attrType = visitService.getVisitAttributeType(1);
VisitAttribute attr = new VisitAttribute();
attr.setAttributeType(attrType);
attr.setValue(now);
visit.addAttribute(attr);
service.saveVisit(visit);
visitService.saveVisit(visit);
assertEquals(new SimpleDateFormat("yyyy-MM-dd").format(now), attr.getValueReference());
}

@Test
public void shouldVoidASimpleAttribute() throws Exception {
executeDataSet(VISITS_ATTRIBUTES_XML);
Visit visit = service.getVisit(1);
VisitAttributeType attrType = service.getVisitAttributeType(1);
Visit visit = visitService.getVisit(1);
VisitAttributeType attrType = visitService.getVisitAttributeType(1);
List<VisitAttribute> attributes = visit.getActiveAttributes(attrType);
assertTrue(attributes.size() > 0);
VisitAttribute attribute = attributes.get(0);
attribute.setVoided(true);
service.saveVisit(visit);
visitService.saveVisit(visit);
assertNotNull(attribute.getVoidedBy());
assertNotNull(attribute.getDateVoided());
}
@@ -878,7 +890,7 @@ public void stopVisits_shouldCloseAllUnvoidedActiveVisitMatchingTheSpecifiedVisi
assertTrue("There should be some active visits for this test to be valid", activeVisitCount > 0);

//close any unvoided open visits
service.stopVisits(null);
visitService.stopVisits(null);

activeVisitCount = Context.getAdministrationService().executeSQL(openVisitsQuery, true).size();

Loading