Pharmacy Patient Monitor and Pop-Up Alerts Part 1

 

In a recent post I realized that I had never explained how to add events to the Pharmacy system for use with the Rules Engine.  Time to remedy that.  In fact, I’m going to take it to another level and show you:

– Setting up rules to fire off patient monitor alerts in Siemens Pharmacy, both from pharmacy driven rules, and Soarian side workflows calls.
– Creating pop up alerts that interrupt medication validation in pharmacy.
– Pulling pharmacy data into Soarian side workflow processes.
– Pulling Soarian data into pharmacy side rule processes.
– Setting up Pharmacy medication triggers in Character Cell.

So get ready, if you were wondering how the Rules Engine works pharmacy side, this is the update you’ve been waiting for.

First the Scenario

Imagine you had a request to check to see if a patient with a spinal catheter had an anticoagulant ordered, or a patient on an anticoagulant had a spinal catheter ordered.  Big tubes coming out of your back plus drugs that keep you from clotting equals a bad time.  In such a situation an alert should appear in pharmacy. This is especially important because spinal catheters are non-medication orders, so without the alert the pharmacists won’t know that one has been placed on the patient.

Before going further, it’s worth noting that there are two different types of Pharmacy alerts: those that appear on the patient monitor or on a patient when a pharmacist first loads their patient profile, and another that appears as an action (in this case a medication being placed) occurs.  The first is persistent, but doesn’t interrupt processing.  The other pops up right away, but is gone as soon as it’s dismissed.

This is important because in this situation we don’t know how the conflict is going to arise.  The anticoagulant could be placed first, and then a spinal catheter order is placed in Soarian, or the spinal catheter order is placed and then the anticoagulant medication is ordered (or the order is validated) in Siemens Pharmacy.  Only if the conflict is discovered as the anticoagulant is being validated will a pop-up alert be of any use, or will the event we create Pharmacy side even fire.  So then how to you get the persistent alert on the patient if the conflict is triggered by spinal catheter event?  Well, then you’ve got to fire the Pharmacy alert using a Soarian side event subscription (aka a workflow).  Don’t worry.  We’re goign to cover all of this, but let’s start with:

The Patient Monitor Alert – When Driven by Spinal Catheter Order

So in the case of a spinal catheter order being placed, we want to check for the existence of an active anticoagulant medication, and if one is found then fire off the alert.

So in the case of a spinal catheter order being placed, we want to check for the existence of an active anticoagulant medication, and if one is found then fire off the alert.

Not seen above is the non-medication order subscription.  Then we only continue if the order type is one of the spinal drain types we care about.  Then we need a rule that can access medication orders in order to see if the patient is on any of these listed anti-coagulants.  Here’s a look at the qualifier for such a rule.


WKF_GET_MED_ORDER_DETAILS
EXPIRE_MINUTES 0
GROUPED_POSITION 0
GROUPED_SEGMENT1 MedOrderData
GROUPED_SEGMENT2 IVOrderData
MXS_ERROR_MESSAGE_FIELD StatusMessage
MXS_ERROR_RECID_FOUND MESSAGESTATUS
MXS_ERROR_STATUS_FIELD StatusCode
MXS_REQUEST_RX_ORDERS Rules_RxOrderData|GetOrderData|MedRecNum|{user=PATIENT_MRN}|PtNumber|{user=ACCOUNT_ID}
TIMESTAMP_FIELDS StartDtm|StopDtm
TIMESTAMP_POSITION 0
TIMESTAMP_RECORDS MedOrderData|IVOrderData

Note that this is a Pharmacy side qualifier, not a Soarian side one.  This is because medications placed within pharmacy, but not yet administered, will not show up in the Soarian side database, so this will give us more complete information. And here’s the rule code:

Workflow – Get A Medication Order’s Details

Additionally, we a rule to fire off the Patient Monitor alert. I recommend using a sub rule that can be called directly from Pharmacy side rules, or from Soarian side using a wrapper rule that will put the patient data in the correct format for Siemens Pharmacy. Here’s the wrapper rule code:

Workflow – Write A Pharmacy RX Alert

If you don’t want to write your own custom rule for writing out the alert, you can always call the model rule SUB_WRITE_TO_RX_ALERT instead. The alert will end up looking like this in the Pharmacy system:

When you first access a patient with the alert on them this will pop-up.

When you first access a patient with the alert on them this will pop-up.

The alert will also be listed under the Patient Monitor section.

The alert will also be listed under the Patient Monitor section.

I’ll go over the way to add Pharmacy side events to trigger rules (and tie them to medications) and how to fire the pop-up alerts in Siemens Pharmacy in the part 2.

The missing Pharmacy services API

So one thing that’s likely a frustration to many rules developers out there is the lack of an API document for the pharmacy services.  There’s an extensive API for Soarian side services, but no equivalent for Siemens Pharmacy.  So how do you know what you even have access to?  I mean you can add additional events to fire off when medications are validated (I should probably do a post showing how that’s done…) but that still wouldn’t give you any notion of default events you have access to.  Thankfully, some digging in the Pharmacy database reveals that the main reason for there being no API is that the default services can be counted on your fingers.  The most familiar will likely be the Home Medication List.

TITLE

SYSTEM

MANDATORY

CATEGORY

PURPOSE

A SUPPORT SUPPORT PHM YES TST RX SUPPORT RULE
A SUPPORT VALIDATE PHM YES TST RX VALIDATE RULE
DISCHARGE MEDICATION PHM NO PHM TO DISPLAY THE LIST OF DISCHARGE MEDS
GENTAMICIN DOSING CALCULATION PHM NO PHM THIS WILL CALCULATE THE DOSE AND FREQUENCY OF >GENTAMICIN
HOME MED LIST PHM NO PHM TO DISPLAY HOME MED LIST COLLECTED AT ADMISSION
REMINDER FOR NEUPOGEN USE PHM NO PHM TO REMIND THE CLINICIAN TO DISCONTINUE GRANULOCYTE COLONY
RENAL FUNCTION AND NSAIDS PHM YES PHM THIS RULE WILL CHECK THE RENAL FUNCTION IN ELDERLY
RISING K LEVELS WHEN PATIENT IS ON K PHM NO PHM WARN OF RISING POTASSIUM LEVELS IN PATIENT ON
WRITE DEBUG-TEST TO CUSTOMAUDIT BOTH YES TEST TEST COMMUNICATION WITH RULES ENGINE

I just figured I’d share that as an easy reference in case you wanted to know what events existed by default in Siemens Pharmacy.  I’ll do another post later describing how to add your own event listeners for medication validations, link them to specific drugs (by GCN code) and use them to do things like check for medication conflicts.  But this list will help you to know what events already exist in the default system.

Do keep in mind that just because an event is there, doesn’t mean that it does anything.  As with the home medication list, the event was there, but until you put a rule in place to actually return output, the event has nothing to trigger.

Preparation for the new workflow engine

As many of you are already aware, the replacement for the current iProcess engine is scheduled to come this year.  When it does, you’re going to need to port over your workflow code.  There will (I’m sure) be various nuances and techniques specific to the new engine, requiring changes in coding style and more features (the ability to listen for event from Soarian Financials appears to be a big promising new feature), but the first thing that every organization will have to deal with is porting over their existing workflow code.

So without access to the new system, how can one prepare for it?  Well one thing to note is that you will be able to copy over the steps into the new engine, though they just won’t do anything.  They’ll basically be replaced with placeholder steps with labels.  So the outline of the logic will be scaffolding, but without any functionality.  Also, the rules engine isn’t going anywhere.

Knowing this, there is one clear way to prepare and make sure that the porting process is easier: Use generic rules as a go between for calling services.  Now I’m sure that the service call workflow sub procedures will have their equivalents within the new system, but will they all be available from the very beginning?  Will the input values change?  If you combine using generic rules with a single workflow sub procedure for rule calls, then all service call steps can easily be rebuilt.  You would just need to ensure that you have the one sub procedure rebuilt (and I have it on good authority that the new workflow engine will use a single rule call sub procedure as model), and then you can just copy and paste the inputs and outputs from your previous iProcess build.  There’s nothing preventing you from having your workflows built like this now, and it will certainly make the porting process easier come upgrade time.

UPDATE –

I figure I should link to Tibco’s official Active Matrix documentation files.  Start with the tutorial file (which comes in html format or in the pdf download pack) if you’re a current healthcare iProcess developer.

Auto-Generated TOC / CCDA Letters

The workflowo and rules engines can be used to auto-generated transition level of care / CCDA letters. Before you can generate a CCDA, you need its template. The system can’t automatically generate the CCDA if nobody can generate the CCDA. This involves getting the template set up…

You should get the template with 3.4, but you still need to set it up in the clinical letter preferences section, similarly to the (now outdated) Summarization of Episode clinical letter.

You should get the template with 3.4, but you still need to set it up in the clinical letter preferences section, similarly to the (now outdated) Summarization of Episode clinical letter.

Auto-Generated TOC CCDA Letters - 2

Somebody has to have the power to create the CCDA for it to be generated automatically. Of course this doesn’t have to be a real user. There are a few system users, one being the Workflow Engine user. You can’t log in as this user, but you can use them to create clinical letters. You’re going to need a creator and a user to generate the CCDA, and the user does have to be a valid log in, though they don’t need these permissions. You can get their object ID from the HUser table. Also, the default template should come with your 3.4 upgrade. Check the HStaff table for the object ID to pass in as the creator.

SELECT stf.ObjectID, stf.Name

FROM HStaff stf

WHERE stf.Name LIKE '%Workflow%'

You still have to use valid user credentials to generate the clinical letter. The user is different from the creator and the user has to be an account that could actually be logged into. We set up a dummy account in TEST and another for PROD. There was this whole big security discussion regarding setting up the one in PROD, but that’s not a technical issue, so you’re going to have to figure it out on your own (sorry).

You can use different users to generate the clinical letter in different environments, and conditionally set those variables prior to calling the sub procedure.

You can use different users to generate the clinical letter in different environments, and conditionally set those variables prior to calling the sub procedure.

There is a model sup procedure named 11AGCL00 (Create clinical letter) that is meant to generate clinical letters. Unfortunately, you may run into a bit of an issue. Using the model sub procedure everything works great, ninety something percent of the time. The issue is that the service call sub procedure gets feedback after it attempted to create a letter, in order to verify that the service had run correctly. If it doesn’t get back a good status, then it pops a handle error and tried again 5 minutes later. That’s standard practice. But sometimes the letter could be created, but not return the status message in a timely manner due to occasional system slowdown or the sheer size of the letter being generated. This would lead to duplicates. The sub procedure thinks it has failed, when it hasn’t, so it creates another CCDA a second time when it retries.

If you use the default service and there’s a system slowness issue, then it’s possible for the workflow to think it failed to create a TOC, when it in fact did.  It will then automatically retry and you’ll end up with multiples.  To get around this you need a logic loop like this.

If you use the default service and there’s a system slowness issue, then it’s possible for the workflow to think it failed to create a TOC, when it in fact did. It will then automatically retry and you’ll end up with multiples. To get around this you need a logic loop like this.

This requires a custom rule and some TDEs as well that retrieve the number of clinical letters that a patient has for a particular visit.

WKF_GET_NUMBER_OF_CLINICAL_LETTERS

Auto-Generated TOC CCDA Letters - 6

You’ll also need to make a modified copy of the model sub procedure 11AGCL00. The model sub procedure checks to see if it worked or not, the modified version takes more of a, “fire and forget,” approach. It’s just deleting a bunch of steps to get rid of error checking. The rule will check after the fact to see if a patient has the TOC and this way, if there is a system slow down, it will never result in a duplicate TOC being generated.

Auto-Generated TOC CCDA Letters - 7

Which you’ll then also have to put back into that earlier logic loop. Just switch out the default with the new fire and forget version. And give it a custom icon, it’s classier.

Auto-Generated TOC CCDA Letters - 8

And finally you should be done, and able to auto generate CCDAs… errr TOCs, well whatever acronym you prefer.

Auto-Generated TOC CCDA Letters - 9

Anticoagulant Home Education

Her’es the clinical scenario: auto ordering anticoagulant home education based on medication administration. When an anticoagulant is administered, check to see if the patient already has a particular education order (with status active or complete). If they do not, then place one. This is a clinical quality measure for you aspiring Meaningful Use attesters.

After a medication administration event we check to see if the home education order exists (twice because we need to check both active and complete status).  Then (if no such order was found) we check to see if the administration was an anticoagulant (only Eliquis and Pradaxa are showing, but there’s more below).  Then (if an anticoagulant was among the administrations) we repeat the order check because sometimes multiple administrations come through milliseconds after each other and so we need this check right before placing the order to avoid duplication.  And finally we place the order.

After a medication administration event we check to see if the home education order exists (twice because we need to check both active and complete status). Then (if no such order was found) we check to see if the administration was an anticoagulant (only Eliquis and Pradaxa are showing, but there’s more below). Then (if an anticoagulant was among the administrations) we repeat the order check because sometimes multiple administrations come through milliseconds after each other and so we need this check right before placing the order to avoid duplication. And finally we place the order.

Here’s the input for the rule call that checks for education orders with status complete.

Here’s the input for the rule call that checks for education orders with status complete.

The complex parts are the rules that allow the workflow to retrieve details about specific orders and administrations.

WKF_GET_NONMED_ORDER_DETAILS

Here’s a quick glance at the custom qualifier (calling the OaR_RetrieveOrderInfo service) that powers the rule for retrieving an order’s details.  I like to give custom qualifiers the same names as the rules that they’re written for (it keeps things easier to manage).  So the rule is also named WKF_GET_NONMED_ORDER_DETAILS.  It’s basically a modified version of the QUERY_GET_ORDERS model qualifier.

Here’s a quick glance at the custom qualifier (calling the OaR_RetrieveOrderInfo service) that powers the rule for retrieving an order’s details. I like to give custom qualifiers the same names as the rules that they’re written for (it keeps things easier to manage). So the rule is also named WKF_GET_NONMED_ORDER_DETAILS. It’s basically a modified version of the QUERY_GET_ORDERS model qualifier.

WKF_GET_ADMINISTRATION_DETAILS

And we also have a custom rule and qualifier named WKF_GET_ADMINISTRATION_DETAILS, which is similar to the model qualifier QUERY_GET_MED_ADMINISTRATIONS.

And we also have a custom rule and qualifier named WKF_GET_ADMINISTRATION_DETAILS, which is similar to the model qualifier QUERY_GET_MED_ADMINISTRATIONS.

Here’s an image of an order that was placed using this workflow.  The Enoxaparin order below it was administered, which drove the workflow to place the education order.  In addition, this assessment will show up as Uncharted in the nurse’s clinical documentation worklist because it’s linked to the education order.  Then once they save the documentation as complete, the order is completed and removed  and the clinical documentation work list and the scheduled / incomplete assessment window.

Here’s an image of an order that was placed using this workflow. The Enoxaparin order below it was administered, which drove the workflow to place the education order. In addition, this assessment will show up as Uncharted in the nurse’s clinical documentation worklist because it’s linked to the education order. Then once they save the documentation as complete, the order is completed and removed and the clinical documentation work list and the scheduled / incomplete assessment window.

Innovations 2014 – Tampa

So Innovations, the big annual Siemens (possibly soon to be Cerner) Healthcare convention is in Tampa this year. I’ll be giving two presentations on Tuesday. One is a panel on automated sepsis screening processes, and the other is about Rules Engine coding. Here are the sessions and times:

Improving Efficiency and Patient Outcomes with Sepsis Workflows, Alerts, Assessments, and Orders
Session 5: Tuesday, August 12 – 9:30 a.m. – 10:30 a.m.

Unique Utilizations of the Rules Engine
Session 7: Tuesday, August 12 – 1:45 p.m. – 2:45 p.m.

I’ll also be putting up copies of the presentations and associated files here after I’ve given them one final glance over with my fellow presenters in Tampa. Hope to see you there!

UPDATE –

The connection speed at my hotel does not enable me to effectively upload these files.  Expect an update tomorrow with the slides.

UPDATE #2 –

All presentations available at: www.usa.siemens.com/InnovationsIT

Soarian Order “Select_Service” Evoke Slots

So let’s say you want to run some other logic not on an order being signed, but on an order being selected and (presumably) being about to be signed in Soarian Clinicals? The most common reason for this is firing off some warning or alert if there is a conflict or potential safety risk associated with the order. Because there’s no event listener for this (and also because Soarian order warinings, if that’s what you intend to do, require interrupting processing) you need to use a rule evoke slot instead of a workflow listener. Now it is possible to fire off a WFE_CaseEvent from within the rule, which then triggers workflow processing to occur, but regardless of your end goal, you need an evoke slot to capture the action of selecting the order.

The format for this evoke slot is laid out in SOARIAN_COS_MED_PLACE_ORDER_SUGGESTED_ACTION (which is a model rule, so I won’t post it here). Basically it’s “Select_Service\\ExampleDrug” where “ExampleDrug” is really the Common Definition Name of the order. For example here is one for a particular form of alteplase:

"Select_Service\\Alteplase4"

“Select_Service\\Alteplase4”

Now if you want a rule to run for one and only one order, then that makes things fairly straight forward. But what if you want a rule to run for various forms of the same drug (maybe there’s an Alteplase1, Alteplase2, and Alteplase3)? Or what if you want a rule to run for all different anticoagulants, but have it process things slightly differently based on the particular medication given? At that point you’d need multiple evoke slots, but you would have to determine which order was the one that triggered the rule from within the rule itself. Thankfully the rule has access to that data within the RunTimeEnvironment. It’s stored in the variable cardc#eventname. Unfortunately, it contains the entire evoke slot itself rather than just the common definition name. To strip out the part we want access to you can use this piece of code in the data section of your rule:

Common_Definition_Name := “”;
eventname := READ LAST {SELECT “cardc#eventname” FROM “RunTimeEnvironment”};

// Determine drug service being ordered
IF eventname IS PRESENT THEN
eventname := UPPERCASE(eventname);
posBeginDrugName := FIND “\\” IN STRING eventname;
posBeginDrugName := posBeginDrugName+1;
lenEventName := LENGTH eventname;
lenDrugName := (lenEventName – posBeginDrugName) + 1;
Common_Definition_Name := SUBSTRING lenDrugName CHARACTERS STARTING AT posBeginDrugName FROM eventname;
ENDIF;

With that you’ll have access to the common definition name of the order that actually triggered the rule to fire. In some ways the is the Soarian side equivalent of pharmacy order triggered rules like this.

There’s just one big question left. What happens if you place two orders that are both set to trigger the same rule? Which evoke slot has priority? This actually is just a thought that occurred to me as I was writing this up. Time to go do some research. Expect an update soon.