Skip to content

Commit

Permalink
locking mechanism for encounter_type - TRUNK-4033
Browse files Browse the repository at this point in the history
[TRUNK-4033] made some changes

added a testcase, and made some other changes

[TRUNK-4033] added a disabled attribute if encounterTypesLocked == 'true'

[TRUNK-4033] added a testcase i.e. EncounterService.saveEncounterType_shouldNotSaveEncounterTypeIfEncounterTypesAreLocked()

[TRUNK-4033] added some other testcases and made some changes

Removed or converted throws clauses for EncounterTypeLockedException to APIException - TRUNK-4033

Removed unused import in HibernateEncounterDAO
  • Loading branch information
k-joseph authored and wluyima committed Aug 29, 2013
1 parent 9037467 commit 07e19c3
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 40 deletions.
13 changes: 12 additions & 1 deletion api/src/main/java/org/openmrs/api/EncounterService.java
Expand Up @@ -270,9 +270,10 @@ public List<Encounter> getEncounters(Patient who, Location loc, Date fromDate, D
* @should not overwrite creator or date created
* @should not overwrite date created
* @should update an existing encounter type name
* @should throw error when trying to save encounter type when encounter types are locked
*/
@Authorized( { PrivilegeConstants.MANAGE_ENCOUNTER_TYPES })
public EncounterType saveEncounterType(EncounterType encounterType);
public EncounterType saveEncounterType(EncounterType encounterType) throws APIException;

/**
* Get encounterType by internal identifier
Expand Down Expand Up @@ -363,6 +364,7 @@ public List<Encounter> getEncounters(Patient who, Location loc, Date fromDate, D
* @throws APIException
* @should retire type and set attributes
* @should throw error if given null reason parameter
* @should should throw error when trying to retire encounter type when encounter types are locked
*/
@Authorized( { PrivilegeConstants.MANAGE_ENCOUNTER_TYPES })
public EncounterType retireEncounterType(EncounterType encounterType, String reason) throws APIException;
Expand All @@ -374,6 +376,7 @@ public List<Encounter> getEncounters(Patient who, Location loc, Date fromDate, D
* @param encounterType the encounter type to unretire
* @throws APIException
* @should unretire type and unmark attributes
* @should should throw error when trying to unretire encounter type when encounter types are locked
*/
@Authorized( { PrivilegeConstants.MANAGE_ENCOUNTER_TYPES })
public EncounterType unretireEncounterType(EncounterType encounterType) throws APIException;
Expand All @@ -384,6 +387,7 @@ public List<Encounter> getEncounters(Patient who, Location loc, Date fromDate, D
* @param encounterType
* @throws APIException
* @should purge type
* @should should throw error when trying to delete encounter type when encounter types are locked
*/
@Authorized( { PrivilegeConstants.PURGE_ENCOUNTER_TYPES })
public void purgeEncounterType(EncounterType encounterType) throws APIException;
Expand Down Expand Up @@ -874,4 +878,11 @@ public List<Encounter> getEncountersByVisitsAndPatient(Patient patient, boolean
@Authorized( { PrivilegeConstants.VIEW_VISITS })
public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean includeVoided, String query)
throws APIException;

/**
* Check if the encounter types are locked, and if so, throw exception during manipulation of encounter type
*
* @throws EncounterTypeLockedException
*/
public void checkIfEncounterTypesAreLocked() throws EncounterTypeLockedException;
}
@@ -0,0 +1,69 @@
/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.api;

import org.openmrs.util.OpenmrsConstants;

/**
* This exception is thrown when a encounter types are locked and the user tries to edit an encounter type
* type, this is done by a global property being true/false.
*
* @since 1.10 added to 1.8.5 and 1.9.4
*
* @see OpenmrsConstants#GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED
* @see EncounterService#checkIfLocked()
*/
public class EncounterTypeLockedException extends APIException {

private static final long serialVersionUID = 1223334444L;

/**
* Generic constructor that gives a normal message about editing not being allowed to the user.
*/
public EncounterTypeLockedException() {
this("Editing of encounter types is not allowed at this time since they are currently locked. ");
}

/**
* Convenience constructor to give the user a message other than normal default one
*
* @param message the String to show to the user as to why the encounter types are locked
*/
public EncounterTypeLockedException(String message) {
super(message);
}

/**
* Convenience constructor to give the user a message other than the normal one and to chain
* this exception with a parent exception.
*
* @param message the String to show to the user as to why the encounter types are locked
* @param cause the parent exception
*/
public EncounterTypeLockedException(String message, Throwable cause) {
super(message, cause);
}

/**
* Convenience constructor used to only set the parent exception to chain with. This does not
* set the error message for the user as to why an exception is being thrown. The
* {@link #EncounterTypeLockedException(String, Throwable)} constructor is preferred over this
* one.
*
* @param cause the parent exception
*/
public EncounterTypeLockedException(Throwable cause) {
super(cause);
}
}
1 change: 0 additions & 1 deletion api/src/main/java/org/openmrs/api/PersonService.java
Expand Up @@ -1114,5 +1114,4 @@ public PersonMergeLog getPersonMergeLogByUuid(String uuid, boolean deserialize)
*/
@Authorized( { PrivilegeConstants.EDIT_PERSONS })
public PersonAddress savePersonAddress(PersonAddress personAddress);

}
24 changes: 24 additions & 0 deletions api/src/main/java/org/openmrs/api/impl/EncounterServiceImpl.java
Expand Up @@ -37,6 +37,7 @@
import org.openmrs.VisitType;
import org.openmrs.api.APIException;
import org.openmrs.api.EncounterService;
import org.openmrs.api.EncounterTypeLockedException;
import org.openmrs.api.ObsService;
import org.openmrs.api.OrderService;
import org.openmrs.api.ProviderService;
Expand Down Expand Up @@ -379,6 +380,9 @@ public void purgeEncounter(Encounter encounter, boolean cascade) throws APIExcep
* @see org.openmrs.api.EncounterService#saveEncounterType(org.openmrs.EncounterType)
*/
public EncounterType saveEncounterType(EncounterType encounterType) {
//make sure the user has not turned off encounter types editing
checkIfEncounterTypesAreLocked();

dao.saveEncounterType(encounterType);
return encounterType;
}
Expand Down Expand Up @@ -425,6 +429,9 @@ public EncounterType retireEncounterType(EncounterType encounterType, String rea
if (reason == null)
throw new IllegalArgumentException("The 'reason' for retiring is required");

//make sure the user has not turned off encounter types editing
checkIfEncounterTypesAreLocked();

encounterType.setRetired(true);
encounterType.setRetireReason(reason);
return saveEncounterType(encounterType);
Expand All @@ -434,6 +441,8 @@ public EncounterType retireEncounterType(EncounterType encounterType, String rea
* @see org.openmrs.api.EncounterService#unretireEncounterType(org.openmrs.EncounterType)
*/
public EncounterType unretireEncounterType(EncounterType encounterType) throws APIException {
checkIfEncounterTypesAreLocked();

encounterType.setRetired(false);
return saveEncounterType(encounterType);
}
Expand All @@ -442,6 +451,9 @@ public EncounterType unretireEncounterType(EncounterType encounterType) throws A
* @see org.openmrs.api.EncounterService#purgeEncounterType(org.openmrs.EncounterType)
*/
public void purgeEncounterType(EncounterType encounterType) throws APIException {
//make sure the user has not turned off encounter types editing
checkIfEncounterTypesAreLocked();

dao.deleteEncounterType(encounterType);
}

Expand Down Expand Up @@ -791,4 +803,16 @@ public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean inc
throws APIException {
return dao.getEncountersByVisitsAndPatientCount(patient, includeVoided, query);
}

/**
* @see org.openmrs.api.EncounterService#checkIfEncounterTypesAreLocked()
*/
@Transactional(readOnly = true)
public void checkIfEncounterTypesAreLocked() {
String locked = Context.getAdministrationService().getGlobalProperty(
OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED, "false");
if (locked.toLowerCase().equals("true")) {
throw new EncounterTypeLockedException();
}
}
}
5 changes: 5 additions & 0 deletions api/src/main/java/org/openmrs/util/OpenmrsConstants.java
Expand Up @@ -879,6 +879,8 @@ public static final Collection<String> AUTO_ROLES() {

public static final String GLOBAL_PROPERTY_ADDRESS_TEMPLATE = "layout.address.format";

public static final String GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED = "EncounterType.encounterTypes.locked";

public static final String DEFAULT_ADDRESS_TEMPLATE = "<org.openmrs.layout.web.address.AddressTemplate>\n"
+ " <nameMappings class=\"properties\">\n"
+ " <property name=\"postalCode\" value=\"Location.postalCode\"/>\n"
Expand Down Expand Up @@ -1432,6 +1434,9 @@ public static final List<GlobalProperty> CORE_GLOBAL_PROPERTIES() {
"",
"Specifies how encounter types are mapped to visit types when automatically assigning encounters to visits. e.g 1:1, 2:1, 3:2 in the format encounterTypeId:visitTypeId"));

props.add(new GlobalProperty(GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED, "false",
"saving, retiring or deleting an Encounter Type is not permitted, if true", BooleanDatatype.class, null));

props
.add(new GlobalProperty(
GP_DASHBOARD_PROVIDER_DISPLAY_ENCOUNTER_ROLES,
Expand Down
74 changes: 74 additions & 0 deletions api/src/test/java/org/openmrs/api/EncounterServiceTest.java
Expand Up @@ -1972,4 +1972,78 @@ public void getActiveEncounterVisitHandler_shouldReturnBeanHaveBeenRegisteredWit

Assert.assertNotNull(activeEncounterVisitHandler);
}

/**
* @see {@link EncounterService#saveEncounterType(EncounterType)}}
* @see {@link EncounterService#checkIfEncounterTypesAreLocked()}}
*/
@Test(expected = EncounterTypeLockedException.class)
@Verifies(value = "should throw error when trying to save encounter type when encounter types are locked", method = "saveEncounterType(EncounterType)")
public void saveEncounterType_shouldThrowErrorWhenTryingToSaveEncounterTypeWhenEncounterTypesAreLocked()
throws Exception {
GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED);
gp.setPropertyValue("true");
Context.getAdministrationService().saveGlobalProperty(gp);

EncounterService encounterService = Context.getEncounterService();
EncounterType encounterType = Context.getEncounterService().getEncounterType(1);

Assert.assertNotNull(encounterType);

encounterService.saveEncounterType(encounterType);
}

/**
* @see {@link EncounterService#retireEncounterType(EncounterType, String)}}
*/
@Test(expected = EncounterTypeLockedException.class)
@Verifies(value = "should throw error when trying to retire encounter type when encounter types are locked", method = "retireEncounterType(EncounterType, String)")
public void retireEncounterType_shouldThrowErrorWhenTryingToRetireEncounterTypeWhenEncounterTypesAreLocked()
throws Exception {
GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED);
gp.setPropertyValue("true");
Context.getAdministrationService().saveGlobalProperty(gp);

EncounterService encounterService = Context.getEncounterService();
EncounterType encounterType = Context.getEncounterService().getEncounterType(1);
Assert.assertNotNull(encounterType);

encounterService.retireEncounterType(encounterType, "reason");
}

/**
* @see {@link EncounterService#unretireEncounterType(EncounterType)}}
*/
@Test(expected = EncounterTypeLockedException.class)
@Verifies(value = "should throw error when trying to unretire encounter type when encounter types are locked", method = "unretireEncounterType(EncounterType)")
public void unretireEncounterType_shouldThrowErrorWhenTryingToUnretireEncounterTypeWhenEncounterTypesAreLocked()
throws Exception {
EncounterService encounterService = Context.getEncounterService();
EncounterType encounterType = Context.getEncounterService().getEncounterType(2);

GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED);
gp.setPropertyValue("true");
Context.getAdministrationService().saveGlobalProperty(gp);

encounterService.unretireEncounterType(encounterType);
}

/**
* @see {@link EncounterService#purgeEncounterType(EncounterType)}}
*/
@Test(expected = EncounterTypeLockedException.class)
@Verifies(value = "should throw error when trying to delete encounter type when encounter types are locked", method = "purgeEncounterType(EncounterType)")
public void purgeEncounterType_shouldThrowErrorWhenTryingToDeleteEncounterTypeWhenEncounterTypesAreLocked()
throws Exception {
EncounterService encounterService = Context.getEncounterService();
EncounterType encounterType = Context.getEncounterService().getEncounterType(1);

Assert.assertNotNull(encounterType);

GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_TYPES_LOCKED);
gp.setPropertyValue("true");
Context.getAdministrationService().saveGlobalProperty(gp);

encounterService.purgeEncounterType(encounterType);
}
}
Expand Up @@ -23,6 +23,7 @@
import org.openmrs.EncounterType;
import org.openmrs.api.APIException;
import org.openmrs.api.EncounterService;
import org.openmrs.api.EncounterTypeLockedException;
import org.openmrs.api.context.Context;
import org.openmrs.web.WebConstants;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
Expand Down Expand Up @@ -71,52 +72,60 @@ protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse
EncounterType encounterType = (EncounterType) obj;
EncounterService es = Context.getEncounterService();

if (request.getParameter("save") != null) {
es.saveEncounterType(encounterType);
view = getSuccessView();
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.saved");
}

// if the user is retiring out the EncounterType
else if (request.getParameter("retire") != null) {
String retireReason = request.getParameter("retireReason");
if (encounterType.getEncounterTypeId() != null && !(StringUtils.hasText(retireReason))) {
errors.reject("retireReason", "general.retiredReason.empty");
return showForm(request, response, errors);
try {
if (request.getParameter("save") != null) {
es.saveEncounterType(encounterType);
view = getSuccessView();
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.saved");
}

es.retireEncounterType(encounterType, retireReason);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.retiredSuccessfully");

view = getSuccessView();
}

// if the user is unretiring the EncounterType
else if (request.getParameter("unretire") != null) {
es.unretireEncounterType(encounterType);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.unretiredSuccessfully");

view = getSuccessView();
}
// if the user is retiring out the EncounterType
else if (request.getParameter("retire") != null) {
String retireReason = request.getParameter("retireReason");
if (encounterType.getEncounterTypeId() != null && !(StringUtils.hasText(retireReason))) {
errors.reject("retireReason", "general.retiredReason.empty");
return showForm(request, response, errors);
}
es.retireEncounterType(encounterType, retireReason);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.retiredSuccessfully");

view = getSuccessView();
}

// if the user is purging the encounterType
else if (request.getParameter("purge") != null) {

try {
es.purgeEncounterType(encounterType);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.purgedSuccessfully");
// if the user is unretiring the EncounterType
else if (request.getParameter("unretire") != null) {
es.unretireEncounterType(encounterType);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.unretiredSuccessfully");

view = getSuccessView();
}
catch (DataIntegrityViolationException e) {
httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "error.object.inuse.cannot.purge");
view = "encounterType.form?encounterTypeId=" + encounterType.getEncounterTypeId();

// if the user is purging the encounterType
else if (request.getParameter("purge") != null) {

try {
es.purgeEncounterType(encounterType);
httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "EncounterType.purgedSuccessfully");
view = getSuccessView();
}
catch (DataIntegrityViolationException e) {
httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "error.object.inuse.cannot.purge");
view = "encounterType.form?encounterTypeId=" + encounterType.getEncounterTypeId();
}
catch (APIException e) {
httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "error.general: "
+ e.getLocalizedMessage());
view = "encounterType.form?encounterTypeId=" + encounterType.getEncounterTypeId();
}
}
catch (APIException e) {
httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "error.general: " + e.getLocalizedMessage());
}
catch (EncounterTypeLockedException e) {
log.error("tried to save, retire, unretire or delete encounter type while encounter types were locked", e);
httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "EncounterType.encounterTypes.locked");
if (encounterType.getEncounterTypeId() != null) {
view = "encounterType.form?encounterTypeId=" + encounterType.getEncounterTypeId();
}
}

}

return new ModelAndView(new RedirectView(view));
Expand Down

0 comments on commit 07e19c3

Please sign in to comment.