Order Entry Module Design

We did not release this module. Ultimately, we introduced a new Order Entry API in OpenMRS Platform 1.10.0, and there is no module to add this support in earlier OpenMRS platform versions.

Background

A new 'Order Entry' module will be authored to provide a new API and features necessary to manage patient specific orders, the module is intended to be a cleaner version of the existing order entry API with several additions and subtractions. For more background information, please visit api support for order entry page. This module will use the "org.openmrs" namespace, rather than the conventional "org.openmrs.module" namespace in order to more easily support the goal of eventually incorporating this module into core. By keeping it as a module initially, this allows implementations running older versions of OpenMRS (1.7, 1.8, 1.9, etc) to take advantage of, and test out, this work, without requiring them to upgrade. It also will allow the module to evolve at a different pace than the core code.

The module will use existing orders tables, installing the module will essentially lead to modification of the related tables, 

Can we have the OrderService in core marked as deprecated prior  to releasing 1.9?

Module id: orderentry

Module name: Order Entry

Package namespace: org.openmrs.orderentry

Module design

We are getting rid of the OrderType class including the associated database table, the broader categorization of  will by the concept class of each order's backing concept. A more granular break down of these can be done through attribute types. (Though this is not supported in older versions)

Order

( * = required)

class Order extends BaseOpenmrsData{

  public enum OrderAction {
     DISCONTINUE, ORDER
  }

  *Integer orderId
  *Patient patient
  *Concept concept
  *String orderNumber
  String previousOrderNumber
  *OrderAction orderAction
  *Date startDate
  Date autoExpireDate 
  *Encounter encounter
  String instructions
  *User orderer
  Boolean discontinued
  User discontinuedBy
  Date discontinuedDate
  String discontinuedReason
}

DrugOrder

class DrugOrder extends Order{
  Drug drug
  Concept concept;//should be drug.concept if drug is not null
  Double dose
  String doseUnits
  Boolean isStructuredDosing
  Double strength
  String strengthUnits  
  Integer quantity
  String quantityUnits
  String frequency
  String brandName
  String dosageForm
  String route
  Boolean asNeeded  - Indicated PRN
  String asNeededCondition
  String additionalInstructions
  Integer duration
  String durationUnits
  Integer numRefills
}

TestOrder

class TestOrder extends Order{  
  Concept specimenSource  
  Concept laterality  
  String clinicalHistory
}

Orderable

Marker interface for things that a User can order

public interface Orderable {
 String getUniqueIdentifier(); //The unique identifier for this Orderable.
 Concept getConcept(); //The concept of the order that will ultimately be created from this Orderable.
 String getName(); //display name of this orderable, typically should be inherited from the concept. Intended for use in the UI.
 String getDescription(); //display descripion of this orderable, typically should be inherited from the concept. Intended for use in the UI.
}

BaseOrderable

Base implementation of the Orderable interface, should define the  properties and provide the default implementation of the inherited methods

Is Drug.concept nullable?

abstract class BaseOrderable{
   Concept concept; //will this be required?
   String name; //We really need this if drug.concept is nullable and fetch it from the drug?
   String description; //same here
}

SimpleOrderable

Acts a wrapper for a concept or Drug(if drug.concept is nullable) with concept class as 'Drug' or 'Test' or 'Misc Order' or a Drug with no

class GenericOrderable extends BaseOrderable{
  //constructor that takes in a concept
  public SimpleOrderable(Concept concept) {
     ..............
  }

  //constructor that takes in a drug if drug.concept is nullable
  public SimpleOrderable(Drug drug) {
     ..............
  }

 //return something unique with type included i.e Concept Vs Drug(if drug.concept is nullable)
 @Override
  public String getUniqueIdentifier() {
     ...........
  }

}

OrderEntryService

interface OrderService extends OpenmrsService{
  saveOrder(Order);//Should not let you change an Order.  can only do an sql insert from here.
  voidOrder(Order, String voidReason);
  unvoidOrder(Order order);
  purgeOrder(Order);
  //Creates a new order with a new order number that is a "discontinue" order. previous_order_number on this
  //should point to old Order, also finds old Order and marks it as discontinued with the given parameters
  discontinueOrder(Order order, Concept discontinueReason, Date discontinueDate);
  discontinueOrder(Order order, String discontinueReason, Date discontinueDate);
  createOrdersAndEncounter(Patient p, Collection<Order> orders);// activates the orders given, do we need this?
  getOrder(Integer orderId);
  getOrderByUuid(String uuid);
  String getNewOrderNumber();
  getOrderByOrderNumber(String orderNumber);
  Class<T extends Order> getOrder(Integer orderId, Class<T> orderClassType);
  getOrders(Class<T extends Order> orderClassType, List<Patient> patients, List<Concept> concepts, OrderAction action, List<User> orderers, List<Encounter> encounters, List<ConceptClass> conceptClasses);
  getOrdersByOrderer(User user);
  getOrdersByPatient(Patient patient);
  getDrugOrdersByPatient(Patient patient, OrderAction orderAction);
  getDrugOrdersByPatient(Patient patient, OrderAction orderAction, boolean includeVoided);
  getDrugOrdersByPatient(Patient patient);
  getOrdersByEncounter(Encounter encounter);
  List<Order> getOrderHistoryByConcept(Patient patient, Concept concept);
  getOrderables(String query);
  getOrderables(String uniqueIdentifier);
}

OrderValidator

class OrderValidator implements Validator{
  public void validate(Object obj, Errors errors) {
    //Enforce all required fields
    //TODO: What are the extra validation rules?
  }
}

DrugOrderValidator

class DrugOrderValidator extends OrderValidator{
  public void validate(Object obj, Errors errors) {
    super.validate(obj, errors);

    //drug and concept cannot both be null, drug.concept should match concept if not null
    //Check that the class of the concept is Drug
    //TODO: Add other validation rules specific to drug orders
  }
}

TestOrderValidator

class TestOrderValidator extends OrderValidator{
  public void validate(Object obj, Errors errors) {
    super.validate(obj, errors);

    //Check that the class of the concept is Test
    //TODO: Add other validation rules specific to test orders
  }
}