Skip to content

Commit

Permalink
Add missing CRUD methods for Order Frequency - TRUNK-4188
Browse files Browse the repository at this point in the history
  • Loading branch information
dkayiwa committed Feb 26, 2014
1 parent db6745c commit 219f817
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 1 deletion.
46 changes: 46 additions & 0 deletions api/src/main/java/org/openmrs/api/OrderService.java
Expand Up @@ -365,4 +365,50 @@ public List<OrderFrequency> getOrderFrequencies(String searchPhrase, Locale loca
* @should fail for a voided order
*/
public Order discontinueOrder(Order orderToDiscontinue, String reasonNonCoded, Date discontinueDate) throws Exception;

/**
* Creates or updates the given order frequency in the database
*
* @param orderFrequency the order frequency to save
* @return the order frequency created/saved
* @since 1.10
* @should add a new order frequency to the database
* @should edit an existing order frequency that is not in use
* @should not allow editing an existing order frequency that is in use
*/
@Authorized(PrivilegeConstants.MANAGE_ORDER_FREQUENCIES)
public OrderFrequency saveOrderFrequency(OrderFrequency orderFrequency) throws APIException;

/**
* Retires the given order frequency in the database
*
* @param orderFrequency the order frequency to retire
* @param reason the retire reason
* @return the retired order frequency
* @since 1.10
* @should retire given order frequency
*/
@Authorized(PrivilegeConstants.MANAGE_ORDER_FREQUENCIES)
public OrderFrequency retireOrderFrequency(OrderFrequency orderFrequency, String reason);

/**
* Restores an order frequency that was previous retired in the database

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

previous -> previously

*
* @param orderFrequency the order frequency to unretire
* @return the unretired order frequency
* @since 1.10
* @should unretire given order frequency
*/
@Authorized(PrivilegeConstants.MANAGE_ORDER_FREQUENCIES)
public OrderFrequency unretireOrderFrequency(OrderFrequency orderFrequency);

/**
* Completely removes an order frequency from the database
*
* @param orderFrequency the order frequency to purge
* @since 1.10
* @should delete given order frequency
*/

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

should not try to purge an order frequency in use too, i.e check before you purge and not wait for the DB to fail due to FK constraints

@Authorized(PrivilegeConstants.PURGE_ORDER_FREQUENCIES)
public void purgeOrderFrequency(OrderFrequency orderFrequency);
}
18 changes: 18 additions & 0 deletions api/src/main/java/org/openmrs/api/db/OrderDAO.java
Expand Up @@ -136,4 +136,22 @@ public <Ord extends Order> List<Ord> getActiveOrders(Patient patient, Class<Ord>
*/
public List<OrderFrequency> getOrderFrequencies(String searchPhrase, Locale locale, boolean exactLocale,
boolean includeRetired);

/**
* @see org.openmrs.api.OrderService#saveOrderFrequency(org.openmrs.OrderFrequency)
*/
public OrderFrequency saveOrderFrequency(OrderFrequency orderFrequency);

/**
* @see org.openmrs.api.OrderService#purgeOrderFrequency(org.openmrs.OrderFrequency)
*/
public void purgeOrderFrequency(OrderFrequency orderFrequency);

/**
* Checks if an order frequency is being referenced by any order
*
* @param orderFrequency the order frequency
* @return true if in use, else false
*/
public boolean isOrderFrequencyInUse(OrderFrequency orderFrequency);
}
Expand Up @@ -31,12 +31,14 @@
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.openmrs.CareSetting;
import org.openmrs.Concept;
import org.openmrs.DrugOrder;
import org.openmrs.Encounter;
import org.openmrs.GlobalProperty;
import org.openmrs.Order;
import org.openmrs.Order.Action;
import org.openmrs.OrderFrequency;
import org.openmrs.Patient;
import org.openmrs.TestOrder;
import org.openmrs.User;
import org.openmrs.api.APIException;
import org.openmrs.api.db.DAOException;
Expand Down Expand Up @@ -333,4 +335,43 @@ public List<OrderFrequency> getOrderFrequencies(String searchPhrase, Locale loca

return criteria.list();
}

/**
* @see org.openmrs.api.db.OrderDAO#saveOrderFrequency(org.openmrs.OrderFrequency)
*/
@Override
public OrderFrequency saveOrderFrequency(OrderFrequency orderFrequency) {
sessionFactory.getCurrentSession().saveOrUpdate(orderFrequency);
return orderFrequency;
}

/**
* @see org.openmrs.api.db.OrderDAO#purgeOrderFrequency(org.openmrs.OrderFrequency)
*/
@Override
public void purgeOrderFrequency(OrderFrequency orderFrequency) {
sessionFactory.getCurrentSession().delete(orderFrequency);
}

/**
* @see org.openmrs.api.db.OrderDAO#isOrderFrequencyInUse(org.openmrs.OrderFrequency)
*/
@Override
public boolean isOrderFrequencyInUse(OrderFrequency orderFrequency) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(DrugOrder.class);

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

I think modules can have their own subclasses that reference order frequency and am not sure how we can solve it, how about if we just not allow editing and purging order frequencies? Darius what do you think?

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

@djazayeri what do you think?

This comment has been minimized.

Copy link
@djazayeri

djazayeri Feb 26, 2014

Member

I agree that this will miss order frequencies referenced by module-defined order subclasses. The only way I can think of to do this is to ask Hibernate for all the subclasses of Order...

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

I had that in mind but how do you know the property name? Unless we inspect the fields on the subclass by type(OrderFrequency)

criteria.add(Restrictions.eq("frequency", orderFrequency));
criteria.setMaxResults(1);
if (criteria.list().size() > 0) {
return true;
}

criteria = sessionFactory.getCurrentSession().createCriteria(TestOrder.class);
criteria.add(Restrictions.eq("frequency", orderFrequency));
criteria.setMaxResults(1);
if (criteria.list().size() > 0) {
return true;
}

return false;
}
}
41 changes: 41 additions & 0 deletions api/src/main/java/org/openmrs/api/impl/OrderServiceImpl.java
Expand Up @@ -36,6 +36,7 @@
import org.openmrs.api.context.Context;
import org.openmrs.api.db.OrderDAO;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.validator.ValidateUtil;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -456,4 +457,44 @@ private void stopOrder(Order orderToStop, Date discontinueDate) {
orderToStop.setDateStopped(discontinueDate);
saveOrderInternal(orderToStop);
}

/**
* @see org.openmrs.api.OrderService#saveOrderFrequency(org.openmrs.OrderFrequency)
*/
@Override
public OrderFrequency saveOrderFrequency(OrderFrequency orderFrequency) throws APIException {

if (orderFrequency.getOrderFrequencyId() != null) {
if (dao.isOrderFrequencyInUse(orderFrequency)) {
throw new APIException("This order frequency cannot be edited because it is already in use");
}
}

//ValidateUtil.validate(orderFrequency);

This comment has been minimized.

Copy link
@dkayiwa

dkayiwa Feb 26, 2014

Author Member

Un commented the above at: 04791e4

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

You don't have to do this, this is called by default by AOP logic around save methods

return dao.saveOrderFrequency(orderFrequency);
}

/**
* @see org.openmrs.api.OrderService#retireOrderFrequency(org.openmrs.OrderFrequency, java.lang.String)
*/
@Override
public OrderFrequency retireOrderFrequency(OrderFrequency orderFrequency, String reason) {
return dao.saveOrderFrequency(orderFrequency);
}

/**
* @see org.openmrs.api.OrderService#unretireOrderFrequency(org.openmrs.OrderFrequency)
*/
@Override
public OrderFrequency unretireOrderFrequency(OrderFrequency orderFrequency) {
return dao.saveOrderFrequency(orderFrequency);
}

/**
* @see org.openmrs.api.OrderService#purgeOrderFrequency(org.openmrs.OrderFrequency)
*/
@Override
public void purgeOrderFrequency(OrderFrequency orderFrequency) {
dao.purgeOrderFrequency(orderFrequency);
}
}
8 changes: 8 additions & 0 deletions api/src/main/java/org/openmrs/util/PrivilegeConstants.java
Expand Up @@ -533,4 +533,12 @@ public class PrivilegeConstants {

@AddOnStartup(description = "Able to assign System Developer role")
public static final String ASSIGN_SYSTEM_DEVELOPER_ROLE = "Assign System Developer Role";

@AddOnStartup(description = "Able to view Order Frequencies")
public static final String VIEW_ORDER_FREQUENCIES = "View Order Frequencies";

@AddOnStartup(description = "Able to add/edit/retire Order Frequencies")
public static final String MANAGE_ORDER_FREQUENCIES = "Manage Order Frequencies";

public static final String PURGE_ORDER_FREQUENCIES = "Purge Order Frequencies";
}
101 changes: 101 additions & 0 deletions api/src/test/java/org/openmrs/api/OrderServiceTest.java
Expand Up @@ -18,6 +18,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
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.test.TestUtil.containsId;
Expand Down Expand Up @@ -978,4 +979,104 @@ public void getOrderFrequencies_shouldRejectANullSearchPhrase() throws Exception
expectedException.expectMessage("searchPhrase is required");
orderService.getOrderFrequencies(null, Locale.ENGLISH, false, false);
}

@Test
@Verifies(value = "should retire given order frequency", method = "retireOrderFrequency(orderFrequency, String)")
public void retireOrderFrequency_shouldRetireGivenOrderFrequency() throws Exception {
OrderFrequency orderFrequency = Context.getOrderService().getOrderFrequency(1);
assertNotNull(orderFrequency);
Assert.assertFalse(orderFrequency.isRetired());
Assert.assertNull(orderFrequency.getRetireReason());

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

date retired should also be null


Context.getOrderService().retireOrderFrequency(orderFrequency, "retire reason");

orderFrequency = Context.getOrderService().getOrderFrequency(1);
assertNotNull(orderFrequency);
assertTrue(orderFrequency.isRetired());
assertEquals("retire reason", orderFrequency.getRetireReason());

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

check dateRetired too


//Should not change the number of order frequencies.
assertEquals(3, Context.getOrderService().getOrderFrequencies(true).size());
}

@Test
@Verifies(value = "should unretire given order frequency", method = "unretireOrderFrequency(OrderFrequency)")
public void unretireOrderFrequency_shouldUnretireGivenOrderFrequency() throws Exception {
OrderFrequency orderFrequency = Context.getOrderService().getOrderFrequency(3);
assertNotNull(orderFrequency);
assertTrue(orderFrequency.isRetired());
assertEquals("Some Retire Reason", orderFrequency.getRetireReason());

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

You also need to check dateRetired


Context.getOrderService().unretireOrderFrequency(orderFrequency);

orderFrequency = Context.getOrderService().getOrderFrequency(3);
assertNotNull(orderFrequency);
assertFalse(orderFrequency.isRetired());
assertNull(orderFrequency.getRetireReason());

//Should not change the number of order frequencies.
assertEquals(3, Context.getOrderService().getOrderFrequencies(true).size());
}

@Test
@Verifies(value = "should delete given order frequency", method = "purgeOrderFrequency(OrderFrequency)")
public void purgeOrderFrequency_shouldDeleteGivenOrderFrequency() throws Exception {
OrderFrequency orderFrequency = Context.getOrderService().getOrderFrequency(3);
assertNotNull(orderFrequency);

Context.getOrderService().purgeOrderFrequency(orderFrequency);

orderFrequency = Context.getOrderService().getOrderFrequency(3);
Assert.assertNull(orderFrequency);

//Should reduce the existing number of order frequencies.
assertEquals(2, Context.getOrderService().getOrderFrequencies(true).size());
}

/**
* @see {@link OrderService#saveOrderFrequency(OrderFrequency)}
*/
@Test
@Verifies(value = "should add a new order frequency to the database", method = "saveOrderFrequency(OrderFrequency)")
public void saveOrderFrequency_shouldAddANewOrderFrequencyToTheDatabase() throws Exception {
OrderService os = Context.getOrderService();
Integer originalSize = os.getOrderFrequencies(true).size();
OrderFrequency orderFrequency = new OrderFrequency();
orderFrequency.setConcept(new Concept(3));
orderFrequency.setFrequencyPerDay(2d);

orderFrequency = os.saveOrderFrequency(orderFrequency);

assertNotNull(orderFrequency.getId());
assertNotNull(orderFrequency.getUuid());
assertNotNull(orderFrequency.getCreator());
assertNotNull(orderFrequency.getDateCreated());
assertEquals(originalSize + 1, os.getOrderFrequencies(true).size());
}

/**
* @see {@link OrderService#saveOrderFrequency(OrderFrequency)}
*/
@Test
@Verifies(value = "should edit an existing order frequency that is not in use", method = "saveOrderFrequency(OrderFrequency)")
public void saveOrderFrequency_shouldEditAnExistingOrderFrequencyThatIsNotInUse() throws Exception {
OrderFrequency orderFrequency = Context.getOrderService().getOrderFrequency(2);
assertNotNull(orderFrequency);

orderFrequency.setFrequencyPerDay(4d);
Context.getOrderService().saveOrderFrequency(orderFrequency);
}

/**
* @see {@link OrderService#saveOrderFrequency(OrderFrequency)}
*/
@Test(expected = APIException.class)
@Verifies(value = "should not allow editing an existing order frequency that is in use", method = "saveOrderFrequency(OrderFrequency)")
public void saveOrderFrequency_shouldNotAllowEditingAnExistingOrderFrequencyThatIsInUse() throws Exception {
OrderFrequency orderFrequency = Context.getOrderService().getOrderFrequency(1);
assertNotNull(orderFrequency);

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

I figured that there is a better way to check exceptions more precisely, use a junit @rule and ExpectedException so that you can check the exact error message because this error could be something else

This comment has been minimized.

Copy link
@dkayiwa

dkayiwa Feb 26, 2014

Author Member

Oh yes i noticed that when reviewing your other commits. Will use it. :)

orderFrequency.setFrequencyPerDay(4d);
Context.getOrderService().saveOrderFrequency(orderFrequency);
}
}
Expand Up @@ -179,7 +179,7 @@
<concept_name concept_id="113" name="1/day x 7 days/week" concept_name_id="1131" locale="en" creator="1" date_created="2008-08-15 13:52:53.0" concept_name_type="FULLY_SPECIFIED" locale_preferred="1" voided="false" uuid="83f24a00-7869-11e3-981f-0800200c9a66"/>
<order_frequency order_frequency_id="1" concept_id="113" creator="1" date_created="2008-08-15 13:52:53.0" retired="false" uuid="28090760-7c38-11e3-baa7-0800200c9a66" />
<order_frequency order_frequency_id="2" concept_id="113" creator="1" date_created="2008-08-15 13:52:53.0" retired="false" uuid="38090760-7c38-11e3-baa7-0800200c9a66" />
<order_frequency order_frequency_id="3" concept_id="113" creator="1" date_created="2008-08-15 13:52:53.0" retired="true" uuid="48090760-7c38-11e3-baa7-0800200c9a66" />
<order_frequency order_frequency_id="3" concept_id="113" creator="1" date_created="2008-08-15 13:52:53.0" retired="true" retire_reason="Some Retire Reason" retired_by="1" date_retired="2009-08-15 13:52:53.0" uuid="48090760-7c38-11e3-baa7-0800200c9a66" />

This comment has been minimized.

Copy link
@wluyima

wluyima Feb 26, 2014

Member

good catch!

<drug_order order_id="1" drug_inventory_id="3" dose="325.0" dose_units="50" as_needed="false" frequency="1" dosing_type="SIMPLE"/>
<drug_order order_id="2" drug_inventory_id="2" dose="1.0" dose_units="51" as_needed="false" frequency="1" dosing_type="SIMPLE"/>
<drug_order order_id="3" drug_inventory_id="2" dose="2.0" dose_units="51" as_needed="false" frequency="1" dosing_type="SIMPLE"/>
Expand Down

0 comments on commit 219f817

Please sign in to comment.