/**
* 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.order;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Concept;
import org.openmrs.ConceptSet;
import org.openmrs.Drug;
import org.openmrs.DrugOrder;
import org.openmrs.Patient;
import org.openmrs.api.APIException;
import org.openmrs.api.OrderService;
import org.openmrs.api.OrderService.ORDER_STATUS;
import org.openmrs.api.context.Context;
import org.openmrs.api.context.ContextAuthenticationException;
import org.openmrs.util.OpenmrsUtil;
/**
* Contains convenience methods for working with Orders.
*/
public class OrderUtil {
private static final Log log = LogFactory.getLog(OrderUtil.class);
/**
* Discontinues all current orders for the given <code>patient</code>
*
* @param patient
* @param discontinueReason
* @param discontinueDate
* @see OrderService#discontinueOrder(org.openmrs.Order, Concept, Date)
* @should discontinue all orders for the given patient if none are yet discontinued
* @should not affect orders that were already discontinued on the specified date
* @should not affect orders that end before the specified date
* @should not affect orders that start after the specified date
*/
public static void discontinueAllOrders(Patient patient, Concept discontinueReason, Date discontinueDate) {
if (log.isDebugEnabled())
log.debug("In discontinueAll with patient " + patient + " and concept " + discontinueReason + " and date "
+ discontinueDate);
OrderService orderService = Context.getOrderService();
List<DrugOrder> drugOrders = orderService.getDrugOrdersByPatient(patient, ORDER_STATUS.CURRENT);
// loop over all of this patient's drug orders to discontinue each
if (drugOrders != null) {
for (DrugOrder drugOrder : drugOrders) {
if (log.isDebugEnabled())
log.debug("discontinuing order: " + drugOrder);
// do the stuff to the database
orderService.discontinueOrder(drugOrder, discontinueReason, discontinueDate);
}
}
}
/**
* Void all DrugOrders for drugs whose concepts are in the given set, and that have the given
* status. An end-user would think of this method as "delete all drug orders of the given type".
*
* @param patient
* @param drugSetId
* @param voidReason
* @param status
* @should void all drug orders of the given type when status is null
* @should void drug orders of the given type for status of CURRENT
* @should void drug orders of the given type for status of COMPLETE
* @should not affect drug orders that are already voided
*/
public static void voidDrugSet(Patient patient, String drugSetId, String voidReason, ORDER_STATUS status) {
if (log.isDebugEnabled())
log.debug("Voiding drug sets for patient: " + patient + " drugSetId: " + drugSetId + " reason: " + voidReason
+ " status: " + status);
// do some null pointer checks
if (Context.isAuthenticated() == false)
throw new ContextAuthenticationException("Unable to void drugs when no one is logged in");
if (patient == null)
throw new APIException("Unable to void drugs without a patient being given");
if (drugSetId == null)
throw new APIException("Unable to void drugs without a drugSetId being given");
OrderService orderService = Context.getOrderService();
List<DrugOrder> currentOrders = orderService.getDrugOrdersByPatient(patient, status);
Map<String, List<DrugOrder>> ordersBySetId = getDrugSetsByDrugSetIdList(currentOrders, drugSetId, ",");
// loop over the orders and mark each as void in the database
if (ordersBySetId != null) {
List<DrugOrder> ordersToVoid = ordersBySetId.get(drugSetId);
if (ordersToVoid != null) {
for (DrugOrder order : ordersToVoid) {
orderService.voidOrder(order, voidReason);
}
}
}
}
/**
* Discontinue orders for the given patient with the given drug sets ...
*
* @param patient
* @param drugSetId
* @param discontinueReason
* @param discontinueDate
* @should discontinue all orders of the given type for the given patient if none are yet
* discontinued
* @should not affect orders that were already discontinued on the specified date
* @should not affect orders that end before the specified date
* @should not affect orders that start after the specified date
*/
public static void discontinueDrugSet(Patient patient, String drugSetId, Concept discontinueReason, Date discontinueDate) {
if (log.isDebugEnabled()) {
log.debug("Discontinuing drug sets. patient: " + patient + " drugSetId: " + drugSetId + " reason: "
+ discontinueReason + " date: " + discontinueDate);
}
// do some null pointer checks
if (Context.isAuthenticated() == false)
throw new ContextAuthenticationException("Unable to discontinue drugs when no one is logged in");
if (patient == null)
throw new APIException("Unable to discontinue drugs without a patient being given");
if (drugSetId == null)
throw new APIException("Unable to discontinue drugs without a drugSetId being given");
OrderService orderService = Context.getOrderService();
List<DrugOrder> currentOrders = orderService.getDrugOrdersByPatient(patient, ORDER_STATUS.CURRENT);
Map<String, List<DrugOrder>> ordersBySetId = getDrugSetsByDrugSetIdList(currentOrders, drugSetId, ",");
// loop over all of the orders and discontinue each of them
if (ordersBySetId != null) {
List<DrugOrder> ordersToDiscontinue = ordersBySetId.get(drugSetId);
if (ordersToDiscontinue != null) {
for (DrugOrder order : ordersToDiscontinue) {
orderService.discontinueOrder(order, discontinueReason, discontinueDate);
}
} else {
log.debug("no orders to discontinue");
}
} else {
log.debug("no ordersBySetId returned for " + drugSetId);
}
}
/**
* Associates the concept id of a drug set to a name of the drug set in the current locale
*
* @param drugSetIds a comma separated list with the concept id of the drug sets
* @return <code>Map<String, String></code> of the drug headers for the given drugSetIds
* @should get map from concept id as string to concept name
*/
public static Map<String, String> getDrugSetHeadersByDrugSetIdList(String drugSetIds) {
Map<String, String> ret = null;
if (drugSetIds == null)
throw new APIException("Unable to get drug headers without drugSetIds being given");
Map<String, Concept> concepts = OpenmrsUtil.delimitedStringToConceptMap(drugSetIds, ",");
if (concepts != null) {
for (Map.Entry<String, Concept> e : concepts.entrySet()) {
String id = e.getKey();
Concept concept = e.getValue();
if (ret == null)
ret = new HashMap<String, String>();
ret.put(id, concept.getName(Context.getLocale()).getName());
}
}
return ret;
}
/**
* Gets a map of DrugOrders that belong to a DrugSet concept ID
*
* @param orderList the Drug Order list
* @param drugSetIdList a 'delimiter' separated list of drug sets
* @param delimiter the delimiter of drug sets (defaults to a comma if set to null)
* @return Map<String, List<DrugOrder>> of DrugOrders that belong to a DrugSet concept_id
* @should get a map from concept id as string to drug orders that belong to that drug set
* @should treat an asterisk as all other drugs
*/
public static Map<String, List<DrugOrder>> getDrugSetsByDrugSetIdList(List<DrugOrder> orderList, String drugSetIdList,
String delimiter) {
if (log.isDebugEnabled()) {
log.debug("in getdrugsetsbydrugsetidlist. orderlist: " + orderList + " drugsetidlist: " + drugSetIdList
+ " delimiter: " + delimiter);
}
if (delimiter == null)
delimiter = ",";
Map<String, List<DrugOrder>> ret = null;
if (drugSetIdList != null && orderList != null) {
List<Concept> drugSetConcepts = new ArrayList<Concept>();
boolean addOthers = false;
Map<Concept, String> idToConceptMappings = new HashMap<Concept, String>();
String[] drugSetIds = drugSetIdList.split(delimiter);
log.debug("starting with " + drugSetIds.length + " items in comma-delimited list, and " + orderList.size()
+ " orders that are " + orderList);
for (String drugSetId : drugSetIds) {
// go through and get all concepts for these drugSetIds - then we can call another method to get Map
if ("*".equals(drugSetId)) {
// add "other"
addOthers = true;
} else {
Concept drugSetConcept = OpenmrsUtil.getConceptByIdOrName(drugSetId);
if (drugSetConcept != null) {
drugSetConcepts.add(drugSetConcept);
idToConceptMappings.put(drugSetConcept, drugSetId);
log.debug("added concept " + drugSetConcept.getName(Context.getLocale()) + ", and mapping to id "
+ drugSetId);
}
}
}
// now we know what drugSet concepts to separate the orderList into
// first, let's create a list of "others", starting with a full list that we remove from
List<DrugOrder> otherOrders = null;
if (addOthers)
otherOrders = orderList;
Map<Concept, List<DrugOrder>> ordersByConcepts = getDrugSetsByConcepts(orderList, drugSetConcepts);
if (ordersByConcepts != null) {
log.debug("obc is size " + ordersByConcepts.size());
for (Map.Entry<Concept, List<DrugOrder>> e : ordersByConcepts.entrySet()) {
Concept c = e.getKey();
List<DrugOrder> orders = e.getValue();
log.debug("found concept " + c.getName(Context.getLocale()) + ", and list is size " + orders.size()
+ " and list is " + orders);
if (addOthers && otherOrders != null) {
otherOrders.removeAll(orders);
}
if (ret == null)
ret = new HashMap<String, List<DrugOrder>>();
log.debug("putting list of size " + orders.size() + " in string " + idToConceptMappings.get(c));
ret.put(idToConceptMappings.get(c), orders);
}
}
// add the "others" list to the Map
if (addOthers && otherOrders != null) {
if (ret == null)
ret = new HashMap<String, List<DrugOrder>>();
ret.put("*", otherOrders);
}
}
return ret;
}
/**
* Splits the drug orders into sublists based on which drug set the order's drug belongs to
*
* @param drugOrders List of drugOrders
* @param drugSets List of drugSets concept
* @return Map<Concept, List<DrugOrder>> of a sublist of drug orders mapped by the drug set
* concept that they belong
* @throws APIException
* @should get a map from concept to drugs orders in that drug set
*/
public static Map<Concept, List<DrugOrder>> getDrugSetsByConcepts(List<DrugOrder> drugOrders, List<Concept> drugSets)
throws APIException {
if (log.isDebugEnabled()) {
log.debug("in getdrugsetsbyconcepts. drugOrders: " + drugOrders + " drugSets: " + drugSets);
}
Map<Concept, List<DrugOrder>> hmRet = null;
if (drugSets != null && drugOrders != null) {
log.debug("drugSets is size " + drugSets.size());
for (Concept c : drugSets) {
List<DrugOrder> ordersForConcept = new ArrayList<DrugOrder>();
Collection<ConceptSet> relatedConcepts = c.getConceptSets();
log.debug("Concept is " + c.getName(Context.getLocale()) + " and has " + relatedConcepts.size()
+ " related concepts");
// now we have as a list, let's iterate
if (relatedConcepts != null) {
for (ConceptSet cs : relatedConcepts) {
Concept csConcept = cs.getConcept();
for (DrugOrder currOrder : drugOrders) {
Drug currDrug = currOrder.getDrug();
if (currDrug != null) {
Concept currConcept = currDrug.getConcept(); // must not be null - ordained by data model
if (currConcept.equals(csConcept)) {
ordersForConcept.add(currOrder);
log.debug("just added an order for " + currDrug.getName() + " to list of "
+ c.getName(Context.getLocale()));
}
}
}
}
}
if (ordersForConcept.size() > 0) {
if (hmRet == null)
hmRet = new HashMap<Concept, List<DrugOrder>>();
hmRet.put(c, ordersForConcept);
log.debug("Concept " + c.getName(Context.getLocale()) + " was put to the map with a list of size "
+ ordersForConcept.size());
}
}
} else
log.debug("drugSets is null");
return hmRet;
}
}