Revising and Renewing Orders

Hi all (particularly @burke and others who worked on the Order Entry API) ,

I’ve been working a bit with the Order Entry API lately, and am trying to best understand how and when to use the REVISE and RENEW order actions and when to void previous Orders.

In the old 1.9 API, orders could be edited, and applications existed (in various modules, core, htmlformentry, etc) that provided a means to do so. Most of the time, Orders were just edited in place, though if one desired they could have written code to void the previous Order and create a new Order. Unlike with Obs, this was not enforced or built into the OpenMRS API for Ordering in 1.9.

In the current system, Orders are immutable, and a subsequent REVISE, RENEW, or DISCONTINUE order is needed to modify an existing Order. Alternatively, one could simply void an existing Order, and then issue a fresh NEW Order for the same orderable with the revised details, though it is unclear how and when this would be considered the right practice. I’m trying to figure out how to support Order editing functionality in htmlformentry and elsewhere, and when to use these particular approaches.

Initially, I figured it was most appropriate to use the REVISE action whenever editing an active Order. However, working with the OrderService API, I’ve run into a few questions. Here is the code in question:

if (REVISE == order.getAction()) {
	if (previousOrder == null) {
		throw new MissingRequiredPropertyException("Order.previous.required", (Object[]) null);
	}
	stopOrder(previousOrder, aMomentBefore(order.getDateActivated()), isRetrospective);
} else if (DISCONTINUE == order.getAction()) {
	discontinueExistingOrdersIfNecessary(order, isRetrospective);
}

Questions:

  1. If I edit an Encounter and revise the details of an Order within that Encounter (so the dateActivated of both the previous and new Order are the same - inherited from the encounterDatetime), this would seem to modify the existing Order so that the stopDate is a moment before the dateActivated. Is this what we want? It would seem like in this case we really would be better off voiding the existing Order and creating a new Order. Is REVISE really appropriate for this use case? Should our API handle this case differently (either via validation rules or logic to void rather than stop where appropriate)?

  2. If I issue a REVISE order, intending to make a future change (eg. in 3 days I want the current order to close and a new order to start) is this an appropriate use of the API? If so, current API seemingly will not work, as it always sets the previous Order stopDate to the dateActivated of the new Order, not to the effectiveStartDate of the new Order (which accounts for scheduled orders as well).

  3. I don’t see any API support for a RENEW order, though presumably one could code it into their own methods. How is RENEW meant to differ from REVISE, if REVISE works as in the code above? What is the meaningful difference between RENEW and REVISE, from an end-user or application design perspective?

Thanks! Mike

3 Likes

tl;dr RENEW is used to re-issue an expiring/expired order/prescription and REVISE is used to change or re-issue an order with changes.

Orders are immutable once signed, since they could be printed and/or sent to external systems and need to be unambiguously traceable throughout their life cycle (which may extend beyond OpenMRS). If we design OpenMRS as a closed system, then orders could not be safely integrated with other clinical systems. This is the same reason behind having DISCONTINUE as a separate order, since voiding an order in OpenMRS does not notify an external system (e.g., nursing MAR, pharmacy, ancillary care, etc.), provides no means to confirm the request to stop the order was fulfilled by external systems, and would not provide an unambiguous reference to the request to stop the order.

If your active orders are also managed in an external system (e.g., a MAR for nursing, a pharmacy system, radiology system, etc.), then voiding the active order in OpenMRS and issuing a NEW order would generate duplicate orders in the external systems (i.e., they would see two NEW orders and have no idea that the original order was discontinued). If you found a way to transmit void events, then the external system would still need to create a virtual discontinue event if it needs – as clinical systems typically do – to track who received or acted on the request to stop the order.

First, I don’t think we should presume orders inherit their timestamp from the Encounter. An order’s dateActivated should be when the order is signed (and potentially sent to external systems). Trying to manage retrospective editing of orders gets dicey, since making changes to orders that could have already been transmitted to other systems and/or carried out, is re-writing history and could have patient safety & medicolegal ramifications. If we were going to support retrospective changes to orders, then this is a case where voiding & cloning would make sense, since it would provide an audit trail (i.e., the ability for someone to recover the historical state).

In the case you describe, I would expect the dateActivated of the revised order to be the current time (when the revision happened) and not artificially changed to match the encounter’s timestamp.

Great question! The effectiveStartDate (aka scheduled_start_date) indicates when the action being requested should be taken and is not meant to delay the request itself. For example, if you want a patient to start aspirin next week, you set this date when you want them to start taking aspirin and that order (your request) is active as soon as you sign it, but the action requested (i.e., to administer the aspirin) is delayed.

If you want an order to be effective for 3 days and then change, you have two options:

  1. Issue two orders, one lasting 3 days and the other with an effectiveStartDate in 3 days. Both will be active orders, but, in 3 days, the first will auto-expire and the 2nd one will take effect.
  2. Issue a single order with instruction to do X for 3 days, then do Y.

RENEW is meant to re-issue an order. The common use case would be to renew a chronic outpatient prescription. For example, someone getting lisinopril for hypertension comes in for their annual check-up and their provider wants them to continue lisinopril for the following year. In this case, the prescription is “renewed,” meaning a new prescription for the standing order is generated/printed with a new set of refills. From a computer/technical standpoint, this is basically a NEW order (or REVISE without any actual changes to instructions); however, it is clinically useful to see this as a renewal to make it easier to distinguish things that are being continued versus newly introduced. For example, if you renew 8 medications, add one, and change the dose of one, it’s friendly & safer to see a bunch of RENEW orders with one REVISE and one NEW instead of a list of revisions, many of which haven’t actually changed.

RENEW is typically an outpatient action (primarily on medication orders, but could be used for any standing order). On the inpatient side (in the hospital), the corollary is CONTINUE, which is used to keep orders from discontinuing during a transfer (e.g., for safety, all orders are assumed to be discontinued unless explicitly continued when a patient transfers between acuity levels or services).

Thanks @burke for the comprehensive response. A few follow-up questions / thoughts:

Makes sense. That said, our API has support for voiding Orders. There are even explicit “voidOrder” and “unvoidOrder” service methods that have ripple effects (stopping and unstopping previous orders associated with the voided Order, etc). So it would seem like a reasonable assumption that voiding Orders is a legitimate thing to do and any integration with an external system would need to take voiding into account and ensure this is communicated properly. Is this typically a gap in current Order Entry integration profiles? Are these not able to handle this kind of event? Is this a real or hypothetical issue? It would be really nice to be able to void Orders and have confidence that our integrations will handle this correctly.

Right, agreed. My assumptions are that a) data entry errors occur, and b) retrospective entry is still quite common. I totally understand that setting dateActivated to the time the Order is signed makes sense where possible, but in the case where you just have an htmlform or a patient’s regimen history in front of you, and you need to make sure the data in the system accurately reflects it, we’ll likely need to support void and recreate and setting the dateActivated to the encounterDate, even if it is well in the past.

This makes sense as you describe. That said, for option #1 it seems like one more Order than should be needed. If I already have an order X that autoExpires in 3 days, and I want to say “extend this for an additional 60 days”, I can do that right now with a single additional Order by just placing a NEW order for the same medication starting 3 days from now (2 separate, non-overlapping orders). But if I want to link the new Order as a RENEW of the current Order, I have to issue an extra Order to do that (REVISE order followed by RENEW Order)? Not the end of the world, I just wouldn’t have expected to need the REVISE necessarily.

Thanks for the help,

Mike

Do we have any standards around what properties of DrugOrder are allowed to be changed when a RENEW is issued? We don’t have any explicit support for this in the API, so wondering what the standard is. From what you describe, it would seem like we’d want to disallow changes aside from:

  • dateActivated
  • scheduledDate
  • urgency
  • duration
  • durationUnits
  • quantity
  • quantityUnits
  • numRefills

Does this sound right? Are there any other validation rules to consider?

I would expect what you’re ordering (formulation) and dosing instructions to be the same for a RENEW order. The items you list and others (e.g., comment to fulfiller) could change.

If there’s a way to allow the API to update the action (change to RENEW if drug & dosing are unchanged or to REVISE if changed), it might be easier for clients to use the API.

Voiding an order is an API action to invalidate an order; discontinuing an order is a user action – i.e., when a user requests to discontinue an order, this request goes through the same workflow as any other order; voiding an order does not. Ideally, an integrated system would provide confirmation that the DISCONTINUE order was received and refer to it by order number if the request is not properly processed. Invalidating an order (voiding it) is an internal action and does not go through the same workflow. For example, when an order is revised, we void* stop the prior version of the order and issue the new one. The revision (the order) would be sent to other systems (e.g., via HL7 messages), but not the internal void operation.

Retrospectively changing the time at which orders occurred gets very messy. @wyclif tried to work through these scenarios and abandoned the idea due to the rabbit hole. Changing the last entry for an order is pretty straightforward; however, changing an order that was subsequently acted on gets nasty (e.g., what if the dateActivated for a past order is moved to be later than a subsequent order that revised it or discontinued it? We might be able to work with the constraint that the dateActivated of an order cannot be earlier than a version that preceded it or later than a version that followed it.

If you have an order X that is set to expire in 3 days and want to extend it for an addition 60 days, then the easiest approach would be to revise the order and change its duration (one step). If you really want to let the existing order expire and then renew it (e.g., you want to print a new prescription for the patient to take to their local pharmacy), then you should be able to create a NEW or RENEW (or REVISE) order that doesn’t overlap (i.e., starting in 3 days). This latter approach could, for example, could print a script for the patient that would have a start date 3 days from now (i.e., that the pharmacy would not fill until that date).


* Oops. I accidentally suggested we void the previous order when revising; when, in fact, we stop the previous order. Thanks to @mseaton for catching this mistake and pointing it out here.

Whoa - hang on @burke :slight_smile: Are you saying that a REVISE operation should void the previous order? That is not what the API currently does - the API stops the previous order. If the revising order has a dateActivated of T, the API sets the “dateStopped” of the previous order to “T - 1s”. So the result is that you have 2 non-voided orders in your history, with the first stopping 1s prior to the second.

I assumed this was the way the API was supposed to work, but I’d be very interested to hear if it isn’t, as that would make it much easier to support these retrospective use cases. eg:

Editing = issuing a ‘REVISE’, which voids the old order and creates a new order with action = ‘REVISE’, and sets it’s previousOrder to the voided order

Changing = issuing a ‘DISCONTINUE’ of the existing order, followed by a ‘NEW’ of the new Order

Or is that not what you meant @burke?

(Incidentally, where the current API causes problems with setting dateStopped on the previous order is where the dateActivated of the revised Order is the same as the dateActivated of the previous Order, because this leads the previousOrder to have dateStopped < dateActivated by 1 second).

Mike

1 Like

From an integration perspective, this sounds like the right workflow.

You’re correct. I misspoke (er, miswrote). I meant to say we stop the previous order, not void. I’ll update my previous post to make that clear.

Personally, I’d prefer we define dateStopped as exclusive – i.e., the time at which the order is no longer active (not the last second that it was active) – and dateActivated as inclusive. This would allow dateStopped of the previous order and the dateActivated to be the same and non-ambiguously define the time at which one order was replaced with the other. It would also make life easier if these were the exact same timestamp in the typical cases (e.g., when an order is revised).

1 Like

Thanks for the clarification - I figured that was the case.

I agree. Do you think it would be problematic to change this behavior at this point as you describe?

Well, we’d need to grep the code for cases where the dateStopped for orders is assumed to be less than dateActivated. Some creative searches combined with a some targeted unit testing might help.

For the data, I’d expect it might be as simple as something like:

UPDATE orders a
INNER JOIN orders b ON b.previous_order_id = a.order_id
SET a.date_stopped = b.date_activated
WHERE
  TIME_TO_SEC(TIMEDIFF(b.date_activated, a.date_stopped)) <= 60;

This seems to be where this decision originated:

We’d want to address the underlying issues that @darius raised in that ticket and confirm that this is the right fix.

A middle ground might be to do something like:

  • If the dateActivated of the revising order = the dateActivated of the order being revised, then set the dateCompleted to the dateActivated without subtracting 1 second.

or

  • If subtracting 1 second from the dateCompleted will result in a dateCompleted < dateActivated, then set the dateCompleted = dateActivated.

Bigger picture I tend to agree that we shouldn’t be doing this in the first place, and should rather change all of the relevant code to assume that dateStopped is exclusive and dateActivated is inclusive, but there are likely broader backwards-compatibility considerations at this point we’d need to consider.

Thoughts? (also if @darius remembers and is lurking, please feel free to chime in :))