948 lines
38 KiB
Plaintext
948 lines
38 KiB
Plaintext
maintenance:
|
|
|
|
title: Venipuncture Consolidation;;
|
|
mlmname: STD_VENIPUNCTURE;;
|
|
arden: version 2.5;;
|
|
version: 18.4;;
|
|
institution: Allscripts, Standard MLM;;
|
|
author: Allscripts Healthcare Solutions, Inc.;;
|
|
specialist: ;;
|
|
date: 2018-10-26;;
|
|
validation: testing;;
|
|
|
|
/* P r o p r i e t a r y N o t i c e */
|
|
/* Unpublished (c) 2013 - 2018 Allscripts Healthcare, LLC. and/or its affiliates. All Rights Reserved.
|
|
|
|
P r o p r i e t a r y N o t i c e: This software has been provided pursuant to a License Agreement, with
|
|
Allscripts Healthcare, LLC. and/or its affiliates, containing restrictions on its use. This software contains
|
|
valuable trade secrets and proprietary information of Allscripts Healthcare, LLC. and/or its affiliates and is
|
|
protected by trade secret and copyright law. This software may not be copied or distributed in any form or medium,
|
|
disclosed to any third parties, or used in any manner not provided for in said License Agreement except with prior
|
|
written authorization from Allscripts Healthcare, LLC. and/or its affiliates. Notice to U.S. Government Users:
|
|
This software is {{{SINGLE-QUOTE}}}Commercial Computer Software{{{SINGLE-QUOTE}}}.
|
|
|
|
All product names are the trademarks or registered trademarks of Allscripts Healthcare, LLC. and/or its affiliates.
|
|
*/
|
|
/* P r o p r i e t a r y N o t i c e */
|
|
|
|
library:
|
|
purpose: Recommends consolidation of blood collections to improve patient comfort by
|
|
avoiding duplicate venipunctures and to avoid inefficient blood draws.
|
|
Provides Actions on Alerts with each recommendation.
|
|
;;
|
|
explanation: An Evoking-Order is considered a candidate for venipuncture consolidation
|
|
of Other-Orders when all of the criteria listed below are met:
|
|
a. The Evoking-Order is one of the following events: new order, released from hold,
|
|
activated from a conditional order, unsuspended, verified, or an order that
|
|
has a modified significant-date.
|
|
b. The evoking-order has a Type Code of "Diagnostic." "Medication" and "Other" are
|
|
excluded, unless the order name is listed in the event clause.
|
|
c. A flag, check_for_unsubmitted_orders, in the MLM determines which Other-Orders
|
|
are checked. FALSE=only orders stored in the database. TRUE=unsubmitted orders
|
|
and orders stored in the database. The default setting is TRUE.
|
|
d. The orders (Evoking-Order and the Other-Orders) have order status level numbers
|
|
between 0-50 (AWPA-AUA10, inclusive), excluding 15 = HOLD.
|
|
e. CONDITIONAL, PRN, and Suspended orders are excluded.
|
|
f. Master Repeat Orders are excluded.
|
|
g. The orders have been designated for venipuncture consolidation checking with
|
|
an "HVC-Venipuncture" "Yes" in their item-catalog-Ordering Information 2 panel.
|
|
h. The location of the patient is not excluded from venipuncture checking in
|
|
the HVC-Venipuncture Policy. The patient{{{SINGLE-QUOTE}}}s location is based on
|
|
the location-business-rules established by the facility for other parts of
|
|
Sunrise Clinical Manager.
|
|
i. The Other-Orders are within the scoping rules for the patient location listed
|
|
in the HVC-Venipuncture Policy.
|
|
j. The Other-Orders are within the consolidation period specified in
|
|
HVC-Venipuncture Policy, and are NOT in the past (ie. less than NOW, adjusted
|
|
by the EXACT MATCH time criteria in the HVC-Venipuncture Policy).
|
|
k. STAT orders cannot be consolidated.
|
|
Routine (RTN) orders can be moved to a time critical (TIMEC) collection time,
|
|
but a TIMEC order cannot be moved to a RTN collection time.
|
|
Two RTN orders can be moved to the others collection times.
|
|
l. Exception---If another order requiring a venipuncture is already scheduled for
|
|
the same time slot as the evoking order, then a venipuncture alert is not needed,
|
|
since it is already consolidated.
|
|
|
|
The GENERATE_ACTIONS_ON_ALERTS variable indicates whether to generate
|
|
Actions on Alerts. The values are:
|
|
* TRUE = Generate Actions on Alerts
|
|
* FALSE = Do NOT generate Actions on Alerts
|
|
|
|
Master orders (ComplexOrderType of 1,3,5) existing in the database from Complex and
|
|
Multiple Frequencies Orders are not checked.
|
|
The following ComplexOrderType values define the type of order:
|
|
0 or NULL - regular order
|
|
1 - Sequential Complex Dose Master
|
|
2 - Sequential Complex Dose Child Order
|
|
3 - Concurrent Complex Dose Master
|
|
4 - Concurrent Complex Dose Child Order
|
|
5 - Multiple Frequencies Master
|
|
6 - Multiple Frequencies Child Order
|
|
|
|
Change history
|
|
|
|
12.27.2010 DW Added site customization to 5.5 version
|
|
02.26.2013 JML Added logic to not display venipuncture alert for AM Round orders
|
|
07.15.2015 TMS Added site customization to 15.1 version. CSR 33555
|
|
11.14.2016 TMS Added site customization to 16.3 version. CSR 35130
|
|
03.21.2019 TMS Added site customization to 18.4 version. CSR 37676
|
|
|
|
|
|
;;
|
|
keywords: Venipuncture;
|
|
;;
|
|
citations:
|
|
{{+B}}Development{{-B}}: Allscripts Healthcare Solutions, Inc. Clinical Information can be customized and configured by local facility.
|
|
{{+B}}Funding{{-B}}: None specific to the development of this alert
|
|
{{+B}}Release{{-B}}: None
|
|
{{+B}}Revision Date{{-B}}: 2012-11-07
|
|
|
|
{{+B}}Citations{{-B}}: None
|
|
;;
|
|
knowledge:
|
|
type: data-driven;;
|
|
data:
|
|
/***************Make Changes To Spelling And Flags In This Section***************/
|
|
/* Set to true if logging is needed.*/
|
|
log_execution_info := false;
|
|
|
|
/* If UNSUBMITTED orders need to be checked for venipuncture consolidation */
|
|
/* Set the flag below to TRUE */
|
|
check_for_unsubmitted_orders:= TRUE;
|
|
|
|
/* Set a flag indicating whether or not Actions on Alerts should be generated */
|
|
generate_actions_on_alerts := TRUE;
|
|
|
|
/* Change the message within the quotes if a different short-message is needed.*/
|
|
venipuncture_alert:= destination { Alert: warning,
|
|
"Venipuncture Consolidation", low, chart,
|
|
"HVC Activity Consolidations", 1005 };
|
|
|
|
/* Change the spelling within the quotes to match the order item-catalog.*/
|
|
/* If Non-diagnostic (Medication or Other) orders need to be screened, */
|
|
/* change the string "Order_Name#" to the name of the non-diagnostic order. */
|
|
/* If there are more than 3 of these, add more ORs to the where clause */
|
|
|
|
any_new_order:= event {OrderEnter User Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )};
|
|
|
|
any_new_patient_group_order:= event {OrderEnter Batch Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )
|
|
AND IsCreatedFromPatientGroupOrderTemplate = TRUE};
|
|
|
|
any_modified_order:= event {OrderModify User Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )};
|
|
|
|
|
|
any_released_order:= event {OrderRelease User Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )};
|
|
|
|
|
|
any_unsuspended_order:= event {OrderUnsuspend User Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )};
|
|
|
|
|
|
any_verified_order:= event {OrderVerify User Order:
|
|
WHERE OrderStatusLevelNum >= 0
|
|
AND OrderStatusLevelNum <= 50
|
|
AND OrderStatusCode <> "HOLD"
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> "STAT"
|
|
AND (TypeCode = "Diagnostic"
|
|
OR Name = "Order_Name1"
|
|
OR Name = "Order_Name2"
|
|
OR Name = "Order_Name3" )};
|
|
|
|
|
|
/***************** Do not change these Internal Representations *****************/
|
|
|
|
hold_code:= "HOLD";
|
|
stat_code:= "STAT";
|
|
routine_code:= "RTN";
|
|
time_critical_code:= "TIMEC";
|
|
lowest_level:= 0;
|
|
highest_level:= 50;
|
|
|
|
/* Set the master order types */
|
|
complex_master_order_type := (1,3,5);
|
|
|
|
continue_checking_order := true;
|
|
|
|
/********************************************************************************/
|
|
|
|
/* Executes only when this MLM is called by the editor */
|
|
if called_by_editor then
|
|
order_obj:= read last
|
|
{Order: This
|
|
WHERE Name = "cbc"
|
|
// AND complexordertype is not in (2,4,6)
|
|
// AND ORDERSTATUSLEVELNUM <=50
|
|
};
|
|
EvokingObject:= order_obj;
|
|
endif;
|
|
|
|
/* Declares MLMs which can be called */
|
|
calc_duration:= MLM {{{SINGLE-QUOTE}}}std_func_dup_duration{{{SINGLE-QUOTE}}};
|
|
func_venipuncture_actions := MLM {{{SINGLE-QUOTE}}}std_func_venipuncture_actions{{{SINGLE-QUOTE}}};
|
|
|
|
/* Gets the Client GUID */
|
|
client_guid := read last {ClientInfo: GUID};
|
|
|
|
/* Gets the TimeZone of current evoking order */
|
|
visit_tz := read last {ClientVisit: TimeZone};
|
|
|
|
/* Gets information from the evoking Order */
|
|
(order_name,
|
|
order_guid,
|
|
order_status_code,
|
|
order_level_num,
|
|
order_summary_line,
|
|
item_catalog_guid,
|
|
chart_guid,
|
|
client_visit_guid,
|
|
order_significant_date,
|
|
order_stop_date,
|
|
order_sys_priority,
|
|
order_user_priority,
|
|
order_is_conditional,
|
|
order_complex_type,
|
|
order_variable_component_obj,
|
|
back_up_obj) := read last
|
|
{Order: Name, GUID, OrderStatusCode, OrderStatusLevelNum, SummaryLine,
|
|
OrderCatalogMasterItemGUID, ChartGUID, ClientVisitGUID, SignificantDtm, StopDtm
|
|
SystemOrderPriorityCode, OrderPriorityCode, IsConditional, ComplexOrderType,
|
|
OrderVariableComponent, BackUp
|
|
REFERENCING EvokingObject};
|
|
|
|
|
|
|
|
|
|
/* Check to see if this is a master order and if so whether children exist */
|
|
if exists order_complex_type
|
|
and order_complex_type IS IN complex_master_order_type
|
|
then
|
|
|
|
/* Gets information from the order variable components */
|
|
(component_child_order_guid_list) := read
|
|
{OrderVariableComponent: ChildOrderGUID
|
|
REFERENCING order_variable_component_obj};
|
|
|
|
/* Check to see if children exist */
|
|
if exists component_child_order_guid_list
|
|
then
|
|
child_orders_generated := true;
|
|
|
|
/* If children exist, this MLM should not run on Master order on modify or unsuspend */
|
|
If EvokingEventType = any_modified_order.type
|
|
OR EvokingEventType = any_unsuspended_order.type
|
|
then
|
|
|
|
continue_checking_order := false;
|
|
endif; //If EvokingEventType = any_modified_order.type
|
|
|
|
/* This is a master order without children*/
|
|
else
|
|
continue_checking_order := true;
|
|
endif; //if exists component_child_order_guid_list
|
|
|
|
endif; //if exists order_complex_type
|
|
|
|
|
|
/* Determines if a modified order should be checked for duplicates */
|
|
If EvokingEventType = any_modified_order.type
|
|
and continue_checking_order
|
|
then
|
|
|
|
if exist back_up_obj
|
|
then
|
|
back_up_obj_date:= read last
|
|
{Order: SignificantDtm
|
|
REFERENCING back_up_obj};
|
|
|
|
if (back_up_obj_signif_date <> order_significant_date)
|
|
OR
|
|
(back_up_obj_stop_date <> order_stop_date)
|
|
OR
|
|
(back_up_obj_stop_date is null and order_stop_date is time)
|
|
OR
|
|
(back_up_obj_stop_date is time and order_stop_date is null)
|
|
then continue_checking_order:= true;
|
|
endif; /* back_up_obj_signif_date... */
|
|
else
|
|
continue_checking_order:= false;
|
|
endif; /* if exist back_up_obj */
|
|
endif; /* If EvokingEventType = any_modified_order.type */
|
|
|
|
// St.Clair Hospital Customization after this //
|
|
|
|
/* Get User Info */
|
|
|
|
no_fire_on_User := ("gfino","chughes","mvennero");
|
|
|
|
user_id := read last {UserInfo: idcode};
|
|
userinlist := user_id in no_fire_on_User;
|
|
|
|
if userinlist = True
|
|
then
|
|
continue_checking_order := False;
|
|
endif;
|
|
|
|
//CSR 25233: AM Rounds change
|
|
if (order_user_priority = "AM Rounds") then
|
|
continue_checking_order := false;
|
|
endif;
|
|
|
|
// St.Clair Hospital Customization before this //
|
|
|
|
If continue_checking_order
|
|
then
|
|
|
|
/* Gets the Item-Catalog GUIDs that have HVC-Venipuncture YES associated with it */
|
|
(venipuncture_catalog_GUID_list,
|
|
veni_value,
|
|
veni_code):= read
|
|
{"SELECT CV3CatalogClassTypeValue.CatalogMasterGUID,"
|
|
||" CV3CatalogClassTypeValue.Value, CV3ClassType.Code "
|
|
||" FROM CV3ClassType JOIN CV3CatalogClassTypeValue "
|
|
||" ON CV3ClassType.GUID = CV3CatalogClassTypeValue.ClassTypeGUID "
|
|
||" WHERE CV3ClassType.Code = {{{SINGLE-QUOTE}}}HVC-Venipuncture{{{SINGLE-QUOTE}}} "
|
|
||" AND CV3CatalogClassTypeValue.Value = {{{SINGLE-QUOTE}}}Yes{{{SINGLE-QUOTE}}} "
|
|
||" AND CV3CatalogClassTypeValue.Active = 1 " };
|
|
|
|
|
|
/* Continue if the Item-Catalog is marked with a HVC-Venipuncture YES */
|
|
If item_catalog_GUID is in venipuncture_catalog_GUID_list
|
|
then
|
|
/* Gets the patient{{{SINGLE-QUOTE}}}s location group */
|
|
If called_by_editor
|
|
Then
|
|
/* Since the patient has many visits, we must get the one from the Evoking Object */
|
|
patient_loc_group:= read last
|
|
{ ClientVisit: BusinessRuleLocationGUID
|
|
where GUID = client_visit_guid};
|
|
Else
|
|
patient_loc_group:= read last
|
|
{ ClientVisit: BusinessRuleLocationGUID};
|
|
Endif;
|
|
|
|
/* Gets the HVC-Venipuncture Policy information */
|
|
(venpuncture_policy_name,
|
|
policy_loc_group_guid_list,
|
|
policy_scope_list,
|
|
policy_performed_time_list,
|
|
policy_performed_unit_list,
|
|
policy_exact_time_list,
|
|
policy_exact_unit_list,
|
|
policy_scheduled_time_list,
|
|
policy_scheduled_unit_list,
|
|
policy_loc_is_excluded_list) := read
|
|
{"SELECT Name, LocationGroupGUID, SearchScope, PastTime, PastTimeUnits,"
|
|
|| " ExactTime, ExactTimeUnits, FutureTime, FutureTimeUnits, IsExcluded"
|
|
|| " FROM CV3OrderDuplicatePolicy JOIN CV3OrderDuplicatePolicyDtl "
|
|
|| " ON CV3OrderDuplicatePolicyDtl.OrderDuplicatePolicyGUID = "
|
|
|| " CV3OrderDuplicatePolicy.GUID "
|
|
|| " WHERE CV3OrderDuplicatePolicy.Name = {{{SINGLE-QUOTE}}}HVC-Venipuncture Policy{{{SINGLE-QUOTE}}} "
|
|
|| " AND LocationGroupGUID IN (0, " || SQL(patient_loc_group) || " )"
|
|
|| " AND CV3OrderDuplicatePolicy.Active = 1 "
|
|
|| " AND CV3OrderDuplicatePolicyDtl.Active = 1 "};
|
|
|
|
/* Matches patient{{{SINGLE-QUOTE}}}s location group to the item-catalog{{{SINGLE-QUOTE}}}s location group and */
|
|
/* Determines if the match excludes the location from duplicate checking */
|
|
If exist policy_scope_list
|
|
then
|
|
If any (patient_loc_group = policy_loc_group_guid_list)
|
|
then
|
|
loc_group_found := patient_loc_group = policy_loc_group_guid_list;
|
|
else
|
|
loc_group_found := policy_loc_group_guid_list is null;
|
|
endif;
|
|
loc_is_excluded := last (policy_loc_is_excluded_list where loc_group_found);
|
|
endif; /* if exist policy_loc_group_guid_list */
|
|
|
|
|
|
/* Continue if there is a location group match or a default location group */
|
|
/* and the location is not excluded from duplicate checking */
|
|
If any loc_group_found and not loc_is_excluded
|
|
then
|
|
/*--------------------------------------------------*/
|
|
/* Finds the scope and times for the location group */
|
|
/*--------------------------------------------------*/
|
|
policy_loc_grp := last (policy_loc_group_guid_list where loc_group_found);
|
|
policy_scope := last (policy_scope_list where loc_group_found);
|
|
policy_performed_time := last (policy_performed_time_list where loc_group_found);
|
|
policy_performed_unit := last (policy_performed_unit_list where loc_group_found);
|
|
policy_exact_time := last (policy_exact_time_list where loc_group_found);
|
|
policy_exact_unit := last (policy_exact_unit_list where loc_group_found);
|
|
policy_scheduled_time := last (policy_scheduled_time_list where loc_group_found);
|
|
policy_scheduled_unit := last (policy_scheduled_unit_list where loc_group_found);
|
|
|
|
|
|
/*-------------------------------------*/
|
|
/* Converts EXACT TIME into Arden Time */
|
|
/*-------------------------------------*/
|
|
If policy_exact_time > 0 and policy_exact_unit is string
|
|
then
|
|
exact_duration:= call calc_duration with
|
|
(policy_exact_time, policy_exact_unit);
|
|
If policy_exact_unit = "days"
|
|
then exact_low_time:= (day floor of order_significant_date)
|
|
- exact_duration ;
|
|
exact_high_time:= (day floor of order_significant_date)
|
|
+ exact_duration + (1 day) - (1 second);
|
|
else exact_low_time:= order_significant_date - exact_duration;
|
|
exact_high_time:= order_significant_date + exact_duration;
|
|
endif; /* if policy_exact_unit = */
|
|
else
|
|
exact_low_time:= order_significant_date;
|
|
exact_high_time:= order_significant_date;
|
|
endif; /* if policy_exact_time > 0...*/
|
|
|
|
|
|
/*-----------------------------------------*/
|
|
/* Converts PERFORMED TIME into Arden Time */
|
|
/*-----------------------------------------*/
|
|
If policy_performed_time > 0 and policy_performed_unit is string
|
|
then
|
|
performed_duration:= call calc_duration with
|
|
(policy_performed_time, policy_performed_unit);
|
|
If policy_performed_unit = "days"
|
|
then past_time:= (day floor of order_significant_date)
|
|
- performed_duration;
|
|
else past_time:= order_significant_date - performed_duration;
|
|
endif; /* if policy_performed_unit = */
|
|
else
|
|
past_time:= exact_low_time;
|
|
endif; /* if policy_performed_time > 0...*/
|
|
|
|
/* Reset the time to NOW - EXACT MATCH time criteria, */
|
|
/* when past_time is less than now */
|
|
If past_time < now
|
|
then
|
|
visit_now := now AS Time visit_tz;
|
|
If policy_exact_unit = "days"
|
|
then past_time:= (day floor of visit_now ) - exact_duration ;
|
|
else past_time:= visit_now - exact_duration;
|
|
endif; /* If policy_exact_unit */
|
|
endif; /* If past_time < now */
|
|
|
|
/*-----------------------------------------*/
|
|
/* Converts SCHEDULED TIME into Arden Time */
|
|
/*-----------------------------------------*/
|
|
If policy_scheduled_time > 0 and policy_scheduled_unit is string
|
|
then
|
|
scheduled_duration:= call calc_duration with
|
|
(policy_scheduled_time, policy_scheduled_unit);
|
|
If policy_scheduled_unit = "days"
|
|
then future_time:= (day floor of order_significant_date)
|
|
+ scheduled_duration + (1 day) - (1 second);
|
|
else future_time:= order_significant_date + scheduled_duration;
|
|
endif; /* if policy_scheduled_unit = */
|
|
else
|
|
future_time:= exact_high_time;
|
|
endif; /* if policy_scheduled_time > 0...*/
|
|
|
|
/* Reset the time to NOW + EXACT MATCH time criteria, */
|
|
/* when future_time is less than now */
|
|
If future_time < now
|
|
then
|
|
visit_now := now AS Time visit_tz;
|
|
if policy_exact_unit = "days"
|
|
then
|
|
future_time:= (day floor of visit_now )
|
|
+ exact_duration + (1 day) - (1 second);
|
|
else
|
|
future_time:= visit_now + exact_duration;
|
|
endif; /* if policy_exact_unit ... */
|
|
endif; /* If future_time < now */
|
|
|
|
/*-----------------------------------------------------*/
|
|
/* Sets the SCOPE to retrieve orders from the database */
|
|
/*-----------------------------------------------------*/
|
|
If policy_scope = "This Chart"
|
|
then
|
|
ID_equals_patient_GUID := "CV3Order.ClientGUID = " || SQL(client_guid)
|
|
|| " AND CV3Order.ChartGUID = " || SQL(chart_guid);
|
|
elseif policy_scope = "This Visit"
|
|
then
|
|
ID_equals_patient_GUID := "CV3Order.ClientGUID = " || SQL(client_guid)
|
|
|| " AND CV3Order.ChartGUID = " || SQL(chart_guid)
|
|
|| " AND CV3Order.ClientVisitGUID = " || SQL(client_visit_guid);
|
|
else
|
|
ID_equals_patient_GUID := "CV3Order.ClientGUID = " || SQL(client_guid);
|
|
endif; /* policy_scope */
|
|
|
|
/*---------------------------------------------*/
|
|
/* Get the GUIDs of ALL the Unsubmitted Orders */
|
|
/*---------------------------------------------*/
|
|
/* So we do not retrieve them from the database */
|
|
(all_unsub_intended_action,
|
|
all_unsub_order_name_list,
|
|
all_unsub_order_guid_list) := read
|
|
{UnsubmittedOrders: IntendedAction, Name, GUID
|
|
WHERE GUID <> order_guid};
|
|
|
|
/*----------------------------------*/
|
|
/* Only get some UNSUBMITTED ORDERS */
|
|
/*----------------------------------*/
|
|
/* 1. They are New or Modifed unsubmitted orders */
|
|
/* 2. The check_for_unsubmitted_orders flag is true */
|
|
|
|
If check_for_unsubmitted_orders
|
|
then
|
|
(unsub_order_name_list,
|
|
unsub_order_guid_list,
|
|
unsub_significant_date_list,
|
|
unsub_sys_priority_list,
|
|
unsub_user_priority_list,
|
|
unsub_is_conditional_list,
|
|
unsub_is_suspended_list,
|
|
unsub_order_status_code_list,
|
|
unsub_order_status_level_list,
|
|
unsub_summary_list,
|
|
unsub_master_GUID_list ):= read
|
|
{UnsubmittedOrders: Name, GUID, SignificantDtm,
|
|
SystemOrderPriorityCode, OrderPriorityCode,
|
|
IsConditional, IsSuspended, OrderStatusCode,
|
|
OrderStatusLevelNum, SummaryLine, OrderCatalogMasterItemGUID
|
|
WHERE SignificantDtm >= past_time
|
|
AND SignificantDtm <= future_time
|
|
AND IsConditional = FALSE
|
|
AND IsPRN = FALSE
|
|
AND IsSuspended = FALSE
|
|
AND SystemOrderPriorityCode <> stat_code
|
|
AND OrderStatusLevelNum >= lowest_level
|
|
AND OrderStatusLevelNum <= highest_level
|
|
AND OrderStatusCode <> HOLD_code
|
|
AND RepeatOrder <> 1
|
|
AND GUID <> order_guid
|
|
AND (IntendedAction is NULL
|
|
OR IntendedAction is in ("Add New","Modify","Modified"))};
|
|
|
|
endif; /* if check_for_unsubmitted_orders */
|
|
|
|
/* Get ALL the UNSUBMITTED ORDERS */
|
|
|
|
|
|
/*------------------------------------------------------------------------------*/
|
|
/* Create a fragment of the SQL code that avoids retrieving the same orders */
|
|
/* from the database that are in the unsubmitted list. */
|
|
/* This is needed when the CDS Trigger is one of the order maintenance triggers */
|
|
/* and the user is performing a multi-order function */
|
|
/*------------------------------------------------------------------------------*/
|
|
|
|
/* Initialize variable to empty string */
|
|
AND_avoid_these_unsubmitted_order_guids := "";
|
|
|
|
/* Concatenate a fragment of the SQL code to the initalized variable */
|
|
if exist all_unsub_order_guid_list
|
|
then
|
|
if (count(all_unsub_order_guid_list) = 1)
|
|
then
|
|
//Set up to exclude this single order item
|
|
single_unsub_order_guid := last of (all_unsub_order_guid_list);
|
|
AND_avoid_these_unsubmitted_order_guids := AND_avoid_these_unsubmitted_order_guids
|
|
|| " AND (CV3Order.GUID <> " || SQL(single_unsub_order_guid)||")";
|
|
|
|
else
|
|
//Set up to exclude the these order guids
|
|
AND_avoid_these_unsubmitted_order_guids := AND_avoid_these_unsubmitted_order_guids
|
|
|| " AND (CV3Order.GUID NOT IN (" || SQL(all_unsub_order_guid_list)||"))";
|
|
endif;
|
|
else
|
|
AND_avoid_these_unsubmitted_order_guids :="";
|
|
endif;
|
|
|
|
/* Create 2 tables temporary result sets of potential orders within the range of maximum time zone difference */
|
|
/* These results will then be filtered by the datetime range based on the Duplicate Policy */
|
|
FROM_common_columns := " Name, CV3Order.GUID, "
|
|
|| " ConvSignificantDtm.TimeValue as SignificantDtmOffset, "
|
|
|| " SystemOrderPriorityCode, "
|
|
|| " OrderPriorityCode, IsConditional,IsSuspended, "
|
|
|| " OrderStatusCode, OrderStatusLevelNum, "
|
|
|| " SummaryLine, OrderCatalogMasterItemGUID "
|
|
|| " FROM CV3Order "
|
|
|| " INNER JOIN CV3ClientVisit v on v.GUID = CV3Order.ClientVisitGUID"
|
|
|| " CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(v.TimeZone, SignificantDtm) AS ConvSignificantDtm ";
|
|
|
|
max_hours_differece_between_time_zones := 26 as number;
|
|
WHERE_conditions_common := " WHERE " || ID_equals_patient_GUID
|
|
|| " AND CV3Order.SignificantDtm >= dateadd( hour, -" || SQLEX(max_hours_differece_between_time_zones)
|
|
|| ", " || SQL(past_time) || " )" // filter out potential orders based on unconverted datetime
|
|
|| " AND CV3Order.SignificantDtm <= dateadd( hour, " || SQLEX(max_hours_differece_between_time_zones)
|
|
|| ", " || SQL(future_time) || " )" // filter out potential orders based on unconverted datetime;
|
|
|| " AND CV3Order.OrderStatusLevelNum >= " || SQLEX(lowest_level)
|
|
|| " AND CV3Order.OrderStatusLevelNum <= " || SQLEX(highest_level)
|
|
|| " AND CV3Order.IsConditional = 0 "
|
|
|| " AND CV3Order.IsPRN = 0 "
|
|
|| " AND CV3Order.IsSuspended = 0 "
|
|
|| " AND CV3Order.Active = 1"
|
|
|| " AND CV3Order.SystemOrderPriorityCode <> " ||SQLEX(stat_code)
|
|
|| " AND CV3Order.RepeatOrder <> 1 "
|
|
|| " AND CV3Order.GUID <> " || SQLEX(order_guid)
|
|
|| " AND CV3Order.OrderStatusCode <> " || SQLEX(HOLD_code);
|
|
|
|
|
|
FROM_result_columns := " Name, GUID, SignificantDtmOffset, SystemOrderPriorityCode, OrderPriorityCode, IsConditional,IsSuspended, "
|
|
|| " OrderStatusCode, OrderStatusLevelNum, "
|
|
|| " SummaryLine, OrderCatalogMasterItemGUID ";
|
|
|
|
Filter_by_policy_datetime_range := " SignificantDtmOffset >= " || SQLEX(past_time)
|
|
|| " AND SignificantDtmOffset <= " || SQLEX(future_time);
|
|
|
|
/*----------------------------------*/
|
|
/* Gets the list of DATABASE ORDERS */
|
|
/*----------------------------------*/
|
|
(db_order_name_list,
|
|
db_order_guid_list,
|
|
db_significant_date_list,
|
|
db_sys_priority_list,
|
|
db_user_priority_list,
|
|
db_is_conditional_list,
|
|
db_is_suspended_list,
|
|
db_order_status_code_list,
|
|
db_order_status_level_list,
|
|
db_summary_list,
|
|
db_master_GUID_list ):= read
|
|
{ ";With CteAllOrders AS ( "
|
|
|| "SELECT " || FROM_common_columns
|
|
|| WHERE_conditions_common
|
|
|| " AND CV3Order.ComplexOrderType NOT IN (" || complex_master_order_type|| ")"
|
|
|| " ), "
|
|
|| " CteAllOrdersComp AS ( "
|
|
|| "SELECT DISTINCT " || FROM_common_columns
|
|
|| " INNER JOIN CV3OrderVariableComponent"
|
|
|| " ON CV3Order.GUID = CV3OrderVariableComponent.OrderGUID "
|
|
|| WHERE_conditions_common
|
|
|| AND_avoid_these_unsubmitted_order_guids
|
|
|| " AND CV3Order.ComplexOrderType IN (" || complex_master_order_type|| ")"
|
|
|| " AND ChildOrderGUID is NULL "
|
|
|| " ) "
|
|
|| "SELECT " || FROM_result_columns
|
|
|| " FROM CteAllOrdersComp"
|
|
|| " WHERE " || Filter_by_policy_datetime_range
|
|
|| " UNION "
|
|
|| "SELECT DISTINCT " || FROM_result_columns
|
|
|| " FROM CteAllOrders"
|
|
|| " WHERE " || Filter_by_policy_datetime_range
|
|
, PrimaryTime = SignificantDtmOffset};
|
|
|
|
endif; /* if any loc_group_found and not loc_is_excluded */
|
|
endif; /* if item_catalog_GUID is in venipuncture_catalog_GUID_list */
|
|
endif; /* If continue_checking_order */
|
|
;;
|
|
evoke: any_new_order
|
|
OR any_new_patient_group_order
|
|
OR any_modified_order
|
|
OR any_released_order
|
|
OR any_unsuspended_order
|
|
OR any_verified_order ;
|
|
;;
|
|
logic:
|
|
If item_catalog_GUID is NOT in venipuncture_catalog_GUID_list
|
|
OR NOT continue_checking_order
|
|
OR NOT (any loc_group_found)
|
|
OR loc_is_excluded
|
|
then conclude false;
|
|
endif;
|
|
|
|
/*-----------------------------------------------------------------*/
|
|
/* Concatenates information on "unsubmitted" and "database" orders */
|
|
/* and avoids concatenating NULL lists */
|
|
/*-----------------------------------------------------------------*/
|
|
If (exist unsub_master_guid_list) and (exist db_master_guid_list)
|
|
then
|
|
master_guid_list:= (unsub_master_guid_list, db_master_guid_list);
|
|
order_name_list:= (unsub_order_name_list, db_order_name_list);
|
|
significant_date_list:= (unsub_significant_date_list, db_significant_date_list);
|
|
sys_priority_list:= (unsub_sys_priority_list, db_sys_priority_list);
|
|
user_priority_list:= (unsub_user_priority_list, db_user_priority_list);
|
|
summary_list:= (unsub_summary_list, db_summary_list);
|
|
order_status_code_list:= (unsub_order_status_code_list, db_order_status_code_list);
|
|
order_guid_list := (unsub_order_guid_list,db_order_guid_list);
|
|
is_suspended_list := (unsub_is_suspended_list,db_is_suspended_list);
|
|
elseif (not exist unsub_master_guid_list) and (exist db_master_guid_list)
|
|
then
|
|
master_guid_list:= db_master_guid_list;
|
|
order_name_list:= db_order_name_list;
|
|
significant_date_list:= db_significant_date_list;
|
|
sys_priority_list:= db_sys_priority_list;
|
|
user_priority_list:= db_user_priority_list;
|
|
summary_list:= db_summary_list;
|
|
order_status_code_list:= db_order_status_code_list;
|
|
order_guid_list := db_order_guid_list;
|
|
is_suspended_list := db_is_suspended_list;
|
|
elseif (exist unsub_master_guid_list) and (not exist db_master_guid_list)
|
|
then
|
|
master_guid_list:= unsub_master_guid_list;
|
|
order_name_list:= unsub_order_name_list;
|
|
significant_date_list:= unsub_significant_date_list;
|
|
sys_priority_list:= unsub_sys_priority_list;
|
|
user_priority_list:= unsub_user_priority_list;
|
|
summary_list:= unsub_summary_list;
|
|
order_status_code_list:= unsub_order_status_code_list;
|
|
order_guid_list := unsub_order_guid_list;
|
|
is_suspended_list := unsub_is_suspended_list;
|
|
endif; /* If (exist unsub_master_guid_list)... */
|
|
|
|
/*-------------------------------------------------*/
|
|
/* Create List of Unsubmitted and Existing Strings */
|
|
/*-------------------------------------------------*/
|
|
action_item_status_list:= ();
|
|
for AA in unsub_order_name_list do
|
|
action_item_status_list := action_item_status_list, "Unsubmitted";
|
|
enddo; //for AA
|
|
|
|
for BB in db_order_name_list do
|
|
action_item_status_list := action_item_status_list, "Existing";
|
|
enddo; //for BB
|
|
|
|
|
|
/*-----------------------*/
|
|
/* Initializes Variables */
|
|
/*-----------------------*/
|
|
matching_master_guid_list:= ();
|
|
matching_name_list:= ();
|
|
matching_significant_date_list:= ();
|
|
matching_sys_priority_list:= ();
|
|
matching_user_priority_list:= ();
|
|
matching_summary_list:= ();
|
|
matching_order_status_code:= ();
|
|
matching_order_guid_list:= ();
|
|
matching_is_suspended_list:= ();
|
|
matching_action_item_status_list := ();
|
|
already_consolidated:= false;
|
|
|
|
/*------------------------------------------------*/
|
|
/* Finds all possible venipuncture consolidations */
|
|
/*------------------------------------------------*/
|
|
If any(venipuncture_catalog_GUID_list is in master_guid_list)
|
|
then
|
|
for item_master_guid in venipuncture_catalog_GUID_list do
|
|
master_guid_found:= item_master_guid = master_guid_list;
|
|
temp_sys_priority:= sys_priority_list where master_guid_found;
|
|
temp_user_priority:= user_priority_list where master_guid_found;
|
|
temp_guid:= master_guid_list where master_guid_found;
|
|
temp_name:= order_name_list where master_guid_found;
|
|
temp_signif:= significant_date_list where master_guid_found;
|
|
temp_summary:= summary_list where master_guid_found;
|
|
temp_status:= order_status_code_list where master_guid_found;
|
|
temp_order_guid:= order_guid_list where master_guid_found;
|
|
temp_is_suspended := is_suspended_list where master_guid_found;
|
|
temp_action_status := action_item_status_list where master_guid_found;
|
|
matching_sys_priority_list:= matching_sys_priority_list, temp_sys_priority;
|
|
matching_user_priority_list:= matching_user_priority_list, temp_user_priority;
|
|
matching_master_guid_list:= matching_master_guid_list, temp_guid;
|
|
matching_name_list:= matching_name_list, temp_name;
|
|
matching_significant_date_list:= matching_significant_date_list, temp_signif;
|
|
matching_summary_list:= matching_summary_list, temp_summary;
|
|
matching_order_status_code:= matching_order_status_code, temp_status;
|
|
matching_order_guid_list:= matching_order_guid_list, temp_order_guid;
|
|
matching_is_suspended_list:= matching_is_suspended_list, temp_is_suspended;
|
|
matching_action_item_status_list:=
|
|
matching_action_item_status_list, temp_action_status;
|
|
enddo; /* for item_master_guid...*/
|
|
|
|
|
|
/* If there is another order within the exact-match time interval */
|
|
/* that requires a venipuncture, */
|
|
/* then the current order{{{SINGLE-QUOTE}}}s blood collection time does not have be be changed */
|
|
/* and there is no need for an venipunture consolidation alert */
|
|
if any(matching_significant_date_list>= exact_low_time
|
|
AND matching_significant_date_list <= exact_high_time)
|
|
then
|
|
already_consolidated:= true;
|
|
else
|
|
/* Removes TIMEC orders, only keeps RTN orders */
|
|
If order_sys_priority = time_critical_code
|
|
AND (time_critical_code is in matching_sys_priority_list)
|
|
then
|
|
RTN_found:= matching_sys_priority_list = routine_code;
|
|
matching_sys_priority_list:= matching_sys_priority_list where RTN_found;
|
|
matching_user_priority_list:= matching_user_priority_list where RTN_found;
|
|
matching_master_guid_list:= matching_master_guid_list where RTN_found;
|
|
matching_name_list:= matching_name_list where RTN_found;
|
|
matching_significant_date_list:=
|
|
matching_significant_date_list where RTN_found;
|
|
matching_summary_list:= matching_summary_list where RTN_found;
|
|
matching_order_status_code:= matching_order_status_code where RTN_found;
|
|
matching_order_guid_list:= matching_order_guid_list where RTN_found;
|
|
matching_is_suspended_list:= matching_is_suspended_list where RTN_found;
|
|
matching_action_item_status_list:=
|
|
matching_action_item_status_list where RTN_found;
|
|
endif; /* if order_sys_priority */
|
|
endif; /* if any(matching_significant_date_list>= exact_low_time */
|
|
endif; /* if any(venipuncture_catalog_GUID_list...*/
|
|
|
|
|
|
/*----------------------*/
|
|
/* Format Alert Message */
|
|
/*----------------------*/
|
|
if NOT already_consolidated
|
|
then
|
|
matching_short_message_list := ();
|
|
alert_message:= "";
|
|
order_index:= 1 seqto count(matching_name_list);
|
|
|
|
for I in order_index do
|
|
index_found:= I = order_index;
|
|
temp_name:= first(matching_name_list where index_found);
|
|
temp_signif:= first(matching_significant_date_list where index_found);
|
|
temp_sys_priority:= first(matching_sys_priority_list where index_found);
|
|
temp_user_priority:= first(matching_user_priority_list where index_found);
|
|
|
|
/* Format dates, removing milliseconds */
|
|
If exist temp_signif then
|
|
temp_signif_formatted := temp_signif formatted with "%.4t";
|
|
endif;
|
|
If exist order_significant_date then
|
|
temp_order_significant_date_formatted :=
|
|
order_significant_date formatted with "%.4t";
|
|
endif;
|
|
|
|
first_sentence:= "A " || temp_user_priority
|
|
|| " blood collection for this patient is currently scheduled at "
|
|
|| temp_signif_formatted || " for " || temp_name ||".";
|
|
|
|
If order_sys_priority = routine_code
|
|
AND temp_sys_priority = routine_code
|
|
then
|
|
temp_msg_list:= first_sentence
|
|
|| " Consider consolidating one of the collection times to"
|
|
|| " the other collection time";
|
|
elseif order_sys_priority = time_critical_code
|
|
AND temp_sys_priority = routine_code
|
|
then
|
|
temp_msg_list:= first_sentence
|
|
|| " Consider consolidating the collection time of the "
|
|
|| temp_user_priority || " order "
|
|
|| "to the collection time of the " || order_user_priority
|
|
||" order";
|
|
elseif order_sys_priority = routine_code
|
|
AND temp_sys_priority = time_critical_code
|
|
then
|
|
temp_msg_list:= first_sentence
|
|
|| " Consider consolidating the collection time of the "
|
|
|| order_user_priority || " order "
|
|
|| "to the collection time of the " || temp_user_priority
|
|
||" order.";
|
|
endif; /* if order_sys_priority... */
|
|
|
|
/* Append or Concatenate alert messages */
|
|
matching_short_message_list:= matching_short_message_list, temp_msg_list;
|
|
alert_message := alert_message ||temp_msg_list || "\n\n";
|
|
enddo; /* for I */
|
|
endif; /* if NOT already_consolidated */
|
|
|
|
/*------------------------------*/
|
|
/* Create the Actions on Alerts */
|
|
/*------------------------------*/
|
|
// Only create actions for alerts when the flag, generate_actions_on_alerts, is TRUE
|
|
// And there are alerts
|
|
// And the EvokingEventType is a new order or the MLM is running the the MLM Editor
|
|
|
|
If generate_actions_on_alerts
|
|
and exist matching_name_list
|
|
and NOT already_consolidated
|
|
and (EvokingEventType = any_new_order.type
|
|
OR EvokingEventType = any_new_patient_group_order.type
|
|
OR EvokingEventType = "OrderEnterNoIVAdditives"
|
|
OR EvokingEventType = "OrderEnterWithIVAdditives"
|
|
or Called_By_Editor)
|
|
then
|
|
|
|
|
|
/* Call the MLM to create and populate actions */
|
|
alert_action_list := call func_venipuncture_actions WITH
|
|
order_guid,
|
|
matching_action_item_status_list,
|
|
matching_order_guid_list,
|
|
matching_name_list,
|
|
matching_master_guid_list,
|
|
matching_short_message_list,
|
|
matching_is_suspended_list ;
|
|
|
|
if exist alert_action_list
|
|
then alert_actions_exist := true;
|
|
else alert_actions_exist := false;
|
|
endif; //if exist alert_action_list
|
|
|
|
endif; //generate_actions_on_alerts
|
|
|
|
|
|
|
|
/*---------------*/
|
|
/* Clinical Rule */
|
|
/*---------------*/
|
|
If exist matching_name_list
|
|
and NOT already_consolidated
|
|
then conclude true;
|
|
endif;
|
|
;;
|
|
action:
|
|
Write "Current Order: " ||order_user_priority || " " || order_name || "---"
|
|
|| temp_order_significant_date_formatted || "\n\n"
|
|
|| alert_message
|
|
at venipuncture_alert;
|
|
|
|
/* Only attach actions, when they exist */
|
|
if alert_actions_exist
|
|
then
|
|
attach alert_action_list to venipuncture_alert;
|
|
endif; //if generate_actions_on_alerts
|
|
;;
|
|
Urgency: 50;;
|
|
end:
|