Initial Checking with all 820 MLMs

This commit is contained in:
2020-02-02 00:54:01 -05:00
parent c59dc6de2e
commit 840d0432f4
828 changed files with 239162 additions and 0 deletions

View File

@@ -0,0 +1,657 @@
maintenance:
title: Rules for Advanced Duplicate Order Checking;;
mlmname: STD_FUNC_DUP_RULES;;
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: Process the orders according to the rules stated in std_duplicate.mlm.
Returns information on the duplicate orders to std_duplicate.mlm.
;;
explanation: See the explanation in std_duplicate.mlm
;;
keywords: Duplicate Order;
;;
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;
/********************************************************************************/
/* Only Change these Internal Representations when the C++ code changes */
canc_code:= "CANC";
canp_code:= "CANP";
cand_code:= "CAND";
cant_code:= "CANT";
compa_code:= "COMPA";
disc_code:= "DISC";
discd_code:= "DISCD";
disct_code:= "DISCT";
hold_code:= "HOLD";
hisi_code:= "HISI";
hise_code:= "HISE";
/* Do Not Change these Internal MLM Variables */
exact_msg:= "exact";
performed_msg:= "performed";
scheduled_msg:= "scheduled";
exact_type:= "exact";
subset_type:= "subset";
superset_type:= "superset";
same_order_type:= "same order type";
partial_match_type:= "partial match";
conflict_type:= "conflict";
possible_conflict_type:= "possible conflict";
no_std_message_type:= "no std message";
/* IV-Additive TYPES are used to store additives in CV3OrderComponent.Type */
/* If more than two IV-additive types are used, add them to this list */
/* Note: Type 3 was used for calculated IV-dosage in CV3.1.2, */
/* but is not used in SCM 3.0 or SCM 3.01 */
iv_additive_type_list:= 0, 3 ;
check_medication_like_orders := false;
(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_requested_date,
order_entered_date,
order_stop_date,
order_is_conditional,
patient_loc_group,
lowest_status_level_for_diagnostics,
highest_status_level_for_diagnostics,
lowest_status_level_for_meds,
highest_status_level_for_meds,
complex_master_order_type,
complex_child_order_type,
order_is_for_discharge,
order_alternate_order_type,
order_is_script,
at_in_house_session_list,
at_discharge_session_list,
at_historical_session_list,
at_outpatient_session_list,
enable_community_data_results_alerts,
enable_Diagnostic_Duplicate_Check_by_Community_Order_Name,
evoking_object,
evoking_object_type):= ARGUMENT;
/* Declares MLMs which can be called */
calc_duration:= MLM {{{SINGLE-QUOTE}}}std_func_dup_duration{{{SINGLE-QUOTE}}};
get_orders:= MLM {{{SINGLE-QUOTE}}}std_func_dup_retrieve_orders{{{SINGLE-QUOTE}}};
/* Gets the Client GUID */
client_guid := read last {ClientInfo: GUID};
/* Gets the evoking order{{{SINGLE-QUOTE}}}s Item-Catalog name, Policy guid and IsOngoingOrder */
/* which indicates if this is a medication like order or diagnostic like order */
/* IsOngoingOrder = False means this is a medication like order */
/* IsOngoingOrder = True means this is a diagnostic like order */
(catalog_name,
duplicate_policy_guid,
order_without_specific_stop_date ) := read last
{"SELECT Name, DuplicatePolicyGUID, IsOngoingOrder "
|| " FROM CV3OrderCatalogMasterItem "
|| " WHERE GUID = " || SQL(item_catalog_guid)
|| " AND Active = 1 "};
if (order_alternate_order_type = 2) //if an outpatient order
then
order_without_specific_stop_date := false;
endif;
/* Continue if "check for duplicates" is marked in the Item-Catalog */
If exist duplicate_policy_guid
then
/* Gets evoking order{{{SINGLE-QUOTE}}}s duplicate policy information */
(order_loc_group_guid_list,
order_scope_list,
order_performed_time_list,
order_performed_unit_list,
order_exact_time_list,
order_exact_unit_list,
order_scheduled_time_list,
order_scheduled_unit_list,
loc_is_excluded_list) := read
{"SELECT LocationGroupGUID, SearchScope, PastTime, PastTimeUnits,"
|| " ExactTime, ExactTimeUnits, FutureTime, FutureTimeUnits, IsExcluded"
|| " FROM CV3OrderDuplicatePolicyDtl "
|| " WHERE OrderDuplicatePolicyGUID = " || SQL(duplicate_policy_guid)
|| " AND LocationGroupGUID IN (0, " || SQL(patient_loc_group)|| " )"
|| " AND 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 order_scope_list
then
If any (patient_loc_group = order_loc_group_guid_list)
then
loc_group_found := patient_loc_group = order_loc_group_guid_list;
else
loc_group_found := order_loc_group_guid_list is null;
endif;
loc_is_excluded := last (loc_is_excluded_list where loc_group_found);
endif; /* if exist order_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 */
/*--------------------------------------------------*/
order_loc_grp:= last (order_loc_group_guid_list where loc_group_found);
order_scope:= last (order_scope_list where loc_group_found);
order_performed_time:= last (order_performed_time_list where loc_group_found);
order_performed_unit:= last (order_performed_unit_list where loc_group_found);
order_exact_time:= last (order_exact_time_list where loc_group_found);
order_exact_unit:= last (order_exact_unit_list where loc_group_found);
order_scheduled_time:= last (order_scheduled_time_list where loc_group_found);
order_scheduled_unit:= last (order_scheduled_unit_list where loc_group_found);
/*-----------------------------------*/
/* Sets check_medication_like_orders */
/*-----------------------------------*/
If NOT order_without_specific_stop_date
then
check_medication_like_orders:= true;
endif; /* If NOT order_without_specific_stop_date */
/*-------------------------------------*/
/* Converts EXACT TIME into Arden Time */
/*-------------------------------------*/
If order_exact_time > 0 and order_exact_unit is string
then
exact_duration:= call calc_duration with
(order_exact_time, order_exact_unit);
If order_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 order_exact_unit = */
else
exact_low_time:= order_significant_date;
exact_high_time:= order_significant_date;
endif; /* if order_exact_time > 0 ...*/
/*-----------------------------------------*/
/* Converts PERFORMED TIME into Arden Time */
/*-----------------------------------------*/
If order_performed_time > 0 and order_performed_unit is string
then
performed_duration:= call calc_duration with
(order_performed_time, order_performed_unit);
If order_performed_unit = "days"
then past_time:= (day floor of order_significant_date)
- performed_duration;
else past_time:= order_significant_date - performed_duration;
endif; /* if order_performed_unit = */
else
past_time:= exact_low_time;
endif; /* if order_performed_time > 0 ...*/
/*-----------------------------------------*/
/* Converts SCHEDULED TIME into Arden Time */
/*-----------------------------------------*/
If order_scheduled_time > 0 and order_scheduled_unit is string
then
scheduled_duration:= call calc_duration with
(order_scheduled_time, order_scheduled_unit);
If order_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 order_scheduled_unit = */
else
future_time:= exact_high_time;
endif; /* if order_scheduled_time > 0 ...*/
/*********************************************/
/* Retrieve ITEMS and CLASSES for Duplicates */
/*********************************************/
/* Gets the evoking order{{{SINGLE-QUOTE}}}s list of duplicates (ITEMS and CLASSES) */
/* from the Item-Catalog */
(cat_dup_item_name_list,
cat_dup_item_guid_list,
cat_class_name_list,
cat_class_value_list,
cat_message_type_list,
cat_message_list) := read
{"SELECT DuplicateItemName, DuplicateItemGUID, ClassTypeCode, "
|| " ClassValue, MessageType, MessageText "
|| " FROM CV3CatalogItemDuplicate "
|| " WHERE OrderCatalogMasterItemGUID = " || SQL(item_catalog_guid)
|| " AND Active = 1 "};
/* If there are any classes associated with the order */
/* then get the GUIDs of the items */
If exist cat_class_value_list
then
SQL_string := "";
index_list_jj := 1 seqto count (cat_class_value_list);
for JJ in index_list_jj do
single_class_value := cat_class_value_list[JJ];
single_class_type:= cat_class_name_list[JJ];
If exist single_class_value
and exist single_class_type
then
/* Create the SQL fragment of ClassTypeCode and ClassValue */
/* to retrieve data from CV3CatalogItemDuplicate table */
if SQL_string = ""
then
SQL_string := SQL_string
|| "( ClassTypeCode = " || SQL(single_class_type)
|| " AND ClassValue = " || SQL(single_class_value) || ")";
else
SQL_string := SQL_string
|| " OR ( ClassTypeCode = " || SQL(single_class_type)
|| " AND ClassValue = " || SQL(single_class_value) || ")";
endif;
endif; /* if exist single_class_value */
enddo; // for JJ
/* Initialize variables */
other_class_message_type_list := ();
other_class_message_list := ();
/* Get the Other OrderCatalogMasterItemGUIDs and their Class Information */
(other_class_guid_list,
other_class_type_list,
other_class_value_list ) := read
{"SELECT OrderCatalogMasterItemGUID, "
|| " ClassTypeCode, ClassValue "
|| " FROM CV3CatalogItemDuplicate "
|| " WHERE (" || SQL_string || ")"
|| " AND OrderCatalogMasterItemGUID <> "
|| SQL(item_catalog_guid)
|| " ORDER BY OrderCatalogMasterItemGUID " };
// Find the MessageType and MessageText that go with the
// ClassTypeCode and ClassValue and add them to the appropriate lists
if exist other_class_type_list
and exist other_class_value_list
then
index_list_kk := 1 seqto count (other_class_type_list);
for KK in index_list_kk do
temp_class_type := other_class_type_list[KK];
temp_class_value := other_class_value_list[KK];
found_class_info :=
(cat_class_name_list = temp_class_type)
and (cat_class_value_list = temp_class_value);
temp_message_type :=
first (cat_message_type_list where found_class_info);
temp_message :=
first (cat_message_list where found_class_info);
other_class_message_type_list:=
other_class_message_type_list, temp_message_type ;
other_class_message_list:=
other_class_message_list, temp_message ;
enddo; //for KK
endif;
endif; /* if exist cat_class_value_list */
/*-----------------------------------------------------------------------*/
/* Retrieve the orders from the DATABASE and the UNSUBMITTED orders list */
/* AND Get Data for ACTIONS ON ALERTS (aoa_) */
/*-----------------------------------------------------------------------*/
(order_name_list,
order_guid_list,
significant_date_list,
requested_date_list,
entered_date_list,
stop_date_list,
is_conditional_list,
is_suspended_list,
order_status_code_list,
order_status_level_list,
order_type_code_list,
order_alternate_type_list,
order_is_script_list,
summary_list,
master_GUID_list,
aoa_action_item_status_list,
aoa_order_name_list,
aoa_master_guid_list) := call get_orders with
(client_guid,
chart_guid,
client_visit_guid,
order_guid,
order_name,
order_is_conditional,
order_scope,
past_time,
future_time,
check_medication_like_orders,
lowest_status_level_for_diagnostics,
highest_status_level_for_diagnostics,
lowest_status_level_for_meds,
highest_status_level_for_meds,
hold_code,
canc_code,
canp_code,
cand_code,
cant_code,
compa_code,
disc_code,
discd_code,
disct_code,
hisi_code,
hise_code,
iv_additive_type_list,
complex_master_order_type,
complex_child_order_type,
order_is_for_discharge,
order_alternate_order_type,
order_is_script,
at_in_house_session_list,
at_discharge_session_list,
at_historical_session_list,
at_outpatient_session_list,
enable_community_data_results_alerts,
enable_Diagnostic_Duplicate_Check_by_Community_Order_Name,
evoking_object,
evoking_object_type);
endif; /* if any loc_group_found and not loc_is_excluded */
endif; /* if exist duplicate_policy_guid */
;;
evoke:
;;
logic:
If NOT exist duplicate_policy_guid
OR NOT (any loc_group_found)
OR loc_is_excluded
then conclude false;
endif;
/*-----------------------*/
/* Initializes Variables */
/*-----------------------*/
matching_guid_list:= ();
matching_name_list:= ();
matching_order_guid_list:= ();
matching_significant_date_list := ();
matching_requested_date_list := ();
matching_entered_date_list := ();
matching_stop_date_list:= ();
matching_msg_type_list:= ();
matching_msg_text_list:= ();
matching_time_msg_list:= ();
matching_summary_list:= ();
matching_class_list:= ();
matching_order_status_code_list:= ();
matching_order_type_code_list:= ();
matching_alternate_order_type_list := ();
matching_is_script_list := ();
dup_item_guid_list:= cat_dup_item_guid_list;
class_name_list:= cat_class_name_list;
class_value_list:= cat_class_value_list;
message_type_list:= cat_message_type_list;
message_list:= cat_message_list;
/*-------------------------------------------------------------------*/
/* Adds extra information to DUP_ITEM_GUID_LIST and associated lists */
/*-------------------------------------------------------------------*/
/* Adds the evoking object{{{SINGLE-QUOTE}}}s OrderCatalogMasterItemGUID and other data, */
/* if the list of items from item-catalog--duplicate checking panel does not include it */
If (item_catalog_guid is not in dup_item_guid_list)
and (item_catalog_guid is in master_guid_list)
then
dup_item_guid_list:= item_catalog_guid, dup_item_guid_list;
class_name_list:= null, class_name_list;
class_value_list:= null, class_value_list;
message_type_list:= exact_type, message_type_list;
message_list:= null, message_list;
endif; /* if item_catalog_guid is not in... */
/* Adds other OrderCatalogMasterItemGUIDs and other data, based on CLASS matches */
If exist other_class_guid_list
then
dup_item_guid_list:= dup_item_guid_list, other_class_guid_list;
class_name_list:= class_name_list, other_class_type_list;
class_value_list:= class_value_list, other_class_value_list;
message_type_list:= message_type_list, other_class_message_type_list;
message_list:= message_list, other_class_message_list;
endif; /* if exist other_class_guid_list */
/*---------------------------------------------------------------*/
/* Finds all possible duplicates among the ITEMS and the CLASSES */
/*---------------------------------------------------------------*/
If any(dup_item_guid_list is in master_guid_list)
then
index_list_nn := 1 seqto count (dup_item_guid_list);
for NN in index_list_nn do
item_master_guid := dup_item_guid_list[NN];
if exist item_master_guid
then
/* Create most of the matching lists */
master_guid_found:= item_master_guid = master_guid_list;
temp_guid:= master_guid_list where master_guid_found;
temp_name:= order_name_list where master_guid_found;
temp_order_guid:= order_guid_list where master_guid_found;
temp_signif:= significant_date_list where master_guid_found;
temp_requested := requested_date_list where master_guid_found;
temp_entered := entered_date_list where master_guid_found;
temp_stop:= stop_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_type_code:= order_type_code_list where master_guid_found;
temp_alternate_order_type := order_alternate_type_list where master_guid_found;
temp_is_script := order_is_script_list where master_guid_found;
matching_guid_list:= matching_guid_list, temp_guid;
matching_name_list:= matching_name_list, temp_name;
matching_order_guid_list:= matching_order_guid_list, temp_order_guid;
matching_significant_date_list := matching_significant_date_list, temp_signif;
matching_requested_date_list := matching_requested_date_list, temp_requested;
matching_entered_date_list := matching_entered_date_list, temp_entered;
matching_stop_date_list:= matching_stop_date_list, temp_stop;
matching_summary_list:= matching_summary_list, temp_summary;
matching_order_status_code_list:= matching_order_status_code_list, temp_status;
matching_order_type_code_list:= matching_order_type_code_list, temp_type_code;
matching_alternate_order_type_list := matching_alternate_order_type_list, temp_alternate_order_type;
matching_is_script_list := matching_is_script_list, temp_is_script;
/* Get the associated message type and message text */
temp_msg_type:= message_type_list[NN];
temp_msg_text:= message_list [NN];
temp_class_value:= class_value_list[NN];
For one_cat_guid in temp_guid do
/* Attach associated message type and message text to their matching lists */
matching_msg_type_list:= matching_msg_type_list, temp_msg_type;
matching_msg_text_list:= matching_msg_text_list, temp_msg_text;
matching_class_list:= matching_class_list, temp_class_value;
/* Set the time messages */
order_time:= time of one_cat_guid;
relative_date:= now;
If order_time >= exact_low_time AND order_time <= exact_high_time
then correct_msg:= exact_msg;
elseif order_time < relative_date
then correct_msg:= performed_msg;
elseif order_time > relative_date
then correct_msg:= scheduled_msg;
else correct_msg:= null;
endif; /* if order_time */
matching_time_msg_list:= matching_time_msg_list, correct_msg;
enddo; // For one_cat_guid
endif; //if exist item_master_guid
enddo; // for NN
endif; /* if any(dup_item_guid_list...*/
/*----------------------------------------------*/
/* Determines if the order is being checked for */
/* CONFLICTING ORDERS or WASTING RESOURCES */
/*----------------------------------------------*/
/* If it is for Conflicting Orders (check_medication_like_orders = true), */
/* then look for overlapping dates */
/* Otherwise all matched orders are considered duplicates */
has_overlapping_dates_list:= ();
If check_medication_like_orders and (exist matching_significant_date_list)
then
index_list:= 1 seqto(count matching_significant_date_list);
for D in index_list do
index_found:= index_list = D;
prior_significant_date:= first (matching_significant_date_list where index_found);
prior_stop_date:= first (matching_stop_date_list where index_found);
/* There are only two conditions when an order with "significant" */
/* and "stop" dates is not considered a duplicate. */
/* If one of these conditions occurs, then then a duplicate flag */
/* is set to false */
If (prior_stop_date is time
and order_significant_date > prior_stop_date)
OR
(order_stop_date is time
and order_stop_date < prior_significant_date)
then
has_overlapping_dates_list:= has_overlapping_dates_list, FALSE;
else
has_overlapping_dates_list:= has_overlapping_dates_list, TRUE;
endif; /* if prior_stop_date... */
enddo; /* for D in index_list */
/* Removes orders that do not have over-lapping dates */
if exist has_overlapping_dates_list
then
overlaps_found:= has_overlapping_dates_list = true;
matching_guid_list:= matching_guid_list where overlaps_found;
matching_name_list:= matching_name_list where overlaps_found;
matching_order_guid_list:= matching_order_guid_list where overlaps_found;
matching_significant_date_list := matching_significant_date_list where overlaps_found;
matching_requested_date_list := matching_requested_date_list where overlaps_found;
matching_entered_date_list := matching_entered_date_list where overlaps_found;
matching_stop_date_list:= matching_stop_date_list where overlaps_found;
matching_msg_type_list:= matching_msg_type_list where overlaps_found;
matching_msg_text_list:= matching_msg_text_list where overlaps_found;
matching_time_msg_list:= matching_time_msg_list where overlaps_found;
matching_summary_list:= matching_summary_list where overlaps_found;
matching_order_status_code_list:=
matching_order_status_code_list where overlaps_found;
matching_order_type_code_list:=
matching_order_type_code_list where overlaps_found;
matching_alternate_order_type_list := matching_alternate_order_type_list where overlaps_found;
matching_is_script_list := matching_is_script_list where overlaps_found;
endif; /* if any has_overlapping_dates_list */
endif;
/*--------------------------------------------------------------*/
/* Finds the Matching Data Needed for Action on Alerts */
/*--------------------------------------------------------------*/
// This assumes that the lists for order_name_list, order_GUID_list, master_GUID_list
// and aoa_action_item_status_list are parallel lists of equal length.
// It creates a list of Matching ACTION ITEM STATUSES that are associated
// with the Matching_Name_List and the Master_GUID_List.
// Create a list of boolean values that indicates the positions that
// have a matching GUID and NAME.
found_matching_guid_and_name := (master_guid_list is in matching_GUID_list)
and (order_name_list is in matching_name_list);
// Extract a sublist of Matching Action Item Statuses.
matching_aoa_action_item_status_list := aoa_action_item_status_list
where found_matching_guid_and_name;
// Extract a sublist of Matching CV3OrderGUIDs
matching_aoa_order_guid_list := order_guid_list
where found_matching_guid_and_name;
// Create a list of Matching Order Names (ie. unsubstituted with
// order components when there are IV Additives).
matching_aoa_order_name_list := aoa_order_name_list
where found_matching_guid_and_name;
// Create a list of Matching CV3OrderCatalogMasterItemGUIDs
// (ie. unsubstituted with order components when there are IV Additives).
matching_aoa_master_guid_list := aoa_master_guid_list
where found_matching_guid_and_name;
/*--------------------------------------------------*/
/* Concludes True To Return Data To The Calling MLM */
/*--------------------------------------------------*/
conclude true;
;;
action:
return( exact_msg,
performed_msg,
scheduled_msg,
exact_type,
subset_type,
superset_type,
same_order_type,
partial_match_type,
conflict_type,
possible_conflict_type,
no_std_message_type,
order_without_specific_stop_date,
matching_name_list,
matching_order_guid_list,
matching_significant_date_list,
matching_requested_date_list,
matching_entered_date_list,
matching_stop_date_list,
matching_msg_type_list,
matching_msg_text_list,
matching_time_msg_list,
matching_class_list,
matching_summary_list,
matching_order_status_code_list,
matching_order_type_code_list,
matching_alternate_order_type_list,
matching_is_script_list,
matching_aoa_action_item_status_list,
matching_aoa_order_guid_list,
matching_aoa_order_name_list,
matching_aoa_master_guid_list
);
;;
end: