maintenance: title: Duplicate Task Occurrence Checking;; mlmname: STD_DUPLICATE_TASK;; 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: Provide Duplicate Task Occurrence Checking. The checking will include: 1. Tasks of the same name or type within a pre-defined date range, which will be varied by patient location. 2. Active task of the same type/class. ;; explanation: Evoking-Occurrence: This is the Order Task Occurrence that causes the MLM to be triggered (evoked). DB-Occurrence: This is an existing Order Task Occurrence from the database or from the cached memory. An Evoking-Occurrence is considered a duplicate of a DB-Occurrence when all of the criteria listed below are true: 1. The Evoking-Occurrence is created by the Order Generation Server, and by a user when marking a task as done at order entry, or adding a completed task, or adding a scheduled task to the worklist, or rescheduling a single instance of a task. 2. The Evoking-Occurrence is a New occurrence, a Modified occurrence, or a Rescheduled occurrence. 3. If the Evoking-Occurrence is a Modified occurrence, only an occurrence with changes to ScheduledDtm, EarliestScheduledDtm, or LatestScheduledDtm will be checked for duplicates. 4. The Evoking-Occurrence must have a CV3OrderTaskOccurrence.CDSOccurrenceType of {10, 11, 20, 30, 31, 40, 41, 90, 91, 110, 111, 120, 130, 131, 140, 141} or is a task that was rescheduled from Clinical Manager to be checked for duplicates. See the Duplicate Task Checking chapter of the CDS Configuration Guide for a detailed definition of each number. 5. The Evoking-Occurrence must have a CV3OrderTaskOccurrence.TaskStatusCode of {Pending, Rescheduled, Overdue}. 6. The Evoking-Occurrence must have a CV3OrderTask.ScheduleTypeCode of {Scheduled, Unscheduled, PRN, To Schedule (when 1st given), Continuous}. The Evoking-Occurrence with a ScheduleTypeCode of {To Schedule (manual), Conditional } will be excluded. 7. The Evoking-Occurrence is not excluded from duplicate checking (over-all or by patient location) in its Duplicate Policy. 8. The DB-Occurrence must have a CV3OrderTaskOccurrence.TaskStatusCode of { Overdue, Pending, Performed, Rescheduled }. DB-Occurrences that have TaskStatusCodes of Canceled or Not Done will be excluded. 9. The DB-Occurrence must have a CV3OrderTask.ScheduleTypeCode of {Scheduled, Unscheduled, PRN, To Schedule (manual), To Schedule (when 1st given), Continuous} or a CV3OrderTaskOccurrence.TaskStatusCode of Performed, except in the case of {{{SINGLE-QUOTE}}}Adding a Completed Task{{{SINGLE-QUOTE}}} on the worklist. DB-Occurrences with a ScheduleTypeCode of Conditional will be excluded. 10. When the Evoking-Occurrence has a ScheduleTypeCode of Continuous, it cannot be a duplicate of DB-Occurrences that are from the same order task (OrderTaskGUID). 11. The Evoking-Occurrence and the DB-Occurrence have identical Item-Catalog names, or the DB-Occurrence match the Item or Class-Name & Value listed in the Evoking-Occurrence{{{SINGLE-QUOTE}}}s item-catalog-tasks panel. 12. The DB-Occurrences are within the scoping rules for the patient location listed in the Evoking-Occurrence{{{SINGLE-QUOTE}}}s Duplicate Policy. 13. The Evoking-Occurrence and the DB-Occurrence have overlapping start and stop dates within the time interval specified in the Evoking-Occurrence{{{SINGLE-QUOTE}}}s Duplicate Policy. See the CDS Configuration and Standard MLM Set up Guide, for a detailed definition of overlapping start and stop dates in the "Setting up Duplicate Task Checking" chapter. 14. If the Duplicate Policy uses Task % and the MLM is unable to determine a time interval for the Evoking-Occurrence, a default time interval of 24 hours (12 hours before and after the date/time of when the Evoking-Occurrence should be done) will be used to screen for potential duplicate tasks. If a potential duplicate exists, an error alert would be generated, unless the facility has turned off the error flag. The error alert would state that the user should review the task because all the required information is not present to identify duplicate task occurrences. 15. The combination of a Scheduled Evoking-Occurrence and a Performed DB-Occurrence is considered a HIGH priority alert. All other combinations are considered a MEDIUM priority alert. 16. To prevent over alerting, an alert will NOT be generated for the same Order Task, if there is a higher priority or equivalent priority alert for one of the Order Task{{{SINGLE-QUOTE}}}s earlier DB-Occurrences. ;; keywords: Duplicate Task Occurrence; ;; 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; /* Change the message within the quotes if a different short-message is needed.*/ high_dup_task_alert:= destination { Alert: warning, "Duplicate Task", high, chart, "HVC Duplicate Task", 2005 }; medium_dup_task_alert:= destination { Alert: warning, "Duplicate Task", medium, chart, "HVC Duplicate Task", 2005 }; /* Change the spelling within the quotes to match the order item-catalog.*/ any_new_task:= event {OrderTaskOccurrenceEnter Any OrderTaskOccurrence: WHERE TaskStatusCode is in ("Pending", "Rescheduled", "Overdue" ) AND CDSOccurrenceType is in (10,11,20,30,31,40,41,90,91,110,111,120,130,131,140,141) OR (TaskStatusCode is in ("Performed" ) AND CDSOccurrenceType = 91)}; any_modified_task:= event {OrderTaskOccurrenceModify Any OrderTaskOccurrence: WHERE TaskStatusCode is in ("Pending", "Rescheduled", "Overdue" ) AND CDSOccurrenceType is in (10,11,20,30,31,40,41,90,91,110,111,120,130,131,140,141)}; any_rescheduled_task_instance:= event {OrderTaskOccurrenceReschedule User OrderTaskOccurrence: WHERE TaskStatusCode is in ("Rescheduled")}; /* A flag to determine if the clinical user should be alerted when */ /* duplicate task occurrences cannot be checked due to an unknown frequency */ /* that is associated with the order task. A time-interval (past-present) */ /* for duplicates cannot be calculated. This only affects Duplicate Policies */ /* that use the "Task %" unit of measure. */ /* True = alert user; False = do not alert user. */ alert_if_unknown_frequency := true; /********************************************************************************/ /* Execute only when this MLM is called by the editor */ if called_by_editor then task_obj:= read last {OrderTaskOccurrence: This WHERE TaskName = "Ampicillin 500 mg" //AND SignificantDtm = 2000-09-13T06:00:00 //AND CDSOCCURRENCETYPE = 10 //and TaskStatusCode = "Rescheduled" //and ScheduleTypeCode = "ToSchedule" }; EvokingObject:= task_obj; endif; /* Declare MLMs which can be called */ func_task_messages:= MLM {{{SINGLE-QUOTE}}}std_func_task_messages{{{SINGLE-QUOTE}}}; func_task_rules:= MLM {{{SINGLE-QUOTE}}}std_func_task_rules{{{SINGLE-QUOTE}}}; /* Get the Client GUID */ client_guid := read last {ClientInfo: GUID}; /* Get information from the evoking OrderTaskOccurrence */ (task_occurrence_name, task_occurrence_guid, task_summary_line, task_status_code, task_cds_occurrence_type, task_catalog_item_guid, task_significant_date, task_scheduled_date, task_earliest_date, task_latest_date, tasks_to_be_canceled_string, order_obj, order_task_obj, back_up_obj ) := read last {OrderTaskOccurrence: TaskName, GUID, SummaryLine, TaskStatusCode, CDSOccurrenceType, CatalogItemTaskGUID, SignificantDtm, ScheduledDtm, EarliestScheduledDtm, LatestScheduledDtm, GUIDList, Order, OrderTask, Backup REFERENCING EvokingObject}; /* Get data from the OrderTask associated with the OrderTaskOccurrence */ (schedule_type_code, process_type, order_task_frequency, item_catalog_guid, order_task_guid, order_guid, task_seq_num, application_source ) := read last {OrderTask: ScheduleTypeCode, ProcessType, OrderFrequency, OrderCatalogMasterItemGUID, GUID, OrderGUID, TaskSeqNum, ApplicSource REFERENCING order_task_obj }; primary_task_sequence_num := 0; if (task_seq_num = primary_task_sequence_num) then is_primary_task := true; else is_primary_task := false; endif; /* Determine if the MLM should continue checking for duplicates */ /* The evoking-object{{{SINGLE-QUOTE}}}s OrderTask must be Continuous, PRN, Scheduled or Unscheduled */ /* OR be ToSchedule (when 1st given). Exclude everything else */ if (schedule_type_code is in ("Continuous","PRN","Scheduled","Unscheduled" ) OR (schedule_type_code = "ToSchedule" AND process_type = 4 )) AND application_source IS NULL then continue_checking_task := true; else continue_checking_task := false; endif; /* Determine if a modified OrderTaskOccurrence should be checked for duplicates */ If EvokingEventType = any_modified_task.type and continue_checking_task then if exist back_up_obj then (backup_scheduled_date, backup_earliest_date, backup_latest_date ) := read last {OrderTaskOccurrence: ScheduledDtm, EarliestScheduledDtm, LatestScheduledDtm REFERENCING back_up_obj }; /* Continue checking if the ScheduledDtm, EarliestScheduledDtm, */ /* or LatestScheduledDtm have been modified */ if (backup_scheduled_date <> task_scheduled_date ) OR (backup_scheduled_date is null and task_scheduled_date is time) OR (backup_scheduled_date is time and task_scheduled_date is null) OR (backup_earliest_date <> task_earliest_date ) OR (backup_earliest_date is null and task_earliest_date is time) OR (backup_earliest_date is time and task_earliest_date is null) OR (backup_latest_date <> task_latest_date ) OR (backup_latest_date is null and task_latest_date is time) OR (backup_latest_date is time and task_latest_date is null) then continue_checking_task:= true; endif; /* backup_scheduled_date... */ else continue_checking_task:= false; endif; /* if exist back_up_obj */ endif; /* If EvokingEvent = any_modified_task */ if continue_checking_task then /* Get data from the order associated with the OrderTaskOccurrence */ (task_name, chart_guid, client_visit_guid, order_type_code ) := read last {Order: Name, ChartGUID, ClientVisitGUID, TypeCode REFERENCING order_obj }; /* 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; /* Get all the alerts in the CACHED MEMORY for the Std_duplicate_task MLM */ (unsub_mlm_name_list, unsub_alert_priority_code_list ):= read {UnsubmittedAlerts: MLMName, PriorityCode where MLMName = "STD_DUPLICATE_TASK" }; /* Stop duplicate checking if a high priority alert exists */ /* in the CACHED MEMORY for a the same OrderTask parent in the set */ if task_cds_occurrence_type is in (11,31,41,111,131,141) AND "HIGH" is in unsub_alert_priority_code_list then continue_checking_task := false; else /* Get all alerts in the DATABASE for the same OrderTask GUID */ (task_name_list, mlm_name_list, alert_priority_code_list, mlm_pobject_name_list, mlm_rule_group_list, mlm_rule_number_list, mlm_alert_create_when_list ) := read {"SELECT t.TaskName, a.MLMName, a.PriorityCode, a.PObjectName," ||" a.RuleGroup, a.RuleNumber, a.CreatedWhen" ||" FROM CV3AlertDeclaration AS a JOIN CV3OrderTaskOccurrence AS t" ||" ON a.ClientGUID = t.ClientGUID" ||" AND t.GUID = a.PObjectGUID " ||" WHERE a.ClientGUID = " || SQL(client_guid) ||" AND t.ClientGUID = " || SQL(client_guid) ||" AND t.OrderTaskGUID = " || SQL(order_task_guid) ||" AND a.PObjectName = {{{SINGLE-QUOTE}}}COrderTaskOccurrence{{{SINGLE-QUOTE}}} " ||" AND a.MLMName = {{{SINGLE-QUOTE}}}STD_DUPLICATE_TASK{{{SINGLE-QUOTE}}} " ||" AND a.Active = 1 " , PrimaryTime = CreatedWhen }; /* Stop duplicate checking if a high priority alert exists */ /* in the DATABASE for a the same OrderTask parent in the set */ if task_cds_occurrence_type is in (11,31,41,111,131,141) AND "HIGH" is in alert_priority_code_list then continue_checking_task := false; endif; /* if task_cds_occurrence_type */ endif; /* if task_cds_occurrence_type */ endif; /* continue_checking_task */ ;; evoke: any_new_task OR any_modified_task OR any_rescheduled_task_instance; ;; logic: If NOT continue_checking_task then conclude false; endif; /* Initialize variable */ indent:= " "; /* Determine Frequency Unit to calculate time interval for "Task %" */ /* Use the frequency code from the OrderTask object, */ if exist order_task_frequency then frequency_unit := order_task_frequency; else frequency_unit := NULL; endif; /*---------------------------------*/ /* Find Duplicate task occurrences */ /*---------------------------------*/ (has_time_interval, has_unknown_frequency, exact_msg, performed_msg, scheduled_msg, same_item_type, same_therapeutic_class_type, similar_task_type, conflict_type, possible_conflict_type, no_std_message_type, duplicate_policy_guid, matching_task_name_list, matching_significant_date_list, matching_msg_type_list, matching_msg_text_list, matching_time_msg_list, matching_class_list, matching_latest_scheduled_dtm_list, matching_order_name_list, matching_order_type_code_list, matching_performed_to_dtm_list, matching_process_type_list, matching_schedule_type_code_list, matching_task_status_code_list ) := call func_task_rules with (task_name, task_occurrence_guid, task_status_code, task_summary_line, is_primary_task, order_guid, item_catalog_guid, chart_guid, client_visit_guid, task_significant_date, patient_loc_group, task_catalog_item_guid, frequency_unit, tasks_to_be_canceled_string, schedule_type_code, order_task_guid ); /*-------------------------------------------------------------*/ /* Call an MLM to select the appropriate message and format it */ /*-------------------------------------------------------------*/ If exist matching_task_name_list and (NOT has_unknown_frequency OR schedule_type_code = "continuous") then alert_msg:= call func_task_messages with (task_name, task_status_code, is_primary_task, order_type_code, exact_msg, performed_msg, scheduled_msg, same_item_type, same_therapeutic_class_type, similar_task_type, conflict_type, possible_conflict_type, no_std_message_type, matching_task_name_list, matching_significant_date_list, matching_msg_type_list, matching_msg_text_list, matching_time_msg_list, matching_class_list, matching_latest_scheduled_dtm_list, matching_order_name_list, matching_order_type_code_list, matching_performed_to_dtm_list, matching_process_type_list, matching_schedule_type_code_list, matching_task_status_code_list ); endif; /* If exist matching_task_name_list */ /*-------------------------------------*/ /* Determine if Alert Message Priority */ /*-------------------------------------*/ if schedule_type_code = "scheduled" and "Performed" is in matching_task_status_code_list then alert_priority := "HIGH"; high_priority_alert := true; else alert_priority := "MEDIUM"; high_priority_alert := false; endif; /* schedule_type_code */ /*-------------------------------------*/ /* Set Variables for the Alert Message */ /*-------------------------------------*/ if alert_priority = "high" then a1_heading := "Warning"; else a1_heading := "Caution"; endif; /* if alert_priority */ // Set task string if is_primary_task then task_string := "task"; else task_string := "follow-up task"; endif; if (is_primary_task and order_type_code = "Medication") then a2_order_type := "medication administration"; else a2_order_type := task_string; endif; // if is_primary_task and order_type_code if schedule_type_code = "scheduled" then a5_task_schedule_type := "Scheduled"; elseif schedule_type_code = "unscheduled" then a5_task_schedule_type := "Unscheduled"; elseif schedule_type_code = "PRN" then a5_task_schedule_type := "Pending PRN"; elseif schedule_type_code = "continuous" then a5_task_schedule_type := "Pending continuous"; elseif schedule_type_code = "ToSchedule" and process_type = 4 then a5_task_schedule_type := "To be scheduled starting when first done"; else a5_task_schedule_type := schedule_type_code; endif; /* if schedule_type_code */ if schedule_type_code = "scheduled" then a6_date_label := "Date" ; else a6_date_label := "Earliest Date" ; endif; /* if schedule_type_code */ /*------------------------*/ /* Assemble Alert Message */ /*------------------------*/ complete_alert_msg := "{{+B}}{{+R}}" || a1_heading || "{{-R}}{{-B}}\n" ||"This " || a2_order_type || "\n" || indent ||"{{+B}}{{+C}}"|| task_occurrence_name || "{{-C}}{{-B}}\n" || indent || "( " || a5_task_schedule_type ||" )\n" || indent || a6_date_label || ": " || task_significant_date formatted with "%.4t"|| "\n\n"; if exist matching_task_name_list and exist alert_msg and (NOT has_unknown_frequency OR schedule_type_code = "continuous") then /* Display Regular Alert Message */ complete_alert_msg := complete_alert_msg ||"{{+B}}May be too close to, or conflict with:{{-B}}\n\n" || alert_msg; elseif exist matching_task_name_list and has_unknown_frequency and alert_if_unknown_frequency then /* Display Error Message */ alert_msg:= true; complete_alert_msg := complete_alert_msg ||"Unable to check for duplicate task occurrences" ||" because all the required information to do a check, is not available. " ||" Please review the tasks at the above time for potential duplicates."; endif; /* exist matching_task_name_list */ /*------------------*/ /* Debug Statements */ /*------------------*/ xxx1_alert_msg:= exist alert_msg; xxx2_dup_policy_guid:= exist duplicate_policy_guid; xxx3_has_time_interval:= has_time_interval; xxx4_alert_priority:= alert_priority; xxx5_occur_first:= (task_cds_occurrence_type is in (10,20,30,40,110,120,130,140) ); xxx6_occur_subsequent:= (task_cds_occurrence_type is in (11,31,41,111,131,141) AND alert_priority is NOT in (alert_priority_code_list, unsub_alert_priority_code_list)); xxx7_occur_all:= ( /* First task occurrence of the set */ (task_cds_occurrence_type is in (10,20,30,40,110,120,130,140) ) OR /* Second task occurrence of the set */ (task_cds_occurrence_type is in (11,31,41,111,131,141) AND alert_priority is NOT in (alert_priority_code_list, unsub_alert_priority_code_list))); xxx8_previous_alert_priorities:= alert_priority_code_list, unsub_alert_priority_code_list; xxx9_task_cds_occurrence_type:= task_cds_occurrence_type; /*---------------*/ /* Clinical Rule */ /*---------------*/ If exist alert_msg AND exist duplicate_policy_guid AND ( // First task occurrence of the set (task_cds_occurrence_type is in (10,20,30,40,110,120,130,140) ) OR // Second task occurrence of the set (task_cds_occurrence_type is in (11,31,41,111,131,141) AND alert_priority is NOT in (alert_priority_code_list, unsub_alert_priority_code_list)) OR // Added scheduled occurrence to the set (task_cds_occurrence_type = 90) OR // Added performed occurrence to the set (task_cds_occurrence_type = 91) OR // Rescheduled an instance in the set (EVOKINGEVENTTYPE = any_rescheduled_task_instance.type) ) then conclude true; endif; ;; action: /* Select the Destination for the Alert{{{SINGLE-QUOTE}}}s Priority */ if high_priority_alert then write complete_alert_msg at high_dup_task_alert; else write complete_alert_msg at medium_dup_task_alert; endif; /* if high_priority_alert */ ;; Urgency: 50;; end: