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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,434 @@
maintenance:
title: Standard Function for setting observation values with
supplied parameters;;
mlmname: STD_DOC_FUNC_CHART_OBSERVATION_HELPER;;
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: MLM standard function that inserts value into an observation in
structured note or Flowsheet.
;;
explanation:
CONFIGURATION:
--------------
Supported Document Types:
[X] Flowsheets
[X] Structured Notes
MLM Events Supported:
[X] ChartObservation
[X] DocumentOpening
[X] DocumentClosing
Instructions:
------------
This function MLM cannot be called directly from flowsheets or structured notes. A calling document MLM would call it.
There are some requirements needed in the calling document MLM before calling this function MLM as followed:
- Object needed to declare in the calling document MLM
SelectedList := OBJECT[ ListGUID, SelectedValues, SuggestedText];
- Input parameters needed to create in Calling document MLM and pass into STD_DOC_FUNC_CHART_OBSERVATION_HELPER:
Object:Property
----------------------------------------------------------------------------------
this_documentCommunication DocumentCommunication
NewValue String array for FreetextValue
DateValue for DateValue
NumericValue for NumericValue or DripValue
NumbericValue array for IOValue or GeneralDripValue
SelectedList for ListValue or ListSetValue
Parameter parameter object of the target observation
USAGE EXAMPLE:
--------------
NewValue for inserting it into Charted Observation:
--------------------------------------------------
- NumericValue
NewValue := <NumericValue>; eg. NewValue := 24.5;
- DateValue
NewValue := <DateValue>; eg. NewValue := NOW;
- FreeTextValue
NewValue := (<String1>, <String2>);
eg. NewValue := ("This is an example of writing to a free text value.", "Replace");
NewValue[1] is Text for FreeText field and NewValue[2] Update Type for either "Replace" or "Append".
- IOValue
NewValue := (<NumericValue1>, <NumericValue1>); eg. NewValue := (24.5, 20.4);
NewValue[1] is InValue and NewValue[2] OutValue.
- GenericDripValue
NewValue := (<NumericValue1>, <NumericValue1>); eg. NewValue := (1000, 50);
NewValue[1] is DoseValue and NewValue[2] RateValue.
- DripValue
NewValue := <NumericValue>; eg. NewValue := (20);
- ListSetValue and ListValue
NewValue := (<SelectedList1>, <SelectedList2>, <SelectedList3>,...);
e.g NewValue := (ItemList1) for ListValue (There is only one SelectedList for ListValue)
NewValue := (ItemList1, List2,... Listn) for ListSetValue;
ItemList1 := NEW SelectedList;
ItemList1.ListGUID := 208488439439; // List Identification - Required
ItemList1.SelectedValues := ("Yellow", "Green", "Blue") // Selected Values - Required
ItemList1.SuggestedText := "Neither black nor white"; // List{{{SINGLE-QUOTE}}}s SugguestedTextValue - Optional - Can be null
............................................................
NewValue for clearing Charted Observation.
-----------------------------------------
This functionality is for most datatypes, except ListSetValue and ListValue.
The NewValue for clearing charted observation is an empty string.
- NumericValue, DateValue, and DripValue
NewValue := "";
- FreeTextValue, IOValue and GenericDripValue
NewValue := ("", "");
This MLM can also clear the current or existing SuggestedText(s) of ListSetValue and ListValue.
If ItemListN.SuggestedText is set to an empty string e.g. ItemListN.SuggestedText := "";.
Calling this MLM:
----------------
Sample codes:
called_DOM_mlm := MLM {{{SINGLE-QUOTE}}}STD_FUNC_CHART_OBSERVATION_HELPER{{{SINGLE-QUOTE}}};
this_documentCommunication := CALL called_DOM_mlm WITH (this_documentCommunication, NewValue, Parameter);
;;
keywords: Called MLM Function
;;
knowledge:
type: data-driven;;
data:
(this_documentCommunication, newValue, parameter) := argument; //v230478
//(this_documentCommunication, newValue, parameterName) := argument;
/*******************Make Changes To Spelling And Flags In This Section******************/
/* Set to true if a decision.log is needed.*/
log_execution_info := false;
Debug := FALSE;
/***************************************************************************************/
//*** Variable and Constant Declaration ***//
// Document Types
FLOWSHEET := "Flowsheet";
STRUCTUREDNOTE := "StructuredNote";
// Event Types
//DOCUMENTOPENING := "DocumentOpening";
//CHARTOBSERVATION := "ChartObservation";
//DOCUMENTCLOSING := "DocumentClosing";
// Parameter Types
NUMERICVALUE := "NumericValue";
FREETEXTVALUE := "FreeTextValue";
LISTVALUE := "ListValue";
LISTSETVALUE := "ListSetValue";
DATEVALUE := "DateValue";
IOVALUE := "IOValue" ;
GENERICDRIPVALUE := "GenericDripValue" ;
DRIPVALUE := "DripValue" ;
//*** Data Structures ***//
//The following data structures can be used to create new objects within the
//MLM itself. Not all data structures are represented here, only ones that can be
//created in the MLM.
//
ObservationType := OBJECT [ObservationGUID, ClientDocumentGUID, ParameterGUID, DataType, ValueObj];
DateValueType := OBJECT [Value];
FreeTextValueType := OBJECT [Value];
ListValueType := OBJECT [ListGUID, ListItemsList, SuggestedTextValue];
ListValueListItemType := OBJECT [ListItemGUID, Value, IsSelected];
NumericValueType := OBJECT [Value];
IOValueType := OBJECT [InValue, OutValue, DayRunningValue, BagNumber, BagInitialVolume];
GenericDripValueType := OBJECT [DoseValue, RateValue];
DripValueType := OBJECT [Value, BagNumber, BagInitialVolume];
ListSetValueType := OBJECT [ListValuesList];
//SelectedList := OBJECT[ ListGUID, SelectedValues, SuggestedTextValue];
(this_parameters) := NULL;
messageDebug := "";
(this_chartedObservationsList) := NULL;
IF this_documentCommunication.DocumentType = FLOWSHEET THEN
(this_flowsheetDoc) := this_documentCommunication.DocumentConfigurationObj;
(this_CurrentColumn) := this_flowsheetDoc.CurrentColumn;
this_parameters := this_flowsheetDoc.ParametersList;
this_chartedObservationsList := this_CurrentColumn.ChartedObservationsList;
(client_document_guid) := this_CurrentColumn.ClientDocumentGUID;
messageDebug := messageDebug || "Flowsheet";
ELSEIF this_documentCommunication.DocumentType = STRUCTUREDNOTE THEN
(this_structuredNoteDoc) := this_documentCommunication.DocumentConfigurationObj;
this_parameters := this_structuredNoteDoc.ParametersList;
this_chartedObservationsList := this_structuredNoteDoc.ChartedObservationsList;
(client_document_guid) := this_structuredNoteDoc.ClientDocumentGUID;
messageDebug := messageDebug || "Structured Note";
ENDIF;
(this_currentObj) := this_documentCommunication.CurrentObservationObj;
obsExisted := TRUE;
IF EXISTS parameter THEN
messageDebug := messageDebug || "\n Parameter is available.";
obs := FIRST OF (this_ChartedObservationsList WHERE this_ChartedObservationsList.parameterGUID = parameter.parameterGUID);
IF NOT EXISTS obs THEN
obsExisted := FALSE;
messageDebug := messageDebug || "\n Charted Observation is not existed. Creating one.";
//Create a new Observation for the list
obs := NEW ObservationType;
obs.ObservationGUID:= 0; //v230478
obs.ClientDocumentGUID := client_document_guid;
obs.ParameterGUID := parameter.ParameterGUID;
obs.DataType := parameter.DataType;
// Based on the parameter.DataType create the ValueObj Type and set the valueObj.value for (FREETEXTVALUETYPE,DATEVALUETYPE,NUMERICVALUETYPE)
// If the DataType is LISTVALUE then creat the valueObj of LISTVALUETYPE ABD ASSIGN THE paramter.configurationObj.ListGUID
IF parameter.DataType = FREETEXTVALUE THEN
obs.ValueObj := NEW FreeTextValueType;
ELSEIF parameter.DataType = DATEVALUE THEN
obs.ValueObj := NEW DateValueType;
ELSEIF parameter.DataType = DRIPVALUE THEN
obs.ValueObj := NEW DripValueType;
ELSEIF parameter.DataType = NUMERICVALUE THEN
obs.ValueObj := NEW NumericValueType;
ELSEIF parameter.DataType = LISTVALUE THEN
obs.ValueObj := NEW ListValueType;
obs.ValueObj.ListGUID := parameter.ConfigurationObj.ListGUID;
ELSEIF parameter.DataType = LISTSETVALUE THEN
obs.ValueObj := NEW ListSetValueType;
ELSEIF parameter.DataType = IOVALUE THEN
obs.ValueObj := NEW IOValueType;
ELSEIF parameter.DataType = GENERICDRIPVALUE THEN
obs.ValueObj := NEW GenericDripValueType;
ENDIF; // creating obs.ValueObj
ELSE
messageDebug := messageDebug || "\n Charted Observation is existed.";
ENDIF; // IF NOT EXISTS obs
// Setting Value
IF parameter.DataType = FREETEXTVALUE THEN
Text := STRING newValue[1];
UpdateType := STRING newValue[2];
IF EXISTS Text AND Text <> "" THEN
IF LENGTH of obs.ValueObj.Value > 0 AND UpdateType = "Append" THEN
obs.ValueObj.Value := obs.ValueObj.Value || "\n" || Text;
messageDebug := messageDebug || "\n Append free text - " || parameter.Name || " - " || Text;
ELSE
obs.ValueObj.Value := Text;
ENDIF;
ELSE
IF EXISTS obs.ValueObj.Value THEN
obs.ValueObj.Value := "";
ENDIF;
messageDebug := messageDebug || "\n Set free text To Empty String";
ENDIF;
ELSEIF parameter.DataType IN(DATEVALUE,NUMERICVALUE, DRIPVALUE) THEN
IF EXISTS newValue AND newValue <> "" THEN
obs.ValueObj.Value := newValue;
messageDebug := messageDebug || "\n Set " || parameter.DataType || " - " || parameter.Name || " - " ||newValue;
ELSE
obs.ValueObj := NULL;
messageDebug := messageDebug || "\n Deleted " || parameter.DataType;
ENDIF;
ELSEIF parameter.DataType = IOVALUE THEN
// newValue[1] is InValue and newValue[2] OutValue
IF EXISTS newValue[1] AND newValue[1] <> "" THEN
messageDebug := messageDebug || "\n Set IOValue IN - " || parameter.Name || " - " || newValue[1];
obs.ValueObj.InValue := newValue[1];
ELSE
messageDebug := messageDebug || "\n Deleted IOValue";
obs.ValueObj := NULL;
ENDIF;
IF EXISTS newValue[2] AND newValue[2] <> "" THEN
messageDebug := messageDebug || "\n Set IOValue OUT - " || parameter.Name || " - " ||newValue[2];
obs.ValueObj.OutValue := newValue[2];
ELSE
messageDebug := messageDebug || "\n Deleted IOValue";
obs.ValueObj := NULL;
ENDIF;
ELSEIF parameter.DataType = GENERICDRIPVALUE THEN
// newValue[1] is DoseValue and newValue[2] RateValue
IF EXISTS newValue[1] AND newValue[1] <> "" THEN
messageDebug := messageDebug || "\n Set GenericDripValue DoseValue - " || parameter.Name || " - " ||newValue[1];
obs.ValueObj.DoseValue := newValue[1];
ELSE
messageDebug := messageDebug || "\n Deleted GenericDripValue DoseValue";
obs.ValueObj := NULL;
ENDIF;
IF EXISTS newValue[2] AND newValue[2] <> "" THEN
messageDebug := messageDebug || "\n Set GenericDripValue RateValue - " || parameter.Name || " - " ||newValue[2];
obs.ValueObj.RateValue := newValue[2];
ELSE
messageDebug := messageDebug || "\n Deleted GenericDripValue";
obs.ValueObj := NULL;
ENDIF;
ELSEIF parameter.DataType IN (LISTVALUE, LISTSETVALUE) THEN
IF obsExisted = TRUE THEN
ListValues := ();
IF parameter.DataType = LISTVALUE THEN
ListValues := (ListValues, Obs.ValueObj);
messageDebug := messageDebug || "\n Selected Items of LISTVALUE - " || parameter.Name;
ELSE
ListValues := Obs.ValueObj.ListValuesList;
messageDebug := messageDebug || "\n Selected Items of LISTSETVALUE - " || parameter.Name;
ENDIF;
FOR itemsList in ListValues DO
selList := newValue WHERE newValue.ListGUID = itemsList.ListGUID;
IF parameter.DataType = LISTVALUE THEN
listConfiguration := parameter.ConfigurationObj;
ELSE
listConfiguration := FIRST OF (parameter.ConfigurationObj.ListConfigurationList
WHERE parameter.ConfigurationObj.ListConfigurationList.ListGUID = itemsList.ListGUID);
ENDIF;
selValues := ();
IF EXIST selList THEN
FOR selvalue in selList.SelectedValues DO
selValues := (selValues, selvalue);
ENDDO;
IF EXISTS selList.SuggestedTextValue THEN
suggText := STRING selList.SuggestedTextValue;
ENDIF;
ENDIF;
IF listConfiguration.AllowsSuggestedText = TRUE THEN
itemsList.SuggestedTextValue := suggText;
ENDIF;
multiSelect := TRUE;
FOR item IN itemsList.ListItemsList DO
IF item.Value IN selValues AND multiSelect = TRUE THEN
item.IsSelected := TRUE;
IF listConfiguration.IsMultiSelect = FALSE THEN
multiSelect := FALSE;
ENDIF;
messageDebug := messageDebug || "\n " || Item.Value || " selected";
ELSE
messageDebug := messageDebug || "\n " || Item.Value || " de-selected";
ENDIF;
ENDDO;
ENDDO;
//obs did not exist, aka: param was not charted on prior to this mlm being called
ELSE
listConfigurations := ();
IF parameter.DataType = LISTVALUE THEN
listConfigurations := (listConfigurations, parameter.ConfigurationObj);
ELSE
listConfigurations := parameter.ConfigurationObj.ListConfigurationList;
ENDIF;
FOR itemsList IN listConfigurations DO
IF parameter.DataType = LISTVALUE THEN
newlistValue := obs.ValueObj;
ELSE
newlistValue := NEW ListValueType;
newlistValue.ListGUID := itemsList.ListGUID;
ENDIF;
//selList is the passed in list contained in newValue
selList := newValue WHERE newListValue.ListGUID = itemsList.ListGUID;
selValues := ();
IF EXIST selList THEN
FOR selvalue in selList.SelectedValues DO
selValues := (selValues, selvalue);
ENDDO;
IF EXISTS selList.SuggestedTextValue THEN
suggText := STRING selList.SuggestedTextValue;
ENDIF;
ENDIF;
IF itemsList.AllowsSuggestedText = TRUE THEN
newListValue.SuggestedTextValue := suggText;
ENDIF;
multiSelect := TRUE;
FOR item IN itemsList.ListItemsList DO
// Create a list item object for the selected list item
newItem := NEW ListValueListItemType;
newItem.ListItemGUID := item.ListItemGUID;
newItem.Value := item.Value;
IF item.Value IN selValues AND multiSelect = TRUE THEN
newItem.IsSelected := TRUE;
IF itemsList.IsMultiSelect = FALSE THEN
multiSelect := FALSE;
ENDIF;
messageDebug := messageDebug || "\n New ListItem - " || item.Value || " selected";
ELSE
// This is To Select any Single select List value. // Start-- Added By Ganesh
IF newValue = item.Value THEN
newItem.IsSelected := TRUE;
ELSE
// Multiselect list value
IF item.Value IN newValue THEN
newItem.IsSelected := TRUE;
ELSE
newItem.IsSelected := FALSE;
ENDIF;
//END Ganesh Changes
ENDIF;
messageDebug := messageDebug || "\n New ListItem - " || item.Value || " de-selected";
ENDIF;
// Arden list append statement appending the new object to the listItems object
newListValue.ListItemsList := (newListValue.ListItemsList, newItem);
ENDDO;
IF parameter.DataType = LISTSETVALUE THEN
Obs.ValueObj.ListValuesList := (Obs.ValueObj.ListValuesList, newListValue);
ELSE
Obs.ValueObj := newListValue;
ENDIF;
ENDDO;
ENDIF;
ENDIF; // END Setting value
IF obsExisted = FALSE THEN
IF exists this_chartedObservationsList THEN
IF this_documentCommunication.DocumentType = FLOWSHEET THEN
this_CurrentColumn.ChartedObservationsList := (this_chartedObservationsList, obs);
ELSEIF this_documentCommunication.DocumentType = STRUCTUREDNOTE THEN
this_structuredNoteDoc.ChartedObservationsList:= (this_chartedObservationsList, obs);
ENDIF;
ELSE
IF this_documentCommunication.DocumentType = FLOWSHEET THEN
this_CurrentColumn.ChartedObservationsList := (obs as list);
ELSEIF this_documentCommunication.DocumentType = STRUCTUREDNOTE THEN
this_structuredNoteDoc.ChartedObservationsList:= (obs as list);
ENDIF;
ENDIF;
ENDIF;
ELSE
messageDebug := messageDebug || "\n Parameter is not available.";
ENDIF; // IF EXISTS parameter
//Tell DocumentCommunication to Display the Message
IF Debug = TRUE THEN
this_documentCommunication.DisplayMessage := TRUE;
this_documentCommunication.Message := messageDebug;
ENDIF;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return this_documentCommunication;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,483 @@
maintenance:
title: Standard Function for setting observation values with
supplied parameters;;
mlmname: STD_DOC_FUNC_CHART_OBSERVATION_HELPER_JAB;;
arden: version 2.5;;
version: 5.50;;
institution: Eclipsys, Function for use with Document Called MLM;;
author: Eclipsys Corporartion;;
specialist: ;;
date: 2010-03-16;;
validation: testing;;
library:
purpose: MLM standard function that inserts value into an observation in
structured note or Flowsheet.
20110203 - JAB edited to allow a passed parameter name.
;;
explanation:
DEPENDENCIES:
-------------
None
SOFTWARE REQUIREMENTS:
----------------------
Requires Sunrise 5.0 SP1
CONFIGURATION:
--------------
Supported Document Types:
[X] Flowsheets
[X] Structured Notes
MLM Events Supported:
[X] ChartObservation
[X] DocumentOpening
[X] DocumentClosing
Instructions:
------------
This function MLM cannot be called directly from flowsheets or structured
notes. A calling document MLM would call it. There are some requirements
needed in the calling document MLM before calling this function MLM as followes:
- Object needed to declare in the calling document MLM
SelectedList := OBJECT[ ListGUID, SelectedValues, SuggestiveText];
- Input parameters needed to create in Calling document MLM and pass into
STD_DOC_FUNC_CHART_OBSERVATION_HELPER:
Object:Property
----------------------------------------------------------------------------------
this_documentCommunication DocumentCommunication
NewValue String array for FreetextValue
DateValue for DateValue
NumericValue for NumericValue or DripValue
NumbericValue array for IOValue or GeneralDripValue
SelectedList for ListValue or ListSetValue
USAGE EXAMPLE:
--------------
NewValue for inserting it into Charted Observation:
--------------------------------------------------
- NumericValue
NewValue := <NumericValue>; eg. NewValue := 24.5;
- DateValue
NewValue := <DateValue>; eg. NewValue := NOW;
- FreeTextValue
NewValue := (<String1>, <String2>);
eg. NewValue := ("This is an example of writing to a free text value.",
"Replace");
NewValue[1] is Text for FreeText field and NewValue[2] Update Type for either
"Replace" or "Append".
- IOValue
NewValue := (<NumericValue1>, <NumericValue1>); eg. NewValue := (24.5, 20.4);
NewValue[1] is InValue and NewValue[2] OutValue.
- GenericDripValue
NewValue := (<NumericValue1>, <NumericValue1>); eg. NewValue := (1000, 50);
NewValue[1] is DoseValue and NewValue[2] RateValue.
- DripValue
NewValue := <NumericValue>; eg. NewValue := (20);
- ListSetValue and ListValue
NewValue := (<SelectedList1>, <SelectedList2>, <SelectedList3>,...);
e.g NewValue := (ItemList1) for ListValue (There is only one SelectedList
for ListValue)
NewValue := (ItemList1, List2,... Listn) for ListSetValue;
ItemList1 := NEW SelectedList;
ItemList1.ListGUID := 208488439439; // List Identification - Required
ItemList1.SelectedValues := ("Yellow", "Green", "Blue")
// Selected Values - Required
ItemList1.SuggestiveText := "Neither black nor white";
//List{{{SINGLE-QUOTE}}}s SugguestedTextValue - Optional - Can be null
............................................................
NewValue for clearing Charted Observation.
-----------------------------------------
This functionality is for most datatypes, except ListSetValue and ListValue.
The NewValue for clearing charted observation is an empty string.
- NumericValue, DateValue, and DripValue
NewValue := "";
- FreeTextValue, IOValue and GenericDripValue
NewValue := ("", "");
This MLM can also clear the current or existing SuggestiveText(s) of ListSetValue
and ListValue. If ItemListN.SuggestiveText is set to an empty string
e.g. ItemListN.SuggestiveText := "";.
Calling this MLM:
----------------
Sample codes:
called_DOM_mlm := MLM {{{SINGLE-QUOTE}}}STD_FUNC_CHART_OBSERVATION_HELPER{{{SINGLE-QUOTE}}};
this_documentCommunication := CALL called_DOM_mlm WITH (this_documentCommunication,
NewValue);
;;
keywords: Called MLM Function
;;
knowledge:
type: data-driven;;
data:
(this_documentCommunication,
//20110203 - JAB edited to allow a passed parameter name.
parameter_name,
newValue) := argument;
/*******************Make Changes To Spelling And Flags In This Section******************/
/* Set to true if a decision.log is needed.*/
log_execution_info := true;
Debug := false;
standard_libs := mlm {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
using "ObjectsPlusXA.SCM.Forms";
using namespace "ObjectsPlusXA.SunriseClinicalManager.Forms";
/***************************************************************************************/
//*** Variable and Constant Declaration ***//
// Document Types
FLOWSHEET := "Flowsheet";
STRUCTUREDNOTE := "StructuredNote";
// Event Types
//DOCUMENTOPENING := "DocumentOpening";
//CHARTOBSERVATION := "ChartObservation";
//DOCUMENTCLOSING := "DocumentClosing";
// Parameter Types
NUMERICVALUE := "NumericValue";
FREETEXTVALUE := "FreeTextValue";
LISTVALUE := "ListValue";
LISTSETVALUE := "ListSetValue";
DATEVALUE := "DateValue";
IOVALUE := "IOValue" ;
GENERICDRIPVALUE := "GenericDripValue" ;
DRIPVALUE := "DripValue" ;
//*** Data Structures ***//
//The following data structures can be used to create new objects within the
//MLM itself. Not all data structures are represented here, only ones that can be
//created in the MLM.
//
ObservationType := OBJECT [ObservationGUID, ClientDocumentGUID, ParameterGUID,
DataType, ValueObj];
DateValueType := OBJECT [Value];
FreeTextValueType := OBJECT [Value];
ListValueType := OBJECT [ListGUID, ListItemsList, SuggestedTextValue];
ListValueListItemType := OBJECT [ListItemGUID, Value, IsSelected];
NumericValueType := OBJECT [Value];
IOValueType := OBJECT [InValue, OutValue, DayRunningValue, BagNumber,
BagInitialVolume];
GenericDripValueType := OBJECT [DoseValue, RateValue];
DripValueType := OBJECT [Value, BagNumber, BagInitialVolume];
ListSetValueType := OBJECT [ListValuesList];
//SelectedList := OBJECT[ ListGUID, SelectedValues, SuggestiveText];
(this_parameters) := NULL;
messageDebug := "";
(this_chartedObservationsList) := NULL;
IF this_documentCommunication.DocumentType = FLOWSHEET THEN
(this_flowsheetDoc) := this_documentCommunication.DocumentConfigurationObj;
(this_CurrentColumn) := this_flowsheetDoc.CurrentColumn;
this_parameters := this_flowsheetDoc.ParametersList;
this_chartedObservationsList := this_CurrentColumn.ChartedObservationsList;
(client_document_guid) := this_CurrentColumn.ClientDocumentGUID;
messageDebug := messageDebug || "Flowsheet";
ELSEIF this_documentCommunication.DocumentType = STRUCTUREDNOTE THEN
(this_structuredNoteDoc) := this_documentCommunication.DocumentConfigurationObj;
this_parameters := this_structuredNoteDoc.ParametersList;
this_chartedObservationsList := this_structuredNoteDoc.ChartedObservationsList;
(client_document_guid) := this_structuredNoteDoc.ClientDocumentGUID;
messageDebug := messageDebug || "Structured Note";
ENDIF;
(this_currentObj) := this_documentCommunication.CurrentObservationObj;
parameter := FIRST OF (this_parameters
//20110203 - JAB edited to allow a passed parameter name.
// WHERE this_parameters.ParameterGUID = this_currentObj.ParameterGUID);
WHERE this_parameters.name = parameter_name);
//20110203 - JAB END of change
obsExisted := TRUE;
IF EXISTS parameter THEN
messageDebug := messageDebug || "\n Parameter is available.";
obs := FIRST OF (this_ChartedObservationsList
WHERE this_ChartedObservationsList.parameterGUID = parameter.parameterGUID);
IF NOT EXISTS obs THEN
obsExisted := FALSE;
messageDebug := messageDebug
|| "\n Charted Observation is not existed. Creating one.";
//Create a new Observation for the list
obs := NEW ObservationType;
obs.ClientDocumentGUID := client_document_guid;
obs.ParameterGUID := parameter.ParameterGUID;
obs.DataType := parameter.DataType;
// Based on the parameter.DataType create the ValueObj Type and set the
// valueObj.value for (FREETEXTVALUETYPE,DATEVALUETYPE,NUMERICVALUETYPE)
// If the DataType is LISTVALUE then creat the valueObj of LISTVALUETYPE
// AND ASSIGN THE paramter.configurationObj.ListGUID
IF parameter.DataType = FREETEXTVALUE THEN
obs.ValueObj := NEW FreeTextValueType;
ELSEIF parameter.DataType = DATEVALUE THEN
obs.ValueObj := NEW DateValueType;
ELSEIF parameter.DataType = DRIPVALUE THEN
obs.ValueObj := NEW DripValueType;
ELSEIF parameter.DataType = NUMERICVALUE THEN
obs.ValueObj := NEW NumericValueType;
ELSEIF parameter.DataType = LISTVALUE THEN
obs.ValueObj := NEW ListValueType;
obs.ValueObj.ListGUID := parameter.ConfigurationObj.ListGUID;
ELSEIF parameter.DataType = LISTSETVALUE THEN
obs.ValueObj := NEW ListSetValueType;
ELSEIF parameter.DataType = IOVALUE THEN
obs.ValueObj := NEW IOValueType;
ELSEIF parameter.DataType = GENERICDRIPVALUE THEN
obs.ValueObj := NEW GenericDripValueType;
ENDIF; // creating obs.ValueObj
// APPEND obs to the ChartedObservationsList
//this_chartedObservationsList := (this_chartedObservationsList, obs);
ELSE
messageDebug := messageDebug || "\n Charted Observation is existed.";
ENDIF; // IF NOT EXISTS obs
// Setting Value
IF parameter.DataType = FREETEXTVALUE THEN
Text := STRING newValue[1];
UpdateType := STRING newValue[2];
IF EXISTS Text AND Text <> "" THEN
//break;
IF LENGTH of obs.ValueObj.Value > 0 AND UpdateType = "Append" THEN
obs.ValueObj.Value := obs.ValueObj.Value || "\n" || Text;
messageDebug := messageDebug || "\n Append free text - "
|| parameter.Name || " - " || Text;
//break;
ELSE
obs.ValueObj.Value := Text;
messageDebug := messageDebug || "\n Set free text - "
|| parameter.Name || " - " || Text;
//break;
ENDIF;
ELSE
IF EXISTS obs.ValueObj.Value THEN
obs.ValueObj.Value := "";
ENDIF;
messageDebug := messageDebug || "\n Set free text To Empty String";
//break;
ENDIF;
ELSEIF parameter.DataType IN(DATEVALUE,NUMERICVALUE, DRIPVALUE) THEN
IF EXISTS newValue AND newValue <> "" THEN
obs.ValueObj.Value := newValue;
messageDebug := messageDebug || "\n Set " || parameter.DataType
|| " - " || parameter.Name || " - " ||newValue;
ELSE
obs.ValueObj := NULL;
messageDebug := messageDebug || "\n Deleted " || parameter.DataType;
//break;
ENDIF;
ELSEIF parameter.DataType = IOVALUE THEN
// newValue[1] is InValue and newValue[2] OutValue
IF EXISTS newValue[1] AND newValue[1] <> "" THEN
messageDebug := messageDebug || "\n Set IOValue IN - " || parameter.Name
|| " - " || newValue[1];
obs.ValueObj.InValue := newValue[1];
ELSE
messageDebug := messageDebug || "\n Deleted IOValue";
obs.ValueObj := NULL;
ENDIF;
IF EXISTS newValue[2] AND newValue[2] <> "" THEN
messageDebug := messageDebug || "\n Set IOValue OUT - " || parameter.Name
|| " - " ||newValue[2];
obs.ValueObj.OutValue := newValue[2];
ELSE
messageDebug := messageDebug || "\n Deleted IOValue";
obs.ValueObj := NULL;
ENDIF;
ELSEIF parameter.DataType = GENERICDRIPVALUE THEN
// newValue[1] is DoseValue and newValue[2] RateValue
IF EXISTS newValue[1] AND newValue[1] <> "" THEN
messageDebug := messageDebug || "\n Set GenericDripValue DoseValue - "
|| parameter.Name || " - " ||newValue[1];
obs.ValueObj.DoseValue := newValue[1];
ELSE
messageDebug := messageDebug || "\n Deleted GenericDripValue DoseValue";
obs.ValueObj := NULL;
ENDIF;
IF EXISTS newValue[2] AND newValue[2] <> "" THEN
messageDebug := messageDebug || "\n Set GenericDripValue RateValue - "
|| parameter.Name || " - " ||newValue[2];
obs.ValueObj.RateValue := newValue[2];
ELSE
messageDebug := messageDebug || "\n Deleted GenericDripValue";
obs.ValueObj := NULL;
ENDIF;
ELSEIF parameter.DataType IN (LISTVALUE, LISTSETVALUE) THEN
IF obsExisted = TRUE THEN
ListValues := ();
IF parameter.DataType = LISTVALUE THEN
ListValues := (ListValues, Obs.ValueObj);
messageDebug := messageDebug || "\n Selected Items of LISTVALUE - "
|| parameter.Name;
ELSE
ListValues := Obs.ValueObj.ListValuesList;
messageDebug := messageDebug
|| "\n Selected Items of LISTSETVALUE - " || parameter.Name;
ENDIF;
FOR itemsList in ListValues DO
selList := newValue WHERE newValue.ListGUID = itemsList.ListGUID;
IF parameter.DataType = LISTVALUE THEN
listConfiguration := parameter.ConfigurationObj;
ELSE
listConfiguration := FIRST OF
(parameter.ConfigurationObj.ListConfigurationList WHERE
parameter.ConfigurationObj.ListConfigurationList.ListGUID =
itemsList.ListGUID);
ENDIF;
suggText := NULL;
selValues := ();
IF EXIST selList THEN
FOR selvalue in selList.SelectedValues DO
selValues := (selValues, selvalue);
ENDDO;
suggText := STRING selList.SuggestiveText;
ENDIF;
IF listConfiguration.AllowsSuggestedText = TRUE THEN
IF NOT EXISTS suggText OR suggText = "" THEN
IF EXIST itemsList.SuggestedTextValue THEN
//break;
itemsList.SuggestedTextValue := NULL;
//break;
ENDIF;
ELSE
IF EXIST itemsList.SuggestedTextValue THEN
//break;
itemsList.SuggestedTextValue :=
itemsList.SuggestedTextValue || ", " || suggText;
//break;
ELSE
//break;
itemsList.SuggestedTextValue := suggText;
//break;
ENDIF;
ENDIF;
ENDIF;
multiSelect := TRUE;
FOR item IN itemsList.ListItemsList DO
IF item.Value IN selValues AND multiSelect = TRUE THEN
item.IsSelected := TRUE;
IF listConfiguration.IsMultiSelect = FALSE THEN
multiSelect := FALSE;
ENDIF;
messageDebug := messageDebug || "\n " || Item.Value
|| " selected";
ELSE
item.IsSelected := FALSE;
messageDebug := messageDebug || "\n " || Item.Value
|| " de-selected";
ENDIF;
ENDDO;
ENDDO;
ELSE
listConfigurations := ();
IF parameter.DataType = LISTVALUE THEN
listConfigurations := (listConfigurations,
parameter.ConfigurationObj);
ELSE
listConfigurations :=
parameter.ConfigurationObj.ListConfigurationList;
ENDIF;
FOR itemsList IN listConfigurations DO
IF parameter.DataType = LISTVALUE THEN
newlistValue := obs.ValueObj;
ELSE
newlistValue := NEW ListValueType;
newListValue.ListGUID := itemsList.ListGUID;
ENDIF;
selList := newValue WHERE newValue.ListGUID = itemsList.ListGUID;
suggText := NULL;
selValues := ();
IF EXIST selList THEN
FOR selvalue in selList.SelectedValues DO
selValues := (selValues, selvalue);
ENDDO;
suggText := STRING selList.SuggestiveText;
ENDIF;
IF itemsList.AllowsSuggestedText = TRUE THEN
IF EXISTS suggText OR suggText <> "" THEN
newListValue.SuggestedTextValue := suggText;
ENDIF;
ENDIF;
multiSelect := TRUE;
FOR item IN itemsList.ListItemsList DO
// Create a list item object for the selected list item
newItem := NEW ListValueListItemType;
newItem.ListItemGUID := item.ListItemGUID;
newItem.Value := item.Value;
IF item.Value IN selValues AND multiSelect = TRUE THEN
newItem.IsSelected := TRUE;
IF itemsList.IsMultiSelect = FALSE THEN
multiSelect := FALSE;
ENDIF;
messageDebug := messageDebug || "\n New ListItem - "
|| item.Value || " selected";
ELSE
newItem.IsSelected := FALSE;
messageDebug := messageDebug || "\n New ListItem - "
|| item.Value || " de-selected";
ENDIF;
// Arden list append statement appending the new object to
// the listItems object
newListValue.ListItemsList :=
(newListValue.ListItemsList, newItem);
ENDDO;
IF parameter.DataType = LISTSETVALUE THEN
Obs.ValueObj.ListValuesList := (Obs.ValueObj.ListValuesList,
newListValue);
ELSE
Obs.ValueObj := newListValue;
ENDIF;
ENDDO;
ENDIF;
ENDIF; // END Setting value
IF obsExisted = FALSE THEN
//20110203 - JAB edited to allow a passed parameter name.
// this_currentObj := obs;
this_chartedObservationsList := (this_chartedObservationsList,
// this_currentObj)
obs)
;
IF this_documentCommunication.DocumentType = STRUCTUREDNOTE THEN
this_documentCommunication.DocumentConfigurationObj.ChartedObservationsList := (
this_documentCommunication.DocumentConfigurationObj.ChartedObservationsList,
obs);
ELSEIF this_documentCommunication.DocumentType = FLOWSHEET THEN
this_documentCommunication.DocumentConfigurationObj.CurrentColumn.ChartedObservationsList:=(
this_documentCommunication.DocumentConfigurationObj.CurrentColumn.ChartedObservationsList,
Obs );
endif;
//20110203 - JAB end of change
ENDIF;
ELSE
messageDebug := messageDebug || "\n Parameter is not available.";
ENDIF; // IF EXISTS parameter
//Tell DocumentCommunication to Display the Message
IF Debug = TRUE THEN
this_documentCommunication.DisplayMessage := TRUE;
this_documentCommunication.Message := messageDebug;
ENDIF;
//this_documentCommunication.FocusParameterGUID := parameter.parameterGUID;
//break;
;;
priority: 50
;;
evoke:
;;
logic: conclude true;
;;
action: return this_documentCommunication;
;;
Urgency: 50;;
end:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,792 @@
maintenance:
title: Advanced Duplicate Order Checking;;
mlmname: STD_DUPLICATE;;
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 Advanced Duplicate-Order Checking and Actions on Alerts.
The checking will include:
1. Orders of the same name or type within a pre-defined date range,
which will be varied by patient location.
2. Active orders of the same type/class.
3. IV-additives.
4. Resulted orders of community results of the same name within a pre-defined date range.
;;
explanation: An Evoking-Order is considered a duplicate of Other-Orders when all of
the criteria listed below are met:
a. The evoking-order is one of the following events: new order or outpatient order, released from hold,
activated from a conditional order, unsuspended, verified, or an order or outpatient order that
has been modified.
b. If the evoking object is a modified order or outpatient order, only an order with changes to the
SignificantDtm or the StopDtm will be checked for duplicate orders.
c. The evoking-order has an order status level number between 0-50 (AWPA-AUA10),
excluding 15 = HOLD.
d. The evoking-order is not excluded from duplicate checking
(over-all or by patient location).
e. The orders have identical Item Names, or the other-order matches the Item or
Class-Name & Value listed in the evoking-order{{{SINGLE-QUOTE}}}s item-catalog
duplicate-checking panel.
f. The other-orders are within the scoping rules for the patient location listed
in the evoking-order{{{SINGLE-QUOTE}}}s Duplicate 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.
g. The IsConditional status match between the evoking-order and the other-order.
h. Neither the evoking-order or the other-order are suspended.
i. Neither the evoking-order or the other-order are Master Repeat Orders.
j. The evoking-order conflicts with another current/active order,
or resources could be wasted if both orders are completed.
The radio-buttons in the item-catalog--duplicate panel determine
which situation may be occurring.
* CONFLICTING ORDER: If the radio-button for
"Based on Start and Stop Date (like medication orders)"
is selected, then only "current" orders with over-lapping
start (significant) & stop-times are considered conflicting orders.
Current orders have an order status level number
between 0-50, excluding HOLD, CANC, CANP, CAND, CANT, COMPA,
HISE, HISI, DISC, DISCD and DISCT.
These orders can be unsubmitted orders or orders already in the database.
* WASTING RESOURCES: If the radio-button for
"Based on Significant Date and Time (like diagnostic orders)"
is selected, then other "current, scheduled, or completed" orders within
the pre-defined time ranges are potential duplicates that could
waste resources. These other-orders will have an order status level
number between 0-100, excluding HOLD, CANC, CANP, CAND, CANT, COMPA,
HISE, HISI, DISC, DISCD and DISCT.
They can be unsubmitted orders or orders already in the database
or resulted orders from community
k. The evoking-order conflicts with existing orders belonging to the session
types as defined in the following list variables (e.g.
at_discharge_session_list, at_in_house_session_list,
at_historical_session_list, or at_outpatient_session_list).
The list variable corresponding to the session type of the entered order is used.
l. The facility can set MLM flag to allow the site to determine whether they want to
see Duplicate alerts for resulted orders from Community Results upon an order being
entered or modified. Set the flag to True to turn on Community Results checking.
The default = False;
enable_community_data_results_alerts := False;
m. The facility can set MLM flag to allow the site to match the resulted
order of community results using the order name if the resulted order cannot
be mapped to an item catalog item.
The default = False;
enable_Diagnostic_Duplicate_Check_by_Community_Order_Name := False;
n. The facility can set MLM flag to allow the site to control the "text" that is displayed in
the alert message for Community Results workflows versus Sunrise Orders.
The default = "Community". The alert text is configurable.
community_resultedOrder_alert_text := "Community";
Once a duplicate-order has been identified, selection of the appropriate message
is based on: (1) the defined MESSAGE TYPE in the item-catalog, (2) if appropriate,
the time period of the significant date (performed, exact, or scheduled), and
(3)if the message type is "exact" and the time period is "performed" or "scheduled,"
then a third criteria of "order without specific stop-date" will be added to
select the correct message.
The SEND_ALERT variable indicates whether to send the message or not.
The values are:
"", or blank = use the {{{SINGLE-QUOTE}}}Send with order{{{SINGLE-QUOTE}}} flag set in the AlertTypes dictionary
(NOTE that default setting of flag is unchecked. If the flag is
checked and this variable is left blank or "" all of the alerts
for this MLM will be sent with the order.)
"DoNotSend" = do not send the alert regardless of the AlertTypes dictionary
setting for the {{{SINGLE-QUOTE}}}Send with order{{{SINGLE-QUOTE}}} flag
"Send" = send the alert regardless of the AlertTypes dictionary setting
for the {{{SINGLE-QUOTE}}}Send with order{{{SINGLE-QUOTE}}} flag
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
The ORDER STATUS LEVEL FLAGS determine what order statuses are retrieved
from the database and the unsubmitted orders. A facility may wish to
increase/decrease the order status numbers to retrieve more/less
order statuses that should be checked for duplicates.
However, increasing the "highest_status_level_for_meds" beyond 50
for MEDS may slow performance since large numbers of orders are returned
and are eventually discarded because their start and stop dates do not overlap.
Examples of setting are:
* 0-100 includes all order statuses
* 0-50 includes all "active/current" orders
* 40-50 includes orders from Pending to Active (excludes Pending Verification)
Complex and Multiple Frequencies Orders:
When retrieving unsubmitted and existing database orders, this MLM will consider
whether the order is:
- that have a start and stop time (like medication orders)
- that have a Significant date and time like (diagnositic orders)
This configuration is set in the Item Catalog Duplicate Checking option
Orders that have a start and stop time (like medication orders) will check
not check child orders (ComplexOrderType of 2,4,6)that exist in the database
or in the unsubmitted orders list.
Orders that have a Significant date and time like (diagnositic orders) will not
check Master orders (ComplexOrderType of 1,3,5) that exist in the database.
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
;;
keywords: Duplicate Order;
;;
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;
/* Set the text for the variable below to indicate whether to send the message or not. */
send_alert := "DoNotSend";
/* Set a flag indicating whether or not Actions on Alerts should be generated */
generate_actions_on_alerts := TRUE;
alert_if_initial_error:= FALSE;
/* Set the ORDER STATUS LEVEL FLAGS to a different Order Status Level */
/* if more or fewer order statuses should be included */
lowest_status_level_for_diagnostics:= 0;
highest_status_level_for_diagnostics:= 100;
lowest_status_level_for_meds:= 0;
highest_status_level_for_meds:= 50;
// The duplicate checking flag for community results is as follows:
// Set this flag to TRUE to include resulted orders from community results in the evaluation.
// Set this flag to FALSE to exclude resulted orders from community results in the evaluation
enable_community_data_results_alerts := false;
// Set this flag to TRUE to match resulted orders from community results to
// the order name if the diagnostic order cannot be mapped to a catalog item.
// Set this flag to FALSE to match resulted orders from commmunity results only
// if the diagnostic order is mapped to a catalog item. (default)
enable_Diagnostic_Duplicate_Check_by_Community_Order_Name := false;
// Enter the text to differentiate resulted orders from community results in duplicate alerts:
// Set this flag to "Community" to include with the resulted order from community results
// data for MLM shown in brackets after the community data.
community_resultedOrder_alert_text := "Community";
/* Change the message within the quotes if a different short-message is needed.*/
duplicate_order_alert:= destination { Alert: warning,
"Duplicate Order", low, chart,
"HVC Duplicate", 1005, send_alert };
/* Change the spelling within the quotes to match the order item-catalog.*/
any_new_order:= event {OrderEnter User Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_new_patient_group_order:= event {OrderEnter Batch Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE
AND IsCreatedFromPatientGroupOrderTemplate = TRUE};
any_modified_order:= event {OrderModify User Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_released_order:= event {OrderRelease User Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_unsuspended_order:= event {OrderUnsuspend User Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_verified_order:= event {OrderVerify User Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
// --------------------------------------------------
// Outpatient Prescription and Home Medication Orders
//---------------------------------------------------
// Comment out below triggers to exclude checking all Outpatient Orders
// To include Home Medications remove the code {{{SINGLE-QUOTE}}}AND OrderAddtionalInfo.IsScript <> FALSE{{{SINGLE-QUOTE}}}
outpatient_order_entry_trigger := event {OutpatientOrderEnterNoIVAdditive User Order:
WHERE OrderAdditionalInfo.IsScript <> FALSE};
outpatient_order_modify_trigger := event {OutpatientOrderModify User Order:
WHERE OrderAdditionalInfo.IsScript <> FALSE};
/* Pharmacy Trigger Events */
any_OrderEnterPharmacyPerfect:= event {OrderEnterPharmacyPerfect Any Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_OrderModifyPharmacyPerfect:= event {OrderModifyPharmacyPerfect Any Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
any_OrderModifyPharmacy:= event {OrderModifyPharmacy Any Order:
WHERE OrderStatusLevelNum >= 0
AND OrderStatusLevelNum <= 50
AND OrderStatusCode <> "HOLD"
AND IsSuspended = FALSE };
/* Uncomment this section if you would like historical session type orders
to evoke this MLM, otherwise keep it commented out and this MLM will
ignore historical session type orders. If you uncomment this section make
sure to also uncomment the equivalent in the evoke clause.
order_alternate_enter_IV:= event{OrderAlternateEnterWithIVAdditive User Order:
where AlternateOrderType = 1};
order_alternate_enter_NOIV:= event{OrderAlternateEnterNoIVAdditive User Order:
where AlternateOrderType = 1};
order_alternate_modify:= event{OrderAlternateModify User Order:
where AlternateOrderType = 1
AND OrderStatusCode <> "HISE"
AND OrderStatusCode <> "HISI"}; */
// Set the list variables with the session types of existing orders against which
// the current order will be checked. The possible values for these variables are
// one or more types from the following list ("Discharge", "Inhouse", "Outpatient Rx", "Outpatient Hx", "Historical").
//
// The default setting is to check for duplicates between
// - current order entered during a discharge session type and existing discharge orders
// - current order entered during an in-house session type and existing in-house orders
// - current order entered during historical session type and existing historical orders
// - current outpatient orders entered and existing outpatient orders
at_discharge_session_list := ("Discharge");
at_in_house_session_list := ("Inhouse");
at_historical_session_list := ("Historical");
at_outpatient_session_list := ("Outpatient Rx", "Outpatient Hx");
/********************************************************************************/
/* Executes only when this MLM is called by the editor */
if called_by_editor then
/* Get current selected client visit in MLM Editor. */
(client_visit_guid,
current_visit) := read last {ClientVisit: GUID, This };
/* Search for example order in the current visit. */
EvokingObject:= read last
{Order: This
WHERE Name = "CBC" AND OrderStatusLevelNum > 40 };
endif;
/* Declares MLMs which can be called */
func_dup_message:= MLM {{{SINGLE-QUOTE}}}std_func_dup_messages{{{SINGLE-QUOTE}}};
func_check_for_duplicates:= MLM {{{SINGLE-QUOTE}}}std_func_dup_rules{{{SINGLE-QUOTE}}};
func_dup_actions := MLM {{{SINGLE-QUOTE}}}Std_Func_Dup_Actions{{{SINGLE-QUOTE}}};
/* Initialize variable */
continue_checking_order := true;
/* Set the order type to check */
complex_child_order_type := (2,4,6);
complex_master_order_type := (1,3,5);
regular_order_type := (NULL, 0);
/* Gets the Client GUID */
client_guid := read last {ClientInfo: GUID};
/* Gets information from the evoking Order */
(main_order_name,
evoking_object_guid,
order_status_code,
order_level_num,
order_summary_line,
main_item_catalog_guid,
order_catalog_master_item_obj,
chart_guid,
client_visit_guid,
order_significant_date,
order_requested_date,
order_entered_date,
order_stop_date,
order_is_conditional,
order_component_obj,
order_complex_type,
order_variable_component_obj,
order_is_for_discharge,
order_alternate_order_type,
evoking_order_additional_info,
back_up_obj) := read last
{Order: Name, GUID, OrderStatusCode, OrderStatusLevelNum, SummaryLine,
OrderCatalogMasterItemGUID, OrderCatalogMasterItem, ChartGUID,
ClientVisitGUID, SignificantDtm, RequestedDtm, Entered, StopDtm, IsConditional, OrderComponent,
ComplexOrderType, OrderVariableComponent, IsForDischarge, AlternateOrderType, OrderAdditionalInfo,
Backup REFERENCING EvokingObject};
(evoking_order_is_script) := read last {OrderAdditionalInfo: IsScript REFERENCING evoking_order_additional_info};
if exists EvokingObject
and (order_significant_date is null)
then
alert_if_initial_error := TRUE;
endif;
order_without_specific_stop_date := false;
if (order_alternate_order_type <> 2) //if not an outpatient order
then
// Get information about ongoing diagnostic order vs medication order
(order_without_specific_stop_date) := read last
{OrderCatalogMasterItem: IsOngoingOrder REFERENCING order_catalog_master_item_obj};
endif;
// This is a diagnostic like order
if order_without_specific_stop_date
then
/* 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
/* This is a child diagnositic order event continue check for modify, unsuspend... */
else
continue_checking_order := true;
endif; //if exists order_complex_type
else
/* This is a medication like order */
/* Check to see if this is a child order and if so stop processing as */
/* data will be alerted on at master order update */
if exists order_complex_type
and order_complex_type IS IN complex_child_order_type
then
continue_checking_order := false;
endif; //if exists order_complex_type
endif; //if order_without_specific_stop_date
// Determines if a modified order should be checked for duplicates
if EvokingEventType = any_modified_order.type
or EvokingEventType = any_OrderModifyPharmacy.type
or EvokingEventType = order_alternate_modify.type
or EvokingEventType = outpatient_order_modify_trigger.type
and continue_checking_order
then
if exist back_up_obj
then
(back_up_obj_signif_date,
back_up_obj_stop_date) := read last
{Order: SignificantDtm, StopDtm 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;
else
continue_checking_order := false;
endif;
else
continue_checking_order := false;
endif;
endif;
if continue_checking_order
then
/* Places the main-order on the lists to process */
order_list:= ,main_order_name;
cat_item_guid_list:= ,main_item_catalog_guid;
/* Only retrieves data if the Order has IV additives */
If exist order_component_obj
then
/* Gets the catalog item from the order component object */
(additive_cat_item_guid_list,
additive_name_list) := read
{ OrderComponent: OrderCatalogMasterItemGUID, Name
REFERENCING order_component_obj
where (Dosage AS Number) > 0 };
/* Places the additive information on the lists to process */
order_list:= order_list, additive_name_list;
cat_item_guid_list:= cat_item_guid_list, additive_cat_item_guid_list;
endif;
/* Gets the patient{{{SINGLE-QUOTE}}}s location group */
If called_by_editor
Then
/* Get visit information from the current selected visit in MLM Editor. */
patient_loc_group:= read last
{ ClientVisit: BusinessRuleLocationGUID
REFERENCING current_visit};
Else
patient_loc_group:= read last
{ ClientVisit: BusinessRuleLocationGUID };
Endif;
endif; /* continue_checking_order */
;;
evoke:
/* Uncomment this section if you would like historical session type orders
to evoke this mlm,otherwise keep it commented out.
If you uncomment this section please make sure to also uncomment the
equivalent event clauses
order_alternate_enter_IV OR
order_alternate_enter_NOIV OR
order_alternate_modify OR */
any_new_order;
any_new_patient_group_order;
any_modified_order;
any_released_order;
any_unsuspended_order;
any_verified_order;
outpatient_order_entry_trigger;
outpatient_order_modify_trigger;
any_OrderEnterPharmacyPerfect;
any_OrderModifyPharmacyPerfect;
any_OrderModifyPharmacy;
;;
logic:
If EvokingObject is NULL
then conclude false;
endif;
if alert_if_initial_error
then conclude true; /* generate an alert */
endif;
If NOT continue_checking_order
then conclude false;
endif;
/* Initialize variables */
indent:= " ";
dash_line:= "-----";
printable_alert_msg:= "";
index_list:= 1 SEQTO count(order_list);
/* Process the main order or the IV-additives */
for J in index_list do
order_name:= last(first J from order_list);
item_catalog_guid:= last(first J from cat_item_guid_list);
(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 ) := call func_check_for_duplicates with
(order_name,
evoking_object_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,
evoking_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,
EvokingObject,
EvokingEventType);
/*--------------------------------------------------------------*/
/* Calls an MLM to select the appropriate message and format it */
/*--------------------------------------------------------------*/
If exist matching_name_list
then
(order_status_msg,
alert_msg,
matching_short_message_list):= call func_dup_message with
(order_name,
order_status_code,
order_without_specific_stop_date,
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,
matching_name_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,
community_resultedOrder_alert_text);
/* Format date, removing milliseconds */
order_significant_date_formatted := order_significant_date formatted with "%.4t";
/* Create one long message to print */
printable_alert_msg:= printable_alert_msg || alert_msg;
endif; /* If exist matching_name_list */
enddo; /* for J */
/* Create a printable list of additives */
if exist additive_name_list
then
if count(additive_name_list) = 1
then additive_message:= indent || "IV-Additives: " || first (additive_name_list)|| "\n";
else additive_message:= indent || "IV-Additives: " || additive_name_list || "\n";
endif; /* if count */
else additive_message:= "";
endif; /* if exist additive_name_list */
/* Set the printable text for the order summary line */
if exist order_summary_line
then
summary_line:= dash_line || order_summary_line;
else
summary_line:= "";
endif; /* if exist order_summary_line */
/*-------------------------------*/
/* Create the Actions On Alerts */
/*-------------------------------*/
// Only create actions for alerts when the flag, generate_actions_on_alerts, is TRUE
// and the evoking object is a new order.
// Since the MLM Editor does NOT have an evoking trigger,
// Check that the EvokingEventType is a new order or the MLM is running the the MLM Editor
if generate_actions_on_alerts
AND exist alert_msg
AND (EvokingEventType = any_new_order.type or EvokingEventType = any_new_patient_group_order.type or Called_By_Editor)
then
// Correct the sort sequence of the SHORT MESSAGES.
// The MLM that created the messages places them in the wrong sequence.
/* Initialize */
matching_aoa_short_message_list := ();
position_list := 1 SEQTO count (matching_aoa_order_guid_list);
// Use the matching_aoa_order_guid_list to place them in the right sequence
for GG in position_list do
//Get the OrderGUID and the Duplicate{{{SINGLE-QUOTE}}}s Name (order name or additive name)
aoa_order_guid := matching_aoa_order_guid_list[GG];
aoa_order_name := matching_aoa_order_name_list[GG];
//Use the GUID and the NAME to find a matching position for a regular order
found_match := (matching_order_guid_list = aoa_order_guid
and matching_name_list = aoa_order_name);
//Use just the GUID to find a matching position for orders with IV Additives
If NOT ANY found_match
then found_match := matching_order_guid_list = aoa_order_guid;
endif;
//Match the position to get the short message
temp_message := first (matching_short_message_list where found_match);
//Put the short message in its correct order in the list
matching_aoa_short_message_list := matching_aoa_short_message_list, temp_message;
enddo; //for GG
// Call the MLM that Generates the Actions
alert_action_object_list := call func_dup_actions WITH
evoking_object_guid,
matching_aoa_action_item_status_list,
matching_aoa_order_guid_list,
matching_aoa_order_name_list,
matching_aoa_master_guid_list,
matching_aoa_short_message_list ;
// Set a flag to attach the alert to the destination when there are alert actions
if exist alert_action_object_list
then continue_action := True;
else continue_action := False;
endif; // if exist
endif; //if generate_actions_on_alerts
/*---------------*/
/* Clinical Rule */
/*---------------*/
If exist alert_msg
then conclude true;
endif;
;;
action:
current_order_alert_msg := "The current ";
if (order_alternate_order_type = 2)
then
if (evoking_order_is_script)
then
current_order_alert_msg := current_order_alert_msg || "prescription: \n";
order_status_msg := order_status_msg || " Prescription";
else
current_order_alert_msg := current_order_alert_msg || "home medication: \n";
order_status_msg := order_status_msg || " Home Medication";
endif;
else
current_order_alert_msg := current_order_alert_msg || "order: \n";
order_status_msg := order_status_msg || " Order";
endif;
if alert_if_initial_error
then
write "Your order for {{+B}}{{+C}}" || main_order_name
|| "{{-B}}{{-C}} was{{+B}}{{+R}} not checked for possible duplicates {{-B}}{{-R}}"
|| "with other patient medications."
|| " Please use an alternate plan to do the check."
|| " \n\nThis drug was not checked because it does not have a start date or a stop date."
at duplicate_order_alert;
else
write current_order_alert_msg
|| indent || main_order_name || summary_line || "\n"
|| indent || "Date: " || order_significant_date_formatted ||"\n"
|| indent || "Status: " || order_status_msg || "\n"
|| additive_message
|| "\n"
|| "May be duplicate with: \n\n"
|| printable_alert_msg
at duplicate_order_alert;
if continue_action
then attach alert_action_object_list to duplicate_order_alert;
endif;
endif;
;;
Urgency: 50;;
end:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
maintenance:
title: Duplicate Order Set Checking;;
mlmname: STD_DUPLICATE_ORDER_SET;;
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 Order Set Checking.
The checking will include:
1. Order sets of the same name or type within a pre-defined date range,
which will be varied by patient location.
2. Active order sets of the same type
;;
explanation: An Evoking-Order-Set is considered a duplicate of Other-Order-Sets when all of
the criteria listed below are met:
a. The evoking-order-set is a NEW order set
b. The evoking-order-set is not excluded from duplicate checking
(over-all or by patient location).
c. The order sets have identical Item Names (i.e.Catalog GUIDs),
or the other-order-set matches the Sets
listed in the evoking-order-set{{{SINGLE-QUOTE}}}s catalog duplicate-checking panel.
d. The other-order-sets are within the scoping rules for the patient location listed
in the evoking-order-set{{{SINGLE-QUOTE}}}s Duplicate 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.
Once a duplicate order set has been identified, selection of the appropriate message
is based on the defined MESSAGE TYPE in the catalog.
;;
keywords: Duplicate Order Set;
;;
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.*/
duplicate_order_set_alert:= destination { Alert: warning,
"Duplicate Order Set", low, chart,
"HVC Duplicate", 2005 };
/* Event statement does not require a change in this MLM.*/
any_new_order_set:= event {OrderSetEnter User OrderSet : where StartDtm is not null};
/********************************************************************************/
/* Executes only when this MLM is called by the editor */
if called_by_editor then
/* Get current selected client visit in MLM Editor. */
(client_visit_guid,
current_visit) := read last
{ClientVisit: GUID, This };
/* Search for example order set in the current visit. */
EvokingObject:= read last
{OrderSet: This
WHERE OrderSetName = "Joyce Linked Parent (w STD & linked)" AND ClientVisitGUID = client_visit_guid
};
endif;
/* Declares MLMs which can be called */
func_dup_message:= MLM {{{SINGLE-QUOTE}}}std_func_order_set_dup_messages{{{SINGLE-QUOTE}}};
func_check_for_duplicates:= MLM {{{SINGLE-QUOTE}}}std_func_order_set_dup_rules{{{SINGLE-QUOTE}}};
/* Gets the Client GUID */
client_guid := read last {ClientInfo: GUID};
/* Gets information from the evoking order set */
(order_set_name,
evoking_object_guid,
order_set_catalog_guid,
chart_guid,
client_visit_guid,
order_set_start_date ) := read last
{OrderSet: OrderSetName, GUID, OrderCatalogSetGUID,
ChartGUID, ClientVisitGUID, StartDtm
REFERENCING EvokingObject};
/* Gets the patient{{{SINGLE-QUOTE}}}s location group */
If called_by_editor
Then
/* Get visit information from the current selected visit in MLM Editor. */
patient_loc_group:= read last
{ ClientVisit: BusinessRuleLocationGUID
REFERENCING current_visit};
Else
patient_loc_group:= read last
{ ClientVisit: BusinessRuleLocationGUID };
Endif;
;;
evoke: any_new_order_set
;;
logic:
//----------------------------------------------------------------
// If there is no evoking object then do nothing, this can
// only be true for the MLM Editor
//----------------------------------------------------------------
If EvokingObject is NULL
then conclude false;
endif;
If NOT continue_checking_order_set
then conclude false;
endif;
/* Initialize variables */
indent:= " ";
dash_line:= "-----";
printable_alert_msg:= "";
/* Process the order_sets for duplicates */
(exact_msg,
performed_msg,
scheduled_msg,
exact_type,
subset_type,
superset_type,
same_set_type,
partial_match_type,
no_std_message_type,
matching_name_list,
matching_order_set_guid_list,
matching_start_date_list,
matching_msg_type_list,
matching_msg_text_list,
matching_time_msg_list,
matching_order_set_type_code_list ) := call func_check_for_duplicates with
(order_set_name,
evoking_object_guid,
order_set_catalog_guid,
chart_guid,
client_visit_guid,
order_set_start_date,
patient_loc_group);
/*--------------------------------------------------------------*/
/* Calls an MLM to select the appropriate message and format it */
/*--------------------------------------------------------------*/
If exist matching_name_list
then
(alert_msg,
matching_short_message_list):= call func_dup_message with
(order_set_name,
exact_msg,
performed_msg,
scheduled_msg,
exact_type,
subset_type,
superset_type,
same_set_type,
partial_match_type,
no_std_message_type,
matching_name_list,
matching_start_date_list,
matching_msg_type_list,
matching_msg_text_list,
matching_time_msg_list,
matching_order_set_type_code_list);
/* Format date, removing milliseconds */
order_set_start_date_formatted := order_set_start_date formatted with "%.4t";
/* Create one long message to print */
printable_alert_msg:= printable_alert_msg || alert_msg;
endif; /* If exist matching_name_list */
/*---------------*/
/* Clinical Rule */
/*---------------*/
If exist alert_msg
then conclude true;
endif;
;;
action:
write "The current Order Set: \n"
|| indent || order_set_name || "\n"
|| indent || "Date: " || order_set_start_date_formatted ||"\n"
|| "\n"
|| "May be duplicate with: \n\n"
|| printable_alert_msg
at duplicate_order_set_alert;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,627 @@
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:

View File

@@ -0,0 +1,209 @@
maintenance:
title: Second Alert Escalation via Email;;
mlmname: STD_ESCALATION_EMAIL;;
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: Notifies the Alert Center that the patient{{{SINGLE-QUOTE}}}s Care-Provider has NOT ACKNOWLEDGED
an urgent alert within the past 30 minutes.
;;
explanation:
This time-based MLM handles the second (final) phase of Alert Escalation through an Email.
It is triggered 30 minutes after the unacknowledged alert is stored into the database.
A facility designates which Care-Provider-Role will be paged when an Escalation alert
occurs. This designation is set using the "provider_role_string" variable in this MLM.
When the patient{{{SINGLE-QUOTE}}}s care-provider has not acknowledged the escalated-alert within
30 minutes of the page, an Email message is sent to the designated Alert Center,
where an alternate care-provider can be contacted by the people at the center.
The rule is as follows:
If an "Escalation" alert-type is stored into the database in an UNACKNOWLEDGED state,
and it remains unacknowledged after 30 minutes
then an Email message is sent to the Alert Center.
;;
keywords: Time-based; Escalation; Alert Escalation;;
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;
/* The Destination statment is located at the end of the data slot */
/* This is due to the use of a variable in the statement, that is set dynamically */
/* Escalation is a core-loaded Alert Type. */
/* Recommend that the spelling within the quotes not be modified */
unack_escalated_alert:= event {AlertEnter Any Alert:
where TypeCode= "Escalation" and Status = "Unack" };
/* Which Care-Provider should be contacted when there is an escalated-alert? */
/* Change the provider-role in quotes to match the one in the STD_ESCALATION_PAGER MLM */
/* In addition, the Role must exist in the Provider Role dictionary */
provider_role_string:= "Attending";
/* Where should the Email be sent when the alert remains Unacknowledged for 30 minutes? */
/* Change the email address in quotes */
/* Recommend that this message be sent to your facility{{{SINGLE-QUOTE}}}s designated Alert Center */
email_address:= "AlertCenter";
/****************************************************************************************/
/* Execute only when this MLM is called by the editor */
if called_by_editor then
obj := read last
{ Alert: THIS
WHERE TypeCode= "Escalation"
AND Status = "Unack" };
EvokingObject := obj;
endif;
/* Get the patient{{{SINGLE-QUOTE}}}s ID and Name */
(client_guid,
client_name) := read last {ClientInfo: GUID, Name};
/* Get information about the evoking alert */
(alert_type,
alert_status,
client_visit_guid,
short_alert_msg,
alert_guid,
alert_text,
alert_has_long_text ):= read last
{Alert: TypeCode, Status, ClientVisitGUID, Description, GUID,
PlainMessageText, HasLongText,
REFERENCING EvokingObject };
/* Continue processing when there is an Unacknowledged alert. */
/* It may be possible that someone has acknowledged the alert, */
/* before the time-based MLM could run */
if alert_status = "unack"
then
/* Get the patient{{{SINGLE-QUOTE}}}s location group (unit) */
(current_loc_name,
patient_loc_group_name ):= read last
{"SELECT cv.CurrentLocation, loc.Name "
|| " FROM CV3ClientVisit AS cv JOIN CV3Location AS loc"
|| " ON cv.CurrentLocationGUID = loc.GUID "
|| " WHERE cv.GUID = " || SQL(client_visit_guid)
|| " AND cv.Active = 1 "
|| " AND loc.Active = 1 " };
/* Retrieve the current (unexpired) Care Provider information for the patient */
/* Only one Care Provider with the designated Care-Provider-Role is retrieved */
/* If there are two or more in the database, then the older ones will be ignored */
(provider_role_code,
provider_status,
from_date,
to_date,
touched_when,
provider_name ):= read last
{"SELECT cpvr.RoleCode, cpvr.Status, fromDtm.TimeValue AS FromDtm, toDtm.TimeValue AS ToDtm, "
||" touchedWhen.TimeValue AS TouchedWhen, cp.DisplayName "
||" FROM CV3CareProviderVisitRole AS cpvr JOIN CV3CareProvider AS cp ON cpvr.ProviderGUID = cp.GUID "
||" INNER JOIN CV3ClientVisit cv ON cpvr.ClientVisitGUID = cv.GUID "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cpvr.ClientVisitGUID, cpvr.FromDtm) as fromDtm "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cpvr.ClientVisitGUID, cpvr.ToDtm) as toDtm "
||" CROSS APPLY dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, cpvr.TouchedWhen) touchedWhenLocal "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cv.GUID, touchedWhenLocal.LocalDate) touchedWhen "
||" WHERE cpvr.ClientVisitGUID = " || SQL(client_visit_guid)
||" AND cpvr.Status = {{{SINGLE-QUOTE}}}Active{{{SINGLE-QUOTE}}} "
||" AND cpvr.RoleCode = " || SQL(provider_role_string)
||" AND cpvr.FromDtm <= (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn()))) "
||" AND (ISNULL (cpvr.ToDtm, (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn())))) >= "
||" (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn()))))"
, PrimaryTime = TouchedWhen };
endif; /* if alert_status = "Unack" */
/*------------------------*/
/* DESTINATION STATEMENTS */
/*------------------------*/
/* Change the message within the quotes if a different short-message is needed.*/
/* Do not change the Alert Type to Escalation. This will cause an infinite-loop */
intermediate_alert:= destination { IntermediateMessage: warning,
"Escalation Alert", high, chart,
"HVC Saved Escalation Message", 1010 };
email_alert:= destination { email: warning, "Escalation Alert",
high, chart, email_address };
;;
evoke: 30 minutes after time of unack_escalated_alert
;;
logic:
/* Exit the MLM when the alert has already been acknowledged */
If alert_status <> "Unack"
then conclude false;
endif;
/*---------------*/
/* Clinical Rule */
/*---------------*/
If alert_status = "unack"
then conclude true;
endif;
;;
action:
/* Send message to email */
write "The "|| provider_role_code || " ( " ||provider_name || " ) "
|| "has not acknowledged an escalated-alert for the patient listed "
|| "below in the past 30 minutes. "
|| "Due to the urgency of the alert, please contact his/her alternate."
|| "\n\nPatient: " || client_name
|| "\nLocation: " || patient_loc_group_name
|| "\nAlert Title: " || short_alert_msg || " (full text below)"
|| "\n\n"
|| alert_text
at email_alert;
/* Keep a copy of the e-mail message */
/* Store it in the database as an intermediate message */
write "The "|| provider_role_code || " ( " ||provider_name || " ) "
|| "has not acknowledged an escalated-alert for the patient listed "
|| "below in the past 30 minutes. "
|| "Due to the urgency of the alert, please contact his/her alternate."
|| "\n\nPatient: " || client_name
|| "\nLocation: " || patient_loc_group_name
|| "\nAlert Title: " || short_alert_msg || " (full text below)"
|| "\n\n"
|| alert_text
at intermediate_alert;
;;
end:

View File

@@ -0,0 +1,288 @@
maintenance:
title: First Alert Escalation via Pager;;
mlmname: STD_ESCALATION_PAGER;;
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: Notifies the patient{{{SINGLE-QUOTE}}}s Care-Provider that an urgent alert has occurred.
;;
explanation:
This time-based MLM handles the first phase of Alert Escalation through a pager or email.
It is triggered zero minutes after the alert is stored into the database.
A facility designates which Care-Provider-Role will be paged when an Escalation alert
occurs. This designation is set using the "provider_role_string" variable in this MLM.
When the care-provider cannot be paged, an email message is sent to the
designated Alert Center, where the appropriate care-provider can be contacted
by the people at the Alert Center. The three rules are as follows:
1. If an "Escalation" alert-type is stored into the database in an UNACKNOWLEDGED state,
then the patient{{{SINGLE-QUOTE}}}s care-provider is contacted through an alpha-numeric pager.
2. When the patient{{{SINGLE-QUOTE}}}s care-provider does not have an alpha-numeric pager,
then an email message is sent to the Alert Center.
3. When the patient does not have a care-provider with a role that can receive the page,
then an email message is sent to the Alert Center.
;;
keywords: Time-based; Escalation; Alert Escalation;;
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;
/* The Destination statment is located at the end of the data slot */
/* This is due to the use of a variable in the statement, that is set dynamically */
/* Escalation is a core-loaded Alert Type. */
/* Recommend that the spelling within the quotes not be modified */
unack_escalated_alert:= event {AlertEnter Any Alert:
where TypeCode= "Escalation" and Status= "Unack"};
/* Change the spelling within the quotes to match a specific dictionary */
phone_type_string:= "Pager-AlphaNum"; /* Phone Type (alpha-numeric pager)*/
/* Which Care-Provider should be contacted when there is an escalated-alert? */
/* Change the provider-role in quotes to match a role in the Provider Role dictionary */
provider_role_string:= "Attending";
/* Where should the alert be sent if there is no pager? */
/* Change the email address in quotes */
/* Recommend that this message be sent to your facility{{{SINGLE-QUOTE}}}s designated Alert Center */
email_address:= "AlertCenter";
/* What is the long-distance country-code for your facility? */
/* In the USA and Canada, the code is 1 */
country_code:= 1;
/****************************************************************************************/
/* This block executes only when this MLM is called by the editor */
if called_by_editor then
obj := read last
{ Alert: THIS
WHERE TypeCode= "Escalation"
AND Status = "Unack" };
EvokingObject := obj;
endif;
/* Get the patient{{{SINGLE-QUOTE}}}s ID and Name */
(client_guid,
client_name) := read last {ClientInfo: GUID, Name};
/* Get information about the evoking alert */
(alert_type,
alert_status,
client_visit_guid,
short_alert_msg,
alert_guid,
alert_text,
alert_has_long_text ):= read last
{Alert: TypeCode, Status, ClientVisitGUID, Description, GUID,
PlainMessageText, HasLongText
REFERENCING EvokingObject };
/* Continue processing when there is an Unacknowledged alert. */
/* It is possible that someone may have acknowledged the alert */
/* before the time-based MLM could run */
if alert_status = "Unack"
then
/* Get the patient{{{SINGLE-QUOTE}}}s location group (unit) */
(current_loc_name,
patient_loc_group_name ):= read last
{"SELECT cv.CurrentLocation, loc.Name "
|| " FROM CV3ClientVisit AS cv JOIN CV3Location AS loc"
|| " ON cv.CurrentLocationGUID = loc.GUID "
|| " WHERE cv.GUID = " || SQL(client_visit_guid)
|| " AND cv.Active = 1 "
|| " AND loc.Active = 1 " };
/* Retrieve the current (unexpired) Care Provider for the patient */
/* and the provider{{{SINGLE-QUOTE}}}s current (unexpired) Pager and Pin number combination */
/* Only one pager and pin number combination is used. */
/* If there are two or more in the database, then the older ones will be ignored */
(provider_role_code_list,
provider_status_list,
from_date_list,
to_date_list,
active_phone_list,
phone_type_list,
area_code_list,
phone_and_pin_list,
touched_when_list,
provider_name_list ):= read
{"SELECT cpvr.RoleCode, cpvr.Status, fromDtm.TimeValue AS FromDtm, toDtm.TimeValue AS ToDtm, "
||" p.Active, p.PhoneType, p.AreaCode, p.PhoneNumber, "
||" touchedWhen.TimeValue AS TouchedWhen, cp.DisplayName"
||" FROM CV3CareProviderVisitRole AS cpvr JOIN CV3CareProvider AS cp "
||" ON cpvr.ProviderGUID = cp.GUID "
||" INNER JOIN CV3ClientVisit cv ON cpvr.ClientVisitGUID = cv.GUID "
||" LEFT OUTER JOIN CV3Phone AS p "
||" ON cpvr.ProviderGUID = p.PersonGUID"
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cpvr.ClientVisitGUID, cpvr.FromDtm) as fromDtm "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cpvr.ClientVisitGUID, cpvr.ToDtm) as toDtm "
||" CROSS APPLY dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, cpvr.TouchedWhen) touchedWhenLocal "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetForVisitTblFn(cv.GUID, touchedWhenLocal.LocalDate) touchedWhen "
||" WHERE cpvr.ClientVisitGUID = " || SQL(client_visit_guid)
||" AND cpvr.Status = {{{SINGLE-QUOTE}}}Active{{{SINGLE-QUOTE}}} "
||" AND cpvr.RoleCode = " || SQL(provider_role_string)
||" AND cpvr.FromDtm <= (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn()))) "
||" AND (ISNULL (cpvr.ToDtm, (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn())))) >= "
||" (SELECT TOP 1 LocalDate FROM dbo.SXADBConvertEnterpriseToLocalTblFn(cv.TimeZone, (SELECT CurDate FROM dbo.SXADBGetEnterpriseNowTblFn()))))"
, PrimaryTime = TouchedWhen };
/*-------------------------------------------------------*/
/* Find the AlphaNumeric Pager Number and Associated Info */
/*-------------------------------------------------------*/
/* Find the location of the phone_type in the phone type list */
found_phone_type := (phone_type_list = phone_type_string) AND (active_phone_list);
/* Get the most recent instance of the data if there is a pager */
/* using the location of the phone type in found_phone_type */
provider_role_code := last (provider_role_code_list where found_phone_type);
provider_status := last (provider_status_list where found_phone_type);
from_date := last (from_date_list where found_phone_type);
to_date := last (to_date_list where found_phone_type);
phone_type := last (phone_type_list where found_phone_type);
area_code := last (area_code_list where found_phone_type);
phone_and_pin := last (phone_and_pin_list where found_phone_type);
touched_when := last (touched_when_list where found_phone_type);
/* Get the provider name */
if exist provider_role_code
then /* The provider has an alpha-numeric pager */
/* Get the provider name associated with the PHONE_TYPE_STRING */
provider_name := last (provider_name_list where found_phone_type);
else /* The provider does not have an alpha-numeric pager */
/* So get the provider name and phone at the end of the lists, */
/* sorted by PrimaryTime (CV3Phone.TouchedWhen) */
provider_name := last (provider_name_list);
if last (active_phone_list) then
provider_phone := last (phone_and_pin_list);
else
provider_phone := "NOT ACTIVE";
endif; // last phone is active
endif; /* if exist provider_role_code */
endif; /* if alert_status = "Unack" */
/*-----------------------*/
/* Assemble Pager Number */
/*-----------------------*/
If exist country_code
and exist area_code
and exist phone_and_pin
then
pager_num_and_pin:= country_code || "-" || area_code || "-" || phone_and_pin;
endif; /* If exist country_code */
/*------------------------*/
/* DESTINATION STATEMENTS */
/*------------------------*/
/* Change the message within the quotes if a different short-message as needed.*/
/* Do not change the Alert Type to Escalation. This will cause an infinite loop */
intermediate_alert:= destination { IntermediateMessage: warning,
"Escalation Alert", high, chart,
"HVC Saved Escalation Message", 1005 };
/* There must be a Care Provider and a Pager with a pin number to send a page */
/* Otherwise, Email is sent to a facility{{{SINGLE-QUOTE}}}s designated Alert Center */
if exist provider_name and exist pager_num_and_pin
then
primary_alert:= destination { Pager: warning,
"Escalation Alert", high, chart, pager_num_and_pin };
else
primary_alert:= destination { Email: warning,
"Escalation Alert", high, chart, email_address };
endif;
;;
evoke: 0 minutes after time of unack_escalated_alert
;;
logic:
/* Exit the MLM when the alert has already been acknowledged */
If alert_status <> "Unack"
then conclude false;
endif;
/* Determine the content of the message */
If exist provider_name and exist pager_num_and_pin
then
alert_message:= client_name
|| " ("|| patient_loc_group_name || ") " || short_alert_msg;
phone_string := "\nPAGER number and pin: " ||pager_num_and_pin;
else
/* Create the top part of the message */
if exist provider_name
then
alert_message:= "A pager message could not be sent to the "
|| provider_role_string || " (" || provider_name || " )"
|| " because he or she does not have an alpha-numeric pager. "
|| " Please notify him or her that there is an escalated alert"
|| " regarding the following patient: " ;
phone_string := "\nPHONE number: " || provider_phone;
else
alert_message:= "A pager message could not be sent because the patient"
|| " does not have a care-provider assigned as "
|| provider_role_string
|| ". Please notify the appropriate person that there is an"
|| " escalated alert regarding the following patient: " ;
provider_name := "NO CARE PROVIDER ASSIGNED";
phone_string := "\nPHONE number: N/A";
endif; /* if exist provider_name */
/* Create the bottom part of the message */
alert_message:= alert_message
||"\n\nPatient: " || client_name
||"\nLocation: " || patient_loc_group_name
|| "\nAlert Title: " || short_alert_msg || " (full text below)"
||"\n\n"
|| alert_text;
endif; /* If exist provider_name... */
/*---------------*/
/* Clinical Rule */
/*---------------*/
If alert_status = "Unack"
then conclude true;
endif;
;;
action:
/* Send message to pager or email */
write alert_message
at primary_alert;
/* Keep a copy of the message and the care-provider{{{SINGLE-QUOTE}}}s ID */
/* Store it in the database as an intermediate message */
write provider_role_string || ": " ||provider_name
|| phone_string
|| "\n\n" || alert_message
at intermediate_alert;
;;
end:

View File

@@ -0,0 +1,326 @@
maintenance:
title: Fusion filtering criteria for importing community allergy data from dbMotion{{{SINGLE-QUOTE}}}s Client SDK.;;
mlmname: STD_FILTER_VPO_ALLERGIES;;
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: This standard MLM defines the filtering criteria for community allergies
when the respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure
only the minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported
by this MLM may be customized for the limited list of filtering criteria only:
(1) Last modified date/time to include (criteria: last_modified_from_dtm).
For allergy, we do not use this field.
ALWAYS set to NULL.
(2) Site defined Identifiers to exclude (criteria: rejected_id_list)
This criteria allows sites to specify a list of identifiers to exclude. These identifiers
can specify those records that have rejected by a Sunrise user if the record should
never be processed, or to exclude all those identifiers that are sent from a source
facility that is a non-trusted source.
Defined as a combined list of rejected identifiers from hard coded identifier list
and database identifier list.
Specify hard coded identifier list and/or database identifier list as conditions for
this criteria:
(a) Hard coded identifier list: specify identifiers formatted as <system OID>.<id>
- Specific all identifiers to be excluded, which can be a list of specific
identifiers, or as wildcard in the form of "<system OID>.%"
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233",
"1.3.6.1.4.1.22812.11.2014.1001.%",
"1.3.6.1.4.1.22812.11.2014.9876.%"
);
(b) Database identifier list: Retrieve community identifiers from database that are
rejected by users.
e.g.
database_id_list := read { "SELECT DISTINCT CommunityRecordID " ||
" FROM CV3AllergyDeclaration " ||
" WHERE " ||
" ClientGUID = " || SQL(client_guid) ||
" AND Status in ({{{SINGLE-QUOTE}}}Rejected{{{SINGLE-QUOTE}}}) "
(3) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 2 fields are supported for Allergies: Status Code, and Intolerance Value.
Specify one or both as conditions for the criteria:
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := false;
- Specify status_code_list formatted as <system OID>.<code> to include or
exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.14.cancelled"
);
After retrieving from dbMotion, only items with status code as one of the
following are processed by the Allergies Summary dialog:
o Active (2.16.840.1.113883.6.96.55561003, 2.16.840.1.113883.5.14.active),
o Final (2.16.840.1.113883.5.4.F), and
o Completed (2.16.840.1.113883.5.4.Completed)
o Cancelled (2.16.840.1.113883.5.14.Cancelled)
o Entered in Error (2.16.840.1.113883.6.96.185981001)
If sites want to filter by status code, specifying to include these status values
limit the amount of data returned from dbMotion.
(b) Intolerance Value (critiera: intolerance_value_include_values,
intolerance_value_list)
- Set intolerance_value_include_values to true to include records with the
listed valued in the returned result, and false to exclude them.
e.g. intolerance_value_include_values := false;
- Specify intolerance_value_list formatted as <system OID>.<code> to
include or exclude.
e.g. intolerance_value_list := (
"2.16.840.1.113883.6.96.409137002",
"2.16.840.1.113883.6.96.160244002",
"2.16.840.1.113883.6.96.429625007",
"2.16.840.1.113883.6.96.428607008"
);
Sites are recommended to filter out all the "No Known" indicators:
o No Known Drug Allergies (NKDA), expressed in SNOMED CT as
"2.16.840.1.113883.6.96.409137002"
o No Known Allergy (NKA), expressed in SNOMED CT as
"2.16.840.1.113883.6.96.160244002"
o No Known Food Allergies (NKFA), expressed in SNOMED CT as
"2.16.840.1.113883.6.96.429625007"
o No Known Environmental Allergies (NKEA), expressed in SNOMED CT as
"2.16.840.1.113883.6.96.428607008"
If there are specific RxNorm codes to be filtered, specify in the
intolerance_value_list with <system OID> as 2.16.840.1.113883.6.88, and
append with relevant RxNorm code in <code>. Similarly, specify UNII
codes to filter by setting <system OID> in intolerance_value_list as
"2.16.840.1.113883.4.9"
(4) Semantic Group filter (criteria: ExcludeMyEHRData, ExcludeSemanticGroup)
Sites will be able to indicate that only data records that are semantically different to be returned.
There are 2 fields to indicate what the filter should be.
(a) Exclude data that alreay exist in current EHR (criteria: ExcludeMyEHRData)
- Set ExcludeMyEHRData to true to filter out data that already exists in current EHR, and
false to include them.
Default: set value to True.
e.g. ExcludeMyEHRData := True;
(b) Exclude semantic equivalent data (criteria: ExcludeSemanticGroup)
- Set ExcludeSemanticGroup to true to filter out data that exists in current EHR based on
semantic similarity, and false to include them. For Allergies, data having same
group domain or same baseline code or local code are filtered out if set to true.
Default: set value to False.
e.g. ExcludeSemanticGroup := False;
;;
keywords: Fusion; Filter; Community Allergies
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded for ObjectsPlus
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time - not used for allergy
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list and set up default value
last_modified_from_dtm := null;
rejected_id_list := ();
hardcoded_id_list := ();
database_id_list := ();
//***************Make Changes To Spelling And Flags In This Section************
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// Semantic group filter
// Specify the flag to indicate whether to include or exclude the data that already exists in
// current EHR in criteria ExcludeMyEHRData.
// By default, if the entry is mising or value is set to false, no filterng will be performed and
// data from current EHR will also be returned.
// If entry is set to true, all data that already exists in current EHR are filtered.
//
ExcludeMyEHRData := true;
// Specify the flag to indicate whether to include or exclude the data that exists in current EHR
// based on semantic similarity in criteria ExcludeSemanticGroup.
// By default, if the entry is missing or value is set to false, no filterng will be performed and
// data that is semantically similar will also be returned.
// If entry is set to true, only the semantic delta list of data is returned.
ExcludeSemanticGroup := false;
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// Specify the list of Ids to exclude in rejected_id_list
// The ids can be hard coded, or fetched from the database
// or combination of both
// By default, the rejected id list is empty
/*
// comment this in to use hard coded list of ids
// specify the ids
hardcoded_id_list := ();
rejected_id_list := rejected_id_list, hardcoded_id_list;
*/
/*
// comment this in to use the ids from the database
// update the SQL to get the ids you want to exclude
database_id_list := read { "SELECT DISTINCT CommunityRecordID " ||
" FROM CV3AllergyDeclaration " ||
" WHERE " ||
" ClientGUID = " || SQL(client_guid) ||
" AND Status in ({{{SINGLE-QUOTE}}}Rejected{{{SINGLE-QUOTE}}}) "
};
rejected_id_list := rejected_id_list, database_id_list;
*/
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
status_code_include_values := false; // true include listed values in result, false exclude
status_code_list := (
"2.16.840.1.113883.5.14.cancelled", // cancelled
"2.16.840.1.113883.6.96.185981001" // entered-in-error
);
intolerance_value_include_values := false;
intolerance_value_list := ();
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
// Format the return value as time, so it can be read by the caller
if exists last_modified_from_dtm
then
last_modified_from_dtm := last_modified_from_dtm as time;
LastModifiedStartDateTime := last_modified_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
// Allergy only has onset (start) date, and no end date, so
// we cannot filter by active allergies using effective start time filter
EffectiveStartFromDateTime_Not_Used := null;
//
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list),
(new NameValueObject with "intoleranceValue", intolerance_value_include_values, intolerance_value_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
property_value_list := (
(new PropertyValueObject with "ExcludeMyEHRData", ExcludeMyEHRData),
(new PropertyValueObject with "ExcludeSemanticGroup", ExcludeSemanticGroup)
);
// Format the name value pairs into a .Net Dictionary
PropertyNameDictionary := call func_gen_property_dictionary with property_value_list;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
LastModifiedStartDateTime,
EffectiveStartFromDateTime_Not_Used,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,443 @@
maintenance:
title: ;;
mlmname: STD_FILTER_VPO_DOCUMENTLIST;;
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) 2017 - 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: This standard MLM defines the filtering criteria for community document list
when the respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure
only the minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported by this MLM may be customized
for the limited list of filtering criteria only:
(1) Document Create date/time to include (criteria: effective_start_from_dtm)
This criteria allows sites to include only documents that have been created since a specified
date/time to filter out any redundant data.
Specify any one of the following conditions:
(a) Document Create timestamp for Fusion Documents for the patient in context is
used to return only documents that were created since the specified date.
- Set value to db_last_modified_from_dtm.
e.g. effective_start_from_dtm := db_last_modified_from_dtm;
(b) Site specified date or time-offset: allows the site to override the default
behavior so that all data that have been modified since a specific date will be
provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. effective_start_from_dtm := "Jan 25 2014";
- Set value to arden date keyword
e.g. effective_start_from_dtm := now;
- Default: Set value to time offset in seconds/days/weeks/months/years ago
e.g. effective_start_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. effective_start_from_dtm := db_last_modified_from_dtm - 6 months
(c) Always return all data: allows sites to override the default behavior so that all
documents are provided in document list. Using this option can result in an impact
to performance.
- Set value to NULL.
(2) Source Object Identifiers to exclude (criteria: hardcoded_id_list)
This criteria allows sites to specify a list of object identifiers to exclude. These object
identifiers specifies source facilities that are non-trusted sources.
Hard coded identifier list: specify identifiers formatted as <system OID>! to exclude.
- Specific all object identifiers to be excluded with an exclaimation mark at the end
to indicate a source OID value.
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060!",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233!",
"1.3.6.1.4.1.22812.11.2014.1001!",
"1.3.6.1.4.1.22812.11.2014.9876!"
);
(3) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 4 fields are supported for Document List: Status Code, Completion Status, Document Type and Media Type.
Specify one or more as conditions for the criteria:
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := false;
- Specify status_code_list formatted as <system OID>.<code> to include
or exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.14.new",
"2.16.840.1.113883.5.14.suspended",
"2.16.840.1.113883.5.14.held",
"2.16.840.1.113883.5.14.aborted",
"2.16.840.1.113883.5.14.cancelled",
"2.16.840.1.113883.6.96.73425007",
"2.16.840.1.113883.6.96.185981001"
);
This example is configured to exclude the statuses with values new, suspended,
held, aborted, cancelled, and those with SNOMEDCT code 73425007 and 185981001.
(b) Completion Status (criteria: completionStatus_code_include_values, completionStatus_code_list)
- Set completionStatus_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. completionStatus_code_include_values := false;
- Specify completionStatus_list formatted as <system OID>.<code> to include
or exclude.
e.g. completionStatus_list := (
"2.16.840.1.113883.5.33.CA", /* canceled */
"2.16.840.1.113883.5.33.IN", /* incomplete */
"2.16.840.1.113883.5.33.CAN", /* canceled */
"2.16.840.1.113883.5.33.IP", /* in progress */
"2.16.840.1.113883.5.33.NU" /* nullified document */
);
This example is configured to exclude completion statuses CA, IN, CAN, IP and NU.
(c) Document Type (critiera: documentType_code_include_values, documentType_code_list)
- Set documentType_code_include_values to true to include records with the listed
valued in the returned result, and false to exclude them.
e.g. documentType_code_include_values := true;
- Specify documentType_code_list formatted as <system OID>.<code> to include or
exclude.
e.g. documentType_code_list := (
"2.16.840.1.113883.6.1.11334-0", /* History of growth+Development Narrative */
"2.16.840.1.113883.6.1.11488-4", /* Consult Note */
"2.16.840.1.113883.6.1.11502-2", /* Laboratory Report */
"2.16.840.1.113883.6.1.11504-8" /* Provider-unspecified Operation note */
);
(d) Media Type (critiera: mediaType_code_include_values, mediaType_code_list)
- Set mediaType_code_include_values to true to include records with the listed
valued in the returned result, and false to exclude them.
e.g. mediaType_code_include_values := false;
- Specify mediaType_code_list formatted as <system OID>.<code> to include or
exclude.
e.g. mediaType_code_list := (
"2.16.840.1.113883.5.79.application/rtf",
"2.16.840.1.113883.5.79.text/richtext"
);
This example is configured to exclude RTF documents and richtext documents.
Only the following media types are allowed:
- application/rtf
- text/richtext
- application/pdf
- text/plain
- text/html
- image/tiff
- image/jpeg
- image/png
- text/xml
;;
keywords: Fusion; Filter; Community Document List
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded for ObjectsPlus
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list and set up default value
last_modified_from_dtm := null;
rejected_id_list := ();
hardcoded_id_list := ();
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// By setting up this filter value, we retrieve documents that
// are active at this date. The document list contains documents that were created on or before
// the effective_start_from_dtm value will be eliminated.
// 1. By default, this value is set to 12 months ago
// 2. User specified
// - null to do no filtering by episode time from
// - string effective_start_from_dtm "Jan 25 2014"
// e.g. effective_start_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. effective_start_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. effective_start_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. effective_start_from_dtm := db_last_modified_from_dtm - 2 weeks;
// 3. Both last modified time and created time filter will be applied
effective_start_from_dtm := 12 months ago;
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
status_code_include_values := false; // true include listed values in result, false exclude
status_code_list := (
"2.16.840.1.113883.5.14.cancelled", // cancelled
"2.16.840.1.113883.5.14.aborted", // aborted
"2.16.840.1.113883.6.96.185981001" // entered-in-error
);
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
//
completionStatus_code_include_values := false; // true include listed values in result, false exclude
completionStatus_code_list := (
"2.16.840.1.113883.5.33.CA",
"2.16.840.1.113883.5.33.IN",
"2.16.840.1.113883.5.33.CAN",
"2.16.840.1.113883.5.33.IP",
"2.16.840.1.113883.5.33.NU"
);
documentType_code_include_values := true;
documentType_code_list := (
"2.16.840.1.113883.6.1.11334-0", /* History of growth+Development Narrative */
"2.16.840.1.113883.6.1.11488-4", /* Consult Note */
"2.16.840.1.113883.6.1.11502-2", /* Laboratory Report */
"2.16.840.1.113883.6.1.11504-8", /* Provider-unspecified Operation note */
"2.16.840.1.113883.6.1.11505-5", /* Physician procedure note */
"2.16.840.1.113883.6.1.11506-3", /* Provider-unspecified Progress note */
"2.16.840.1.113883.6.1.11522-0", /* Deprecated Cardiac echo study */
"2.16.840.1.113883.6.1.11526-1", /* Pathology study */
"2.16.840.1.113883.6.1.18736-9", /* Physician Initial evaluation note */
"2.16.840.1.113883.6.1.18737-7", /* Podiatry Initial evaluation note */
"2.16.840.1.113883.6.1.18744-3", /* Bronchoscopy study */
"2.16.840.1.113883.6.1.18748-4", /* Diagnostic imaging study */
"2.16.840.1.113883.6.1.18751-8", /* Endoscopy Study */
"2.16.840.1.113883.6.1.18752-6", /* Exercise stress test study */
"2.16.840.1.113883.6.1.18754-2", /* Holter monitor study */
"2.16.840.1.113883.6.1.18761-7", /* Provider-unspecified Transfer summary */
"2.16.840.1.113883.6.1.18836-7", /* Cardiac stress study Procedure */
"2.16.840.1.113883.6.1.18842-5", /* Discharge summary */
"2.16.840.1.113883.6.1.24537-3", /* US Guidance for removal of amniotic fluid from Uterus */
"2.16.840.1.113883.6.1.24757-7", /* Coronary arteries CT fast */
"2.16.840.1.113883.6.1.25002-7", /* Scrotum and testicle ultrasound */
"2.16.840.1.113883.6.1.27899-4", /* Diagnostic Imaging Report */
"2.16.840.1.113883.6.1.28570-0", /* Procedure note */
"2.16.840.1.113883.6.1.28624-5", /* Podiatry Operation note */
"2.16.840.1.113883.6.1.28636-9", /* Initial evaluation note */
"2.16.840.1.113883.6.1.29757-2", /* Colposcopy Study */
"2.16.840.1.113883.6.1.34095-0", /* Comprehensive history and physical note */
"2.16.840.1.113883.6.1.34098-4", /* Conference Note */
"2.16.840.1.113883.6.1.34105-7", /* Hospital Discharge Summary Report */
"2.16.840.1.113883.6.1.34117-2", /* History and Physical Note */
"2.16.840.1.113883.6.1.34121-4", /* Interventional procedure note */
"2.16.840.1.113883.6.1.34133-9", /* Summarization of episode note */
"2.16.840.1.113883.6.1.34138-8", /* Targeted history and physical note */
"2.16.840.1.113883.6.1.34856-5", /* Evaluation and management of anticoagulation note */
"2.16.840.1.113883.6.1.34859-9", /* Evaluation and management of hyperlipidemia */
"2.16.840.1.113883.6.1.34860-7", /* Evaluation and management of hypertension */
"2.16.840.1.113883.6.1.34868-0", /* Orthopaedic surgery Surgical operation note */
"2.16.840.1.113883.6.1.34875-5", /* Surgery Postoperative evaluation and management note */
"2.16.840.1.113883.6.1.34877-1", /* Urology Surgical operation note */
"2.16.840.1.113883.6.1.42348-3", /* Advance directives (narrative)*/
"2.16.840.1.113883.6.1.47040-1", /* Consultation 2nd opinion */
"2.16.840.1.113883.6.1.47045-0", /* Study report */
"2.16.840.1.113883.6.1.47046-8", /* Summary of death note */
"2.16.840.1.113883.6.1.47519-4", /* History of Procedures Document */
"2.16.840.1.113883.6.1.48765-2", /* Allergies and adverse reactions Document */
"2.16.840.1.113883.6.1.51847-2", /* Evaluation + Plan note */
"2.16.840.1.113883.6.1.51848-0", /* Evaluation Note */
"2.16.840.1.113883.6.1.51849-8", /* Admission history and physical note */
"2.16.840.1.113883.6.1.51898-5", /* Risk factors Document */
"2.16.840.1.113883.6.1.53242-4", /* Charge ticket or encounter form */
"2.16.840.1.113883.6.1.55109-3", /* Complications Document */
"2.16.840.1.113883.6.1.55112-7", /* Document summary */
"2.16.840.1.113883.6.1.56444-3", /* Healthcare communication Doc */
"2.16.840.1.113883.6.1.55112-7", /* Document summary */
"2.16.840.1.113883.6.1.56445-0", /* Medication summary Document */
"2.16.840.1.113883.6.1.56446-8", /* Appointment summary Document */
"2.16.840.1.113883.6.1.56447-6", /* Plan of care note */
"2.16.840.1.113883.6.1.57055-6", /* Antepartum summary */
"2.16.840.1.113883.6.1.57056-4", /* Labor and delivery admission history and physical */
"2.16.840.1.113883.6.1.57057-2", /* Labor and Delivery summary note */
"2.16.840.1.113883.6.1.57058-0", /* Maternal Discharge Summary */
"2.16.840.1.113883.6.1.57059-8", /* Pregnancy visit summary note Narrative */
"2.16.840.1.113883.6.1.57133-1", /* Referral note */
"2.16.840.1.113883.6.1.57828-6", /* Prescription List */
"2.16.840.1.113883.6.1.57833-6", /* Prescription for medication */
"2.16.840.1.113883.6.1.59268-3", /* Neonatal care report */
"2.16.840.1.113883.6.1.59282-4", /* Stress cardiac echo study report US */
"2.16.840.1.113883.6.1.59283-2", /* Well child visit note */
"2.16.840.1.113883.6.1.60591-5", /* Patient summary Document */
"2.16.840.1.113883.6.1.64290-0", /* Health insurance card */
"2.16.840.1.113883.6.1.66113-2", /* Uterus Pathology biopsy report */
"2.16.840.1.113883.6.1.66117-3", /* Prostate Pathology biopsy report */
"2.16.840.1.113883.6.1.67851-6", /* Admission evaluation note */
"2.16.840.1.113883.6.1.67853-2", /* Plan of care note */
"2.16.840.1.113883.6.1.67860-7", /* Post-operative evaluation and management note */
"2.16.840.1.113883.6.1.67862-3", /* Pre-operative evaluation and management note */
"2.16.840.1.113883.6.1.68563-6", /* Obstetrics and Gynecology procedure note */
"2.16.840.1.113883.6.1.68607-1", /* Progress letter */
"2.16.840.1.113883.6.1.68608-9", /* Summarization note */
"2.16.840.1.113883.6.1.74188-4", /* interRAI Acute Care (AC) Hospital Document */
"2.16.840.1.113883.6.1.75477-0", /* Physician resident Note */
"2.16.840.1.113883.6.1.77962-9" /* Obstetrics and Gynecology Summary */
);
// Hard coded identifier list: specify identifiers formatted as <system OID>.<ID>
// if the <system OID> ends with an ! then any document from that OID will be filtered out.
//
// This list should contain at minimum the myEHR OID. Use the format "<myEHR OID>!".
//
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
//
hardcoded_id_list := (
//"1.3.6.1.4.1.22812.4.545.6.1.19.Note_8480", // An exact match against system OID.Document ID
//"1.3.6.1.4.1.22812.4.545.6.1!" // An exact match against system OID only.
);
rejected_id_list := rejected_id_list, hardcoded_id_list;
// Field Name and Value List are used to specify if values are to be included or excluded.
// This criteria allows sites to specify a field name, along with a list of eligible values.
// All data values matching the specified value list will be included or excluded as defined.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
//
mediaType_code_include_values := false; // Set mediaType_code_include_values to true to include only the list of documents and false to exclude them
mediaType_code_list := (
//"2.16.840.1.113883.5.79.application/rtf",
//"2.16.840.1.113883.5.79.text/richtext",
//"2.16.840.1.113883.5.79.application/pdf"
);
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
// Format the return value as time, so it can be read by the caller
//
if exists last_modified_from_dtm
then
last_modified_from_dtm := last_modified_from_dtm as time;
LastModifiedStartDateTime := last_modified_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
if exists effective_start_from_dtm
then
effective_start_from_dtm := effective_start_from_dtm as time;
EffectiveStartFromDateTime := effective_start_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list),
(new NameValueObject with "documentCompletionCode", completionStatus_code_include_values, completionStatus_code_list ),
(new NameValueObject with "documentTypeCode", documentType_code_include_values, documentType_code_list),
(new NameValueObject with "mediaTypeCode", mediaType_code_include_values, mediaType_code_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
// MyEHR and SemanticGroup are not supported for documents, so leave false.
property_value_list := (
(new PropertyValueObject with "ExcludeMyEHRData", false),
(new PropertyValueObject with "ExcludeSemanticGroup", false)
);
// Format the name value pairs into a .Net Dictionary
PropertyNameDictionary := call func_gen_property_dictionary with property_value_list;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
LastModifiedStartDateTime,
EffectiveStartFromDateTime,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,402 @@
maintenance:
title: Fused Agent filter for importing community health issue data;;
mlmname: STD_FILTER_VPO_HEALTH_ISSUES;;
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: This standard MLM defines the filtering criteria for community health issues when the
respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure only the
minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported by this MLM may be customized
for the limited list of filtering criteria only:
(1) Last modified date/time to include (criteria: last_modified_from_dtm)
This criteria allows sites to include only data that has been changed since a
specified date/time to filter out any redundant data. Specify any one of the
following conditions:
(a) Last updated timestamp stored in SXACommunityDataStatus for
health issues data for the patient in context is used to return only data that
has been changed since the last successful request will be returned.
- Set value to db_last_modified_from_dtm.
e.g. last_modified_from_dtm := db_last_modified_from_dtm;
(b) Site specified date or time-offset: allows the site to override the default
behavior so that all data that have been modified since a specific date will be
provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. last_modified_from_dtm := "Jan 25 2014";
- Set value to arden date keyword
e.g. last_modified_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. last_modified_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. last_modified_from_dtm := db_last_modified_from_dtm -
6 months
(c) Default: Always return all data: allows sites to override the default behavior so that all
data is provided for reprocessing. This can be useful when processing of
previously filtered data is required. Using this option can result in an impact
to performance. (Recommended to ensure all data after Patient Merge are returned in VPO)
- Set value to NULL.
(2) Effective date to include (criteria: effective_start_from_dtm)
This criteria allows sites to include only health issues that are active after the
specified date. This will return all those health issues that are active before this
date and resolved after this date, and active after this date which may/may not
be resolved. Any health issues that are resolved on or before the specified date
will be excluded.
When the condition is specified, if a health issue has either the onset date or a
resolved date, then the date is used to determine if the health issue is active on the
specified date. A health issue is always included if neither onset date nor
resolved date is valued.
(a) Default: set value to NULL to indicate no filtering is required, and all items are
eligible.
(d) Site specified date or time-offset: allows set to override the default behavior
so that all data that are active after a specific date will be provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. effective_start_from_dtm := "Jan 01 2014";
- Set value to arden date keyword
e.g. effective_start_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. effective_start_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. effective_start_from_dtm := db_last_modified_from_dtm -
6 months
(3) Site defined Identifiers to exclude (criteria: rejected_id_list)
This criteria allows sites to specify a list of identifiers to exclude. These identifiers
can specify those records that have rejected by a Sunrise user if the record
should never be processed, or to exclude all those identifiers that are sent from
a source facility that is a non-trusted source, and to exclude all those identifiers
that are sent from the current site or facility.
Defined as a combined list of rejected identifiers from hard coded identifier list
and database identifier list.
Specify hard coded identifier list and/or database identifier list as conditions for
this criteria:
(a) Hard coded identifier list: specify identifiers formatted as <system OID>.<id>
- Specific all identifiers to be excluded, which can be a list of specific
identifiers, or as wildcard in the form of "<system OID>.%".
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233",
"1.3.6.1.4.1.22812.11.2014.1001.%",
"1.3.6.1.4.1.22812.11.2014.9876.%"
);
(b) Database identifier list: Retrieve community identifiers from database that
are rejected by users.
e.g.
database_id_list := read { "SELECT DISTINCT CommunityRecordID " ||
" FROM CV3HealthIssueDeclaration " ||
" WHERE " ||
" ClientGUID = " || SQL(client_guid) ||
" AND InternalStateType = 2 }"
(4) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 2 fields are supported for Health Issues: Status Code, and Observation Value.
Specify one or both as conditions for the criteria:
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := false;
- Specify status_code_list formatted as <system OID>.<code> to include
or exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.14.cancelled",
"2.16.840.1.113883.6.96.73425007",
"2.16.840.1.113883.6.96.103330002"
);
This example is configured to exclude all those statuses that are
identified as cancelled, inactive (SNOMED CT 73425007), or no diagnosis
(SNOMED CT 103330002).
(b) Observation Value (critiera: observation_include_values, observation_list)
- Set observation _include_values to true to include records with the listed
valued in the returned result, and false to exclude them.
e.g. observation_include_values := false;
- Specify observation_list formatted as <system OID>.<code> to include or
exclude.
e.g. observation_list := (
"2.16.840.1.113883.6.103.V%",
"2.16.840.1.113883.6.96.160245001",
);
This example is configured to exclude:
o Routine examinations expressed in ICD-9 for all the diagnosis
codes that start with V.
o No Known Health Problems expressed in SNOMED CT as
"2.16.840.1.113883.6.96.160245001"
If there are specific ICD-9 codes to be filtered, specify in the
observation_list with <system OID> as 2.16.840.1.113883.6.103, and
append with relevant ICD-9 code in <code>. Similarly, specify ICD-10
codes to filter by setting <system OID> in observantion_list as
2.16.840.1.113883.6.90, and SNOMED CT codes as 2.16.840.1.113883.6.96.
Filtering by specific coding system/code will only apply if the coding
system/code pair is available from VPO. As in example above, the
filtering condition "2.16.840.1.113883.6.103.V%" will only apply if VPO has
returned matching values. Using this condition can result in an impact to
performance.
(5) Semantic Group filter (criteria: ExcludeMyEHRData, ExcludeSemanticGroup)
Sites will be able to indicate that only data records that are semantically different to be returned.
There are 2 fields to indicate what the filter should be.
(a) Exclude data that alreay exist in current EHR (criteria: ExcludeMyEHRData)
- Set ExcludeMyEHRData to true to filter out data that already exists in current EHR, and
false to include them.
Default: set value to True.
e.g. ExcludeMyEHRData := True;
(b) Exclude semantic equivalent data (criteria: ExcludeSemanticGroup)
- Set ExcludeSemanticGroup to true to filter out data that exists in current EHR based on
semantic similarity, and false to include them. For Allergies, data having same
group domain or same baseline code or local code are filtered out if set to true.
Default: set value to False.
e.g. ExcludeSemanticGroup := False;
;;
keywords: Fusion; Filter; Community Health Issues
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded for ObjectsPlus
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list and set up default value
last_modified_from_dtm := db_last_modified_from_dtm;
rejected_id_list := ();
hardcoded_id_list := ();
database_id_list := ();
//***************Make Changes To Spelling And Flags In This Section************
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// Last Modified from dtm
// 1. By Default, value is set to NULL so that no filtering will be
// done based on last modified and all the data will come back.
// 2. User specified
// - set to db_last_modified_from_dtm to use the last successful
// retrieval timestamp
// - string date time "Jan 25 2014"
// e.g. last_modified_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. last_modified_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. last_modified_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. last_modified_from_dtm := db_last_modified_from_dtm - 2 weeks;
last_modified_from_dtm := NULL;
// Semantic group filter
// Specify the flag to indicate whether to include or exclude the data that already exists in
// current EHR in criteria ExcludeMyEHRData.
// By default, if the entry is mising or value is set to false, no filterng will be performed and
// data from current EHR will also be returned.
// If entry is set to true, all data that already exists in current EHR are filtered.
//
ExcludeMyEHRData := true;
// Specify the flag to indicate whether to include or exclude the data that exists in current EHR
// based on semantic similarity in criteria ExcludeSemanticGroup.
// By default, if the entry is missing or value is set to false, no filterng will be performed and
// data that is semantically similar will also be returned.
// If entry is set to true, only the semantic delta list of data is returned.
ExcludeSemanticGroup := false;
// By setting up this filter value, we retrieve health issues that
// are active at this date. Active means not having an end date, or end date
// is after the given effective start from dtm
// The health issues that are completed on or before
// the effective_start_from_dtm value will be eliminated.
// This is episode time from time
// 1. By default, this value is set to null to do no filtering by episode time from
// 2. User specified
// - string effective_start_from_dtm "Jan 25 2014"
// e.g. effective_start_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. effective_start_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. effective_start_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. effective_start_from_dtm := db_last_modified_from_dtm - 2 weeks;
// 3. Note if the health issue does not have an episode time, and the episode time
// filter is specified, it brings all the health issue without episode time
// 4. Both last modified time and episode time filter will be applied
effective_start_from_dtm := null;
// Specify the list of Ids to exclude in rejected_id_list
// The ids can be hard coded, or fetched from the database
// or combination of both
// By default, the rejected id list is empty
/*
// comment this in to use hard coded list of ids
// specify the ids
hardcoded_id_list := ();
rejected_id_list := rejected_id_list, hardcoded_id_list;
*/
/*
// comment this in to use the ids from the database
// update the SQL to get the ids you want to exclude
database_id_list := read { "SELECT DISTINCT CommunityRecordID " ||
" FROM CV3HealthIssueDeclaration " ||
" WHERE " ||
" ClientGUID = " || SQL(client_guid) ||
" AND InternalStateType = 2" // InternalStateType=2 means rejected community health issue
};
rejected_id_list := rejected_id_list, database_id_list;
*/
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values,
// and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered
// as specified
status_code_include_values := false; // true include listed values in result, false exclude
status_code_list := (
"2.16.840.1.113883.5.14.cancelled" // cancelled
);
observation_include_values := true;
observation_list := ();
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
// Format the return value as time, so it can be read by the caller
if exists last_modified_from_dtm
then
last_modified_from_dtm := last_modified_from_dtm as time;
LastModifiedStartDateTime := last_modified_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
if exists effective_start_from_dtm
then
effective_start_from_dtm := effective_start_from_dtm as time;
EffectiveStartFromDateTime := effective_start_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
//
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list),
(new NameValueObject with "observation", observation_include_values, observation_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
property_value_list := (
(new PropertyValueObject with "ExcludeMyEHRData", ExcludeMyEHRData),
(new PropertyValueObject with "ExcludeSemanticGroup", ExcludeSemanticGroup)
);
// Format the name value pairs into a .Net Dictionary
PropertyNameDictionary := call func_gen_property_dictionary with property_value_list;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
LastModifiedStartDateTime,
EffectiveStartFromDateTime,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,321 @@
maintenance:
title: Fused Agent filter for importing community Immunizations data;;
mlmname: STD_FILTER_VPO_IMMUNIZATIONS;;
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: This standard MLM defines the filtering criteria for community immunizations when the
respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure only the
minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported by this MLM may be customized for the limited list of filtering criteria only:
(1) Last modified date/time to include (criteria: last_modified_from_dtm)
This criteria allows sites to include only data that has been changed since a
specified date/time to filter out any redundant data. Specify any one of the
following conditions:
(a) Last updated timestamp stored in SXACommunityDataStatus for
immunization data for the patient in context is used to return only data that
has been changed since the last successful request will be returned.
- Set value to db_last_modified_from_dtm.
e.g. last_modified_from_dtm := db_last_modified_from_dtm;
(b) Site specified date or time-offset: allows the site to override the default
behavior so that all data that have been modified since a specific date will be
provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. last_modified_from_dtm := "Jan 25 2014";
- Set value to arden date keyword
e.g. last_modified_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. last_modified_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. last_modified_from_dtm := db_last_modified_from_dtm -
6 months
(c) Default: Always return all data: allows sites to override the default behavior so that all
data is provided for reprocessing. This can be useful when processing of
previously filtered data is required. Using this option can result in an impact
to performance. (Recommended to ensure all data after Patient Merge are returned in VPO)
- Set value to NULL.
(2) Site defined Identifiers to exclude (criteria: rejected_id_list)
This criteria allows sites to specify a list of identifiers to exclude. These identifiers
can specify those records that have been processed by a Sunrise user and so no
updates would be presented, or to exclude all those
identifiers that are sent from a source facility that is a non-trusted source.
Defined as a combined list of rejected identifiers from hard coded identifier list
and database identifier list.
Specify hard coded identifier list and/or database identifier list as conditions for
this criteria:
(a) Hard coded identifier list: specify identifiers formatted as <system OID>.<id>
- Specific all identifiers to be excluded, which can be a list of specific
identifiers, or as wildcard in the form of "<system OID>.%".
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233",
"1.3.6.1.4.1.22812.11.2014.1001.%",
"1.3.6.1.4.1.22812.11.2014.9876.%"
);
(b) Database identifier list: Retrieve community identifiers from database that
are already accepted by users, and so updates will not be allowed.
e.g.
database_id_list := read = { "SELECT DISTINCT CommunityRecordID " ||
" FROM SXAHMScheduledEventOccurrence " ||
" WHERE ClientGUID = " || SQL(client_guid) ||
" AND OccurrenceStatusType NOT in (5,6,9,10) " ||
" AND CommunityRecordID IS NOT NULL"
};
(3) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 1 field is supported for Immunizations: Status Code.
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := false;
- Specify status_code_list formatted as <system OID>.<code> to include
or exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.14.cancelled",
"2.16.840.1.113883.6.96.185981001" // entered-in-error
);
This example is configured to exclude all those statuses that are
identified as cancelled or completed or with the EIE SNOMEDCT code.
(4) Semantic Group filter (criteria: ExcludeMyEHRData, ExcludeSemanticGroup)
Sites will be able to indicate that only data records that are semantically different to be returned.
There are 2 fields to indicate what the filter should be.
(a) Exclude data that already exist in current EHR (criteria: ExcludeMyEHRData)
- Set ExcludeMyEHRData to true to filter out data that already exists in current EHR, and
false to include them.
Default: set value to True.
e.g. ExcludeMyEHRData := True;
(b) Exclude semantic equivalent data (criteria: ExcludeSemanticGroup)
- Set ExcludeSemanticGroup to true to filter out data that exists in current EHR based on
semantic similarity, and false to include them. For Immuizations, data having same
effective date and same material baseline code or local code are filtered out if set to true.
Default: set value to False.
e.g. ExcludeSemanticGroup := False;
;;
keywords: Fusion; Filter; Community Immunizations
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded for ObjectsPlus
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Set the default last modified value
last_modified_from_dtm := db_last_modified_from_dtm;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list
rejected_id_list := ();
hardcoded_id_list := ();
database_id_list := ();
//***************Make Changes To Spelling And Flags In This Section************
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// Semantic group filter
// Specify the flag to indicate whether to include or exclude the data that already exists in
// current EHR in criteria ExcludeMyEHRData.
// By default, if the entry is missing or value is set to false, no filtering will be performed and
// data from current EHR will also be returned.
// If entry is set to true, all data that already exists in current EHR are filtered.
ExcludeMyEHRData := true;
// Specify the flag to indicate whether to include or exclude the data that exists in current EHR
// based on semantic similarity in criteria ExcludeSemanticGroup.
// By default, if the entry is missing or value is set to false, no filtering will be performed and
// data that is semantically similar will also be returned.
// If entry is set to true, only the semantic delta list of data is returned.
ExcludeSemanticGroup := false;
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// Last Modified from dtm
// 1. By Default, value is set to NULL so that no filtering will be
// done based on last modified and all the data will come back.
// 2. User specified
// - set to db_last_modified_from_dtm to use the last successful
// retrieval timestamp
// - string date time "Jan 25 2014"
// e.g. last_modified_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. last_modified_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. last_modified_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. last_modified_from_dtm := db_last_modified_from_dtm - 2 weeks;
last_modified_from_dtm := NULL;
// Specify the list of Ids to exclude in rejected_id_list
// The ids can be hard coded, or fetched from the database
// or combination of both
// By default, the rejected id list is empty
/*
// comment this in to use hard coded list of ids
// specify the ids
hardcoded_id_list := ();
rejected_id_list := rejected_id_list, hardcoded_id_list;
*/
/*
// comment this in to use the ids from the database
// update the SQL to get the ids you want to exclude
database_id_list := read { "SELECT DISTINCT CommunityRecordID " ||
" FROM SXAHMScheduledEventOccurrence " ||
" WHERE ClientGUID = " || SQL(client_guid) ||
" AND OccurrenceStatusType NOT in (5,6,9,10) " ||
" AND CommunityRecordID IS NOT NULL"
};
rejected_id_list := rejected_id_list, database_id_list;
*/
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
status_code_include_values := false; // true include listed values in result, false exclude
status_code_list := (
"2.16.840.1.113883.5.14.cancelled", // cancelled
"2.16.840.1.113883.6.96.185981001" // entered-in-error
);
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
// Format the return value as time, so it can be read by the caller
if exists last_modified_from_dtm
then
last_modified_from_dtm := last_modified_from_dtm as time;
LastModifiedStartDateTime := last_modified_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
// Immunization only has performed date, and no end date, so
// we cannot filter by active immunizations using effective start time filter
EffectiveStartFromDateTime_Not_Used := null;
// Only the statusCode field is supported for Immunizations
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
property_value_list := (
(new PropertyValueObject with "ExcludeMyEHRData", ExcludeMyEHRData),
(new PropertyValueObject with "ExcludeSemanticGroup", ExcludeSemanticGroup)
);
// Format the name value pairs into a .Net Dictionary
PropertyNameDictionary := call func_gen_property_dictionary with property_value_list;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
LastModifiedStartDateTime,
EffectiveStartFromDateTime_Not_Used,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,370 @@
maintenance:
title: Fused Agent filter for importing community Medications data;;
mlmname: STD_FILTER_VPO_MEDICATIONS;;
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: This standard MLM defines the filtering criteria for community medications when the
respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure only the
minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported by this MLM may be customized for the limited list of filtering criteria only:
(1) Last modified date/time to include (criteria: last_modified_from_dtm)
This criteria allows sites to include only data that has been changed since a
specified date/time to filter out any redundant data. Specify any one of the
following conditions:
(a) Last updated timestamp stored in SXACommunityDataStatus for
health issues data for the patient in context is used to return only data that
has been changed since the last successful request will be returned.
- Set value to db_last_modified_from_dtm.
e.g. last_modified_from_dtm := db_last_modified_from_dtm;
(b) Site specified date or time-offset: allows the site to override the default
behavior so that all data that have been modified since a specific date will be
provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. last_modified_from_dtm := "Jan 25 2014";
- Set value to arden date keyword
e.g. last_modified_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. last_modified_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. last_modified_from_dtm := db_last_modified_from_dtm -
6 months
(c) Default: Always return all data: allows sites to override the default behavior so that all
data is provided for reprocessing. This can be useful when processing of
previously filtered data is required. Using this option can result in an impact
to performance. (Recommended to ensure all data after Patient Merge are returned in VPO)
- Set value to NULL.
(2) Effective date to include (criteria: effective_start_from_dtm)
This criteria allows sites to include only medications that are active after the
specified date. This will return all those medications that are active before this
date and resolved after this date, and active after this date which may/may not
be completed. Any medications that are completed on or before the specified
date will be excluded.
When the condition is specified, if a medication has either the start date or an
end date, then the date is used to determine if the medication is active on the
specified date. A medication is always included if neither start date nor end date
is valued.
(a) Set value to NULL to indicate no filtering is required, and all items are
eligible.
(d) Site specified date or time-offset: allows set to override the default behavior
so that all data that are active after a specific date will be provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. effective_start_from_dtm := "Jan 01 2014";
- Set value to arden date keyword
e.g. effective_start_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. effective_start_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. effective_start_from_dtm := db_last_modified_from_dtm -
6 months
(3) Site defined Identifiers to exclude (criteria: rejected_id_list)
This criteria allows sites to specify a list of identifiers to exclude. These identifiers
can specify those records that have been processed by a Sunrise user and so no
updates would be presented, or to exclude all those
identifiers that are sent from a source facility that is a non-trusted source.
Defined as a combined list of rejected identifiers from hard coded identifier list
and database identifier list.
Specify hard coded identifier list and/or database identifier list as conditions for
this criteria:
(a) Hard coded identifier list: specify identifiers formatted as <system OID>.<id>
- Specific all identifiers to be excluded, which can be a list of specific
identifiers, or as wildcard in the form of "<system OID>.%".
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233",
"1.3.6.1.4.1.22812.11.2014.1001.%",
"1.3.6.1.4.1.22812.11.2014.9876.%"
);
(b) Database identifier list: Retrieve community identifiers from database that
are already accepted by users, and so updates will not be allowed.
e.g.
database_id_list := read = { "SELECT DISTINCT Dtl.CommunityMedID " ||
" FROM SXAAMBeRxDispensedDetail Dtl " ||
" INNER JOIN SXAAMBeRxDispensedHeader Hdr " ||
" ON Hdr.DispensedHeaderID = Dtl.DispensedHeaderID " ||
" WHERE " ||
" Hdr.ClientGUID = " || SQL(client_guid) ||
" AND Dtl.StatusType in (1, 2) "
};
(4) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 1 field is supported for Medications: Status Code.
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := false;
- Specify status_code_list formatted as <system OID>.<code> to include
or exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.14.cancelled",
"2.16.840.1.113883.5.14.completed"
);
This example is configured to exclude all those statuses that are
identified as cancelled or completed.
(5) Semantic Group filter (criteria: ExcludeMyEHRData, ExcludeSemanticGroup)
Sites will be able to indicate that only data records that are semantically different to be returned.
There are 2 fields to indicate what the filter should be.
(a) Exclude data that already exist in current EHR (criteria: ExcludeMyEHRData)
- Set ExcludeMyEHRData to true to filter out data that already exists in current EHR, and
false to include them.
Default: set value to True.
e.g. ExcludeMyEHRData := True;
(b) Exclude semantic equivalent data (criteria: ExcludeSemanticGroup)
- Set ExcludeSemanticGroup to true to filter out data that exists in current EHR based on
semantic similarity, and false to include them. For Medications, data having same
generic or branded code using baseline code or local code are filtered out if set to true.
Default: set value to False.
e.g. ExcludeSemanticGroup := False;
;;
keywords: Fusion; Filter; Community Medications
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using namespace "System";
using namespace "System.Exception";
using namespace "System.Windows.Forms";
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Set the default last modified value
last_modified_from_dtm := db_last_modified_from_dtm;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list
rejected_id_list := ();
hardcoded_id_list := ();
database_id_list := ();
//***************Make Changes To Spelling And Flags In This Section************
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// Semantic group filter
// Specify the flag to indicate whether to include or exclude the data that already exists in
// current EHR in criteria ExcludeMyEHRData.
// By default, if the entry is missing or value is set to false, no filtering will be performed and
// data from current EHR will also be returned.
// If entry is set to true, all data that already exists in current EHR are filtered.
//
ExcludeMyEHRData := true;
// Specify the flag to indicate whether to include or exclude the data that exists in current EHR
// based on semantic similarity in criteria ExcludeSemanticGroup.
// By default, if the entry is missing or value is set to false, no filtering will be performed and
// data that is semantically similar will also be returned.
// If entry is set to true, only the semantic delta list of data is returned.
ExcludeSemanticGroup := false;
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// Last Modified from dtm
//1.By Default, value is set to NULL so that no filtering will be
//done based on last modified and all the data will come back.
//2. User specified
// - set to db_last_modified_from_dtm to use the last successful
//retrieval timestamp
// - string date time "Jan 25 2014"
//e.g. last_modified_from_dtm := "Jan 25 2014" ;
// - arden date keyword : now
//e.g.last_modified_from_dtm := now;
// - time offset:3[seconds|days|weeks|months|years]ago
//e.g.last_modified_from_dtm:= 3 months ago;
// - calculated time:db_last_modified_from_dtm-3 hours
//e.g. last_modified_from_dtm:=db_last_modified_from_dtm -2 weeks;
last_modified_from_dtm := NULL;
// By setting up this filter value, we retrieve medications that
// are active at this date. The medication that are completed on or before
// the effective_start_from_dtm value will be eliminated.
// 1. By default, this value is set to 18 months ago
// 2. User specified
// - null to do no filtering by episode time from
// - string effective_start_from_dtm "Jan 25 2014"
// e.g. effective_start_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. effective_start_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. effective_start_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. effective_start_from_dtm := db_last_modified_from_dtm - 2 weeks;
// 3. Note if the medication does not have an episode time, and the episode time
// filter is specified, it brings all the medication without episode time
// 4. Both last modified time and episode time filter will be applied
effective_start_from_dtm := 18 months ago;
// Specify the list of Ids to exclude in rejected_id_list
// The ids can be hard coded, or fetched from the database
// or combination of both
// By default, the rejected id list is empty
/*
// comment this in to use hard coded list of ids
// specify the ids
hardcoded_id_list := ();
rejected_id_list := rejected_id_list, hardcoded_id_list;
*/
/*
// comment this in to use the ids from the database
// update the SQL to get the ids you want to exclude
database_id_list := read { "SELECT DISTINCT Dtl.CommunityMedID " ||
" FROM SXAAMBeRxDispensedDetail Dtl " ||
" INNER JOIN SXAAMBeRxDispensedHeader Hdr " ||
" ON Hdr.DispensedHeaderID = Dtl.DispensedHeaderID " ||
" WHERE " ||
" Hdr.ClientGUID = " || SQL(client_guid) ||
" AND Dtl.StatusType in (1, 2) "
};
rejected_id_list := rejected_id_list, database_id_list;
*/
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
status_code_include_values := false; // true include listed values in result, false exclude
status_code_list := (
"2.16.840.1.113883.5.14.cancelled", // cancelled
"2.16.840.1.113883.6.96.185981001" // entered-in-error
);
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
// Format the return value as time, so it can be read by the caller
if exists last_modified_from_dtm
then
last_modified_from_dtm := last_modified_from_dtm as time;
LastModifiedStartDateTime := last_modified_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
if exists effective_start_from_dtm
then
effective_start_from_dtm := effective_start_from_dtm as time;
EffectiveStartFromDateTime := effective_start_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
//
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
property_value_list := (
(new PropertyValueObject with "ExcludeMyEHRData", ExcludeMyEHRData),
(new PropertyValueObject with "ExcludeSemanticGroup", ExcludeSemanticGroup)
);
// Format the name value pairs into a .Net Dictionary
PropertyNameDictionary := call func_gen_property_dictionary with property_value_list;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
LastModifiedStartDateTime,
EffectiveStartFromDateTime,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,272 @@
maintenance:
title: Fused Agent filter for importing community Results data;;
mlmname: STD_FILTER_VPO_RESULTS;;
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) 2017 - 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: This standard MLM defines the filtering criteria for community results when the
respective data is requested from dbMotion.
This MLM allows specification of either inclusion or exclusion of data to ensure only the
minimal volume of data that is necessary for processing to be returned.
;;
explanation:
The use case and respective filtering criteria supported by this MLM may be customized for the limited list of filtering criteria only:
(1) Last updated date/time to include (criteria: effective_start_from_dtm)
This criteria allows sites to include only data that has been changed since a
specified date/time to filter out any redundant data. Specify any one of the
following conditions:
(a) Last updated timestamp stored in SXACommunityDataStatus for
results data for the patient in context is used to ensure only data that
has been changed since the last successful request will be returned.
- Set value to db_last_modified_from_dtm.
e.g. effective_start_from_dtm := db_last_modified_from_dtm;
(b) Site specified date or time-offset: allows the site to override the default
behavior so that all data that have been modified since a specific date will be
provided.
- Set value to a date string formatted as "mmm dd yyyy"
e.g. effective_start_from_dtm := "Jan 25 2014";
- Set value to arden date keyword
e.g. effective_start_from_dtm := now;
- Set value to time offset in seconds/days/weeks/months/years ago
e.g. effective_start_from_dtm := 2 years ago;
- Set value as a calculated value using units in
seconds/days/weeks/months/years, if applicable.
e.g. effective_start_from_dtm := db_last_modified_from_dtm -
6 months
(c) No filter - Always return all data: allows sites to override the default behavior so that all
data is provided for reprocessing. This can be useful when processing of
previously filtered data is required. Using this option can result in an impact
to performance. (Recommended to ensure all data after Patient Merge are returned in VPO)
- Set value to NULL.
(2) Source Object Identifiers to exclude (criteria: hardcoded_id_list)
This criteria allows sites to specify a list of object identifiers to exclude. These object
identifiers specifies source facilities that are non-trusted sources.
Hard coded identifier list: specify identifiers formatted as <system OID>! to exclude.
- Specify all object identifiers to be excluded with an exclaimation mark at the end
to indicate a source OID value.
e.g. hardcoded_id_list := (
"1.3.6.1.4.1.22812.11.0.0.4.10.2.41700060!",
"1.3.6.1.4.1.22812.11.0.0.4.10.2.39248233!",
"1.3.6.1.4.1.22812.11.2014.1001!",
"1.3.6.1.4.1.22812.11.2014.9876!"
);
(3) Field name and value list to include or exclude
This criteria allows sites to specify a field name, and indicate an option to include
or exclude, along with a list of eligible values. Filtering by the field is only
performed if all required elements are specified.
All data values matching the specified value list will be included or excluded as
defined.
Only 1 field is supported for Results: Status Code.
(a) Status Code (criteria: status_code_include_values, status_code_list)
- Set status_code_include_values to true to include records with the listed
values in the returned result, and false to exclude them.
e.g. status_code_include_values := true;
- Specify status_code_list formatted as <system OID>.<code> to include
or exclude.
e.g. status_code_list := (
"2.16.840.1.113883.5.4.PRLMN", // preliminary
"2.16.840.1.113883.5.4.C", // corrected
"2.16.840.1.113883.5.4.F" // final
);
This example is configured to include all those statuses that are
identified as preliminary, corrected or final.
(4) Top N records filter
This criteria allows sites to include only last N records.
The top items to choose from are based on sorting by the effective dates in descending order.
Set TopItemCount to the maximum number of lab events you wish to receive from dbMotion.
This filter only limits the maximum lab events returned by dbMotion, the actual number of lab events
may become less due to additional filtering such as Source Object Identifiers, which occurs after
the lab events are returned by dbMotion.
e.g. TopItemCount := 200;
;;
keywords: Fusion; Filter; Community Results
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using namespace "System";
using namespace "System.Exception";
using namespace "System.Windows.Forms";
// Arguments are passed in from the calling C++ program or MLM */
(client_guid,
visit_guid,
last_modified_from_db_str
) := argument;
// ------------------------------------------------------------------
// Do not touch this section
// ------------------------------------------------------------------
error_message := "";
fatal_error := false;
// Declare the MLMs that can be called
func_gen_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_DICTIONARY{{{SINGLE-QUOTE}}};
func_gen_property_dictionary := MLM {{{SINGLE-QUOTE}}}STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY{{{SINGLE-QUOTE}}};
// Set the input from string to time
db_last_modified_from_dtm := last_modified_from_db_str as time;
// Define the name value object
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
// Define the name value object for properties
PropertyValueObject := OBJECT [ field_name, value ];
// Initialize the id list
rejected_id_list := ();
hardcoded_id_list := ();
database_id_list := ();
// Initialize the Top filter
TopItemCount := 0;
//***************Make Changes To Spelling And Flags In This Section************
// Set to true if logging is needed.
log_execution_info := false;
show_Debug_statements := false;
// ------------------------------------------------------------------
// Please update this section to customize the community data filter
// ------------------------------------------------------------------
// By setting up this filter value, we retrieve results that
// are active at this date.
// 1. By default, this value is set to 5 years ago
// 2. User specified
// - null to do no filtering by episode time from
// - string effective_start_from_dtm "Jan 25 2014"
// e.g. effective_start_from_dtm := "Jan 25 2014";
// - arden date keyword: now
// e.g. effective_start_from_dtm := now;
// - time offset: 3 [seconds|days|weeks|months|years] ago
// e.g. effective_start_from_dtm := 3 months ago;
// - calculated time: db_last_modified_from_dtm - 3 hours
// e.g. effective_start_from_dtm := db_last_modified_from_dtm - 2 weeks;
effective_start_from_dtm := 5 years ago;
// Hard coded identifier list: specify identifiers formatted as <system OID>.<ID>
// if the <system OID> ends with an ! then any result from that OID will be filtered out.
//
// This list should contain at minimum the myEHR OID. Use the format "<myEHR OID>!".
//
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
//
hardcoded_id_list := (
//"1.3.6.1.4.1.22812.4.545.6.1!" // An exact match against system OID.
);
rejected_id_list := rejected_id_list, hardcoded_id_list;
// Field Name value filter
// Specify the field name, flag to indicate whether to include or exclude the values, and list of values.
// By default, if the entry is missing for the field, or the value list is empty, no filtering
// will be performed for the field
// If the values are specified, the data matching the specified data will be filtered as specified
status_code_include_values := true; // true include listed values in result, false exclude
status_code_list := (
//"2.16.840.1.113883.5.4.PRLMN", // preliminary
//"2.16.840.1.113883.5.4.C", // corrected
//"2.16.840.1.113883.5.4.F" // final
);
// Top N records filter
// Specify the maximum number of lab events to receive from dbMotion.
// If specified, only the last N lab events will be included.
// Default value: 200
TopItemCount := 200; // Set to top 200 records
// ------------------------------------------------------------------
// End of user customization section
// ------------------------------------------------------------------
//*****************************************************************************
;;
priority: 50
;;
evoke:
;;
logic:
/************************* DO NOT UPDATE ****************************************/
// This section formats the data in a format that is understood by
// the caller
if exists effective_start_from_dtm
then
effective_start_from_dtm := effective_start_from_dtm as time;
EffectiveStartFromDateTime := effective_start_from_dtm as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
endif;
//
field_value_list := (
(new NameValueObject with "statusCode", status_code_include_values, status_code_list)
);
// Format the name value pairs into a .Net Dictionary with field name, and a list of values
(FieldCriteriaDictionary, FieldValuesListDictionary) := call func_gen_dictionary with field_value_list;
// Ids to exclude
if (count rejected_id_list > 0)
then
IdsToExcludeList := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List<String>{{{SINGLE-QUOTE}}};
for id in rejected_id_list
do
id_val := id as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
void := call IdsToExcludeList.Add with id_val;
enddo;
else
IdsToExcludeList := null;
endif;
conclude true;
;;
action:
if fatal_error
then
return fatal_error, error_message;
else
return
null,
EffectiveStartFromDateTime,
FieldCriteriaDictionary,
FieldValuesListDictionary,
IdsToExcludeList,
PropertyNameDictionary,
TopItemCount
;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,177 @@
maintenance:
title: Get Filter Query And Bit Flags Based on Alert On Demand flag ;;
mlmname: STD_Func_Alert_On_Demand_Filter;;
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: This sub MLM generates the order session type filter and
prescription type filter list based on the AlertCheckAgainstSelection flag
;;
explanation:
The AlertCheckAgainstSelection flag is a combination of following values:
0 - No items selected
1 - Order or Client Prescription selected from the catalog
2 - Current database orders selected
3 - (1+2)
4 - Current database Client Prescriptions selected
5 - (1+4)
6 - (2+4)
7 - (1+2+4)
;;
keywords:
Session Type
;;
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;
/********************************************************************************/
(AlertCheckAgainstSelection,
use_community_medication) /* this flag specifies whether to check
against community medication or not */
:= ARGUMENT;
//--------- Unpack the bit packed values -------//
// The AlertCheckAgainstSelection is a value
// that ranges between 0~7 inclusively.
//
// This is a bit packed value. It is created by adding
// at most one instance of 1, 2, or 4.
//
// Unpack by subtracting the largest value first
user_selection_const_val := 1;
order_const_val := 2;
rx_const_val := 4;
combined_value := AlertCheckAgainstSelection;
if (combined_value >= rx_const_val)
then
// The combined value contains 4.
// Possible values are 4,5,6 or 7
combined_value := combined_value - rx_const_val;
gen_rx_filters := true;
else
gen_rx_filters := false;
endif;
if (combined_value >= order_const_val)
then
// The combined value contains 2.
// Possible values are 2 or 3
combined_value := combined_value - order_const_val;
gen_order_filters := true;
else
gen_order_filters := false;
endif;
// Initialize the values for the include community medication flag
if (use_community_medication = true)
then
include_community_medication := true;
else
include_community_medication := false;
endif;
// The combined value is either 0 or 1
user_selection_exists := (combined_value = user_selection_const_val);
//------- Generate filters ---------------------//
// Enum values for Rx, Hx, Community Medication defined
enum_rx_type_Rx := 1;
enum_rx_type_Hx := 3;
enum_rx_type_Community_Med := 5;
// Generate alert-on-demand filters for
// database prescriptions
if (include_community_medication)
then
unsubmitted_rx_type_list := (enum_rx_type_Rx, enum_rx_type_Hx, enum_rx_type_Community_Med);
else
unsubmitted_rx_type_list := (enum_rx_type_Rx, enum_rx_type_Hx);
endif;
if (gen_rx_filters)
then
db_rx_type_str := enum_rx_type_Rx || ", " || enum_rx_type_Hx;
db_rx_types_list := (enum_rx_type_Rx, enum_rx_type_Hx);
if (include_community_medication)
then
db_rx_type_str := db_rx_type_str || ", "|| enum_rx_type_Community_Med;
db_rx_types_list := db_rx_types_list, enum_rx_type_Community_Med;
endif;
else
db_rx_type_str := "";
db_rx_types_list := ();
endif;
order_table_name := "";
include_in_house_session_type_orders := false;
include_historical_session_type_orders := false;
include_discharge_session_type_orders := false;
include_outpatient_rx_session_type_orders := false;
include_outpatient_hx_session_type_orders := false;
// Generate alert-on-demand filters for
// database prescriptions
unsubmitted_session_type_bit_flags := 1;
if (gen_order_filters)
then
order_table_name := "CV3AllOrdersVw";
include_in_house_session_type_orders := true;
include_discharge_session_type_orders := true;
include_outpatient_rx_session_type_orders := true;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return( order_table_name,
include_in_house_session_type_orders,
include_historical_session_type_orders,
include_discharge_session_type_orders,
include_outpatient_rx_session_type_orders,
include_outpatient_hx_session_type_orders,
unsubmitted_session_type_bit_flags,
unsubmitted_rx_type_list,
db_rx_type_str,
db_rx_types_list,
include_community_medication );
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,360 @@
maintenance:
title: Allergy Checking Using the Item-Catalog;;
mlmname: STD_FUNC_ALLERGY_CAT;;
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: Checks for Drug Allergies via Item-Catalog.
;;
explanation: See STD_ALLERGY MLM for an explanation.
;;
keywords: allergy; IV additives; Item-Catalog;;
knowledge:
type: data-driven;;
data:
(
order_name,
order_is_additive,
patient_allergy_names,
OrderCatalogMasterItemGUID,
Generic_name_id,
patient_allergy_category_types,
patient_allergy_adverse_event_date_year,
patient_allergy_adverse_event_date_month,
patient_allergy_adverse_event_date_day,
input_parameter_xml,
allergen_guid,
client_guid,
allergy_category_type,
rx_other_allergen_check,
is_reverse_check,
reverse_check_order,
reverse_check_rx,
reverse_check_med_orders,
reverse_check_outpatient_orders_flag):= ARGUMENT;
/*******************Make Changes To Spelling And Flags In This Section*******************/
/* Set to true if logging is needed.*/
log_execution_info := false;
/***************************************************************************************/
//Declare the Med_Data_Object
Med_Data_Object := OBJECT [
rx_hx_typecode,
sort_field,
OrderName,
OrderOrAdditiveName,
PrescriptionName,
ComponentName,
ComboDrugName,
OrderGUID,
AdditiveGUID,
PrescriptionID,
StartDate,
StatusType,
TypeCode,
IsUnmapped,
allergen_msg,
msg_type,
IsComboDrug
];
// list that holds all of the objects that will be returned
mdo_list := ();
if is_reverse_check
then
( rx_hx_typecode_list,
allergen_msg_list,
order_guid_list,
additive_guid_list,
prescription_id_list,
order_name_list,
order_or_additive_name_list,
prescription_name_list,
start_date_list,
status_type_list,
type_code_list,
IsDnumLevel_list,
FormularyBrandKey_list
) := read { "EXEC SXACatalogAllergyAlertSelPr "
|| SQL(input_parameter_xml)|| ", "
|| SQL(allergen_guid) || ", "
|| SQL(client_guid) || ", "
|| SQL(allergy_category_type) || ", "
|| SQL(rx_other_allergen_check) || ", "
|| SQL(reverse_check_order) || ", "
|| SQL(reverse_check_rx) || ", "
|| SQL(reverse_check_med_orders) || ", "
|| SQL(reverse_check_outpatient_orders_flag) };
if exist allergen_msg_list
then
num_msgs := count (allergen_msg_list);
//num_msgs := num_msgs + 1;
for JJ in (1 seqto num_msgs ) do
instance := new Med_Data_Object;
instance.rx_hx_typecode := rx_hx_typecode_list[JJ];
instance.OrderName := order_name_list[JJ];
instance.OrderOrAdditiveName := order_or_additive_name_list[JJ];
instance.PrescriptionName := prescription_name_list[JJ];
instance.ComponentName := "";
instance.ComboDrugName := "";
instance.OrderGUID := order_guid_list[JJ];
instance.AdditiveGUID := additive_guid_list[JJ];
instance.PrescriptionID := prescription_id_list[JJ];
instance.StartDate := start_date_list[JJ];
instance.StatusType := status_type_list[JJ];
instance.TypeCode := type_code_list[JJ];
instance.msg_type := "Catalog";
instance.IsComboDrug := false;
instance.IsUnmapped := false;
if (instance.PrescriptionID is not null and instance.PrescriptionID <> -1)
then
instance.sort_field :=
instance.PrescriptionName || "|" || instance.PrescriptionID
|| "|{2}";
//[MU2][SNOMEDCT]
current_FormularyBrandKey := FormularyBrandKey_list[JJ];
IsDnumLevel := IsDnumLevel_list[JJ];
if IsDnumLevel = false
then
IsDnumLevel:=0;
else
IsDnumLevel:=1;
endif;
tempallergen_msg := allergen_msg_list[JJ];
(one_allergen_msg) := read last { "EXEC SXACatalogAllergenMessageTextSelPr "
|| SQL(IsDnumLevel)|| ", "
|| SQL(instance.PrescriptionName) || ", "
|| SQL(current_FormularyBrandKey) || ", "
|| SQL(allergen_guid) || ", "
|| SQL(1) || ", "
|| SQL(NULL) };
if one_allergen_msg <> ""
then
instance.allergen_msg := allergen_msg_list[JJ] || one_allergen_msg;
mdo_list := mdo_list, instance;
endif;
elseif (instance.AdditiveGUID is not null)
then
instance.sort_field :=
instance.OrderOrAdditiveName || "|" || instance.AdditiveGUID
|| "|{2}";
instance.allergen_msg := allergen_msg_list[JJ];
mdo_list := mdo_list, instance;
else
instance.sort_field :=
instance.OrderName || "|" || instance.OrderGUID
|| "|{2}";
instance.allergen_msg := allergen_msg_list[JJ];
mdo_list := mdo_list, instance;
endif;
enddo;
endif;
/* Only retrieves data if the patient has allergies */
elseIf exist patient_allergy_names
then
if OrderCatalogMasterItemGUID is not null
then
/* Gets the allergen codes and other relevant data associated with the order{{{SINGLE-QUOTE}}}s
catalog item allergens */
(allergen_codes,
allergen_msg_texts) := read
{ "SELECT Code, MessageText,CV3OrderCatalogMasterItem.Name "
|| " FROM CV3Allergen JOIN CV3CatalogItemAllergen"
|| " ON CV3Allergen.GUID = CV3CatalogItemAllergen.AllergenGUID"
|| " INNER JOIN CV3OrderCatalogMasterItem ON"
|| " CV3CatalogItemAllergen.ItemGUID = CV3OrderCatalogMasterItem.GUID"
|| " WHERE CV3CatalogItemAllergen.ItemGUID = "
|| SQL(OrderCatalogMasterItemGUID)};
if (order_is_additive)
then
order_or_prescription_string := " additive.";
else
order_or_prescription_string := " order.";
endif;
else
/* Gets the allergen codes and other relevant data associated with the
prescription{{{SINGLE-QUOTE}}}s catalog item allergens */
num_allergies := count (patient_allergy_names);
for J in (1 seqto num_allergies ) do
if J=1
then
one_patient_allergy_name:= patient_allergy_names[J];
else
one_patient_allergy_name:= one_patient_allergy_name || "," || patient_allergy_names[J];
endif;
enddo;
(allergen_codes,
allergen_msg_texts) := read { "EXEC SXACatalogAllergenMessageTextSelPr "
|| SQL(NULL)|| ", "
|| SQL(order_name) || ", "
|| SQL(EVOKINGOBJECT.FormularyBrandKey) || ", "
|| SQL(allergen_guid) || ", "
|| SQL(0) || ", "
|| SQL(one_patient_allergy_name) };
order_or_prescription_string := " prescription.";
endif;
endif; /* If exist patient_allergy_names */
;;
evoke: ;;
logic:
if (is_reverse_check)
then
conclude true;
endif;
/* Stops processing when the patient does not have any allergies */
if not (exist order_name or exist patient_allergy_names)
then
xxx_debug_check:= "patient does not have allergies";
conclude false;
endif;
/* Initializes variables */
alert_msg_list:= ();
alert_allergen_list:= ();
alert_category_type_list := ();
alert_adverse_event_year_list := ();
alert_adverse_event_month_list := ();
alert_adverse_event_day_list := ();
allergies_found := patient_allergy_names is in allergen_codes ;
if any allergies_found
then
num_allergies := count (patient_allergy_names);
for J in (1 seqto num_allergies ) do
one_patient_allergy_name:= patient_allergy_names[J];
if (one_patient_allergy_name is in allergen_codes)
then
category_type := patient_allergy_category_types[J];
adverse_event_date_year := patient_allergy_adverse_event_date_year[J];
adverse_event_date_month := patient_allergy_adverse_event_date_month[J];
adverse_event_date_day := patient_allergy_adverse_event_date_day[J];
allergen_code := one_patient_allergy_name;
if (category_type = "Adverse Event" and
category_type = prev_category_type and
allergen_code = prev_allergen_code)
then
alert_allergen_list := alert_allergen_list, null;
alert_msg_list:= alert_msg_list, null;
alert_category_type_list := alert_category_type_list, null;
alert_adverse_event_year_list := alert_adverse_event_year_list, null;
alert_adverse_event_month_list := alert_adverse_event_month_list, null;
alert_adverse_event_day_list := alert_adverse_event_day_list, null;
else
/* Creates the list of matching allergens
to return to the calling MLM */
alert_allergen_list:= alert_allergen_list, allergen_code;
/* Creates a portion of the alert message */
if (category_type = "Allergy" or category_type is null)
then
temp_alert_msg:=
"The patient is allergic to " || allergen_code
|| ". A reaction may occur with the "
|| order_name || order_or_prescription_string;
elseif (category_type = "Adverse Event")
then
temp_alert_msg:=
"The patient had an adverse event with " || allergen_code
|| ". A reaction may occur with the "
|| order_name || order_or_prescription_string ;
elseif (category_type = "Intolerance")
then
temp_alert_msg:=
"The patient has an intolerance to " || allergen_code
|| ". A reaction may occur with the "
|| order_name || order_or_prescription_string ;
endif;
/* Extracts the freetext message in the item-catalog that is */
/* assocated with the allergen code */
allergy_freetext_msg:= first(allergen_msg_texts
where allergen_code = allergen_codes);
/* Adds the item-catalog{{{SINGLE-QUOTE}}}s freetext message to the alert */
if exist allergy_freetext_msg
then
temp_alert_msg:= temp_alert_msg || " " || allergy_freetext_msg;
endif;
/* Creates the alert message that is returned to the calling MLM */
alert_msg_list:= alert_msg_list, temp_alert_msg;
alert_category_type_list := alert_category_type_list, category_type;
alert_adverse_event_year_list := alert_adverse_event_year_list,
adverse_event_date_year;
alert_adverse_event_month_list := alert_adverse_event_month_list,
adverse_event_date_month;
alert_adverse_event_day_list := alert_adverse_event_day_list,
adverse_event_date_day;
endif;
prev_category_type := category_type;
prev_allergen_code := allergen_code;
endif;
enddo;
endif; /* if any allergies_found */
/* Always conclude true to return information to the calling MLM */
conclude true;
;;
action:
if is_reverse_check
then
return mdo_list;
else
return (alert_allergen_list,
alert_msg_list,
alert_category_type_list,
alert_adverse_event_year_list,
alert_adverse_event_month_list,
alert_adverse_event_day_list);
endif;
;;
end:

View File

@@ -0,0 +1,678 @@
maintenance:
title: Medication Allergy Checking using Drug Vendor Data Drug Database;;
mlmname: STD_FUNC_ALLERGY_DRUG_VENDOR_DATA;;
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: Checks for Drug Allergies via Drug Vendor Data.
;;
explanation: See STD_ALLERGY MLM for an explanation.
;;
keywords: allergy; IV additives; Drug Vendor Data ;;
knowledge:
type: data-driven;;
data:
/* List Arguments passed by the calling MLM */
(unmapped_allergen_type_list,
pending_community_allergy_alert_text,
enable_community_data_allergy_alerts,
retrieve_pending_imported_allergies,
cat_item_guid,
client_guid,
allergy_names,
allergy_external_drug_code_list,
allergy_external_drug_category_list,
allergy_external_categorytype_list,
generic_nameID,
Allergen_Classification_Check,
evoked_from_prescriptions,
display_alert_types,
alert_if_error,
alert_if_unmapped,
input_parameter_xml,
allergy_decl_xml,
DRUG_VENDOR_DATA_ALLERGY_CHECK,
reverse_check_order,
reverse_check_rx,
reverse_check_outpatient_orders_flag):= ARGUMENT;
/***************Make Changes To Spelling And Flags In This Section**************/
/* Set to true if logging is needed.*/
log_execution_info := false;
/*******************************************************************************/
alert_allergen_list:= ();
temp_alert_msg_list:= ();
alert_msg_list:= ();
temp_drug_vendor_allergen_IDs := ();
drug_vendor_allergen_IDs := ();
temp_drug_vendor_allergen_reaction_level := ();
temp_drug_vendor_category_names := ();
temp_drug_vendor_class_names := ();
temp_allergen_categorytype_description := ();
temp_allergen_categorytype := ();
temp_allergen_onset_day_list := ();
temp_allergen_onset_month_list:= ();
temp_allergen_onset_year_list := ();
temp_drug_vendor_allergen_name_list := ();
temp_drug_vendor_allergen_component_name_list := ();
temp_drug_vendor_component_allergen_id_list := ();
temp_drug_vendor_text_id_list := ();
temp_drug_vendor_drug_category_id_list := ();
temp_drug_vendor_drug_class_id_list := ();
temp_drug_vendor_catalog_guid_list := ();
temp_drug_vendor_prescription_id_list := ();
temp_order_name_list := ();
temp_OrderOrAdditive_name_list := ();
temp_prescription_name_list := ();
temp_start_date_list := ();
temp_status_type_list := ();
alert_category_list := ();
alert_adverse_event_year:= ();
alert_adverse_event_month:= ();
alert_adverse_event_day:= ();
alert_allergen_generic_name_list:= ();
alert_allergen_component_list:= ();
alert_allergen_id_list := ();
alert_reaction_level_list := ();
alert_medication_category_name_list := ();
alert_medication_class_name_list :=();
alert_allergen_category_type_list := ();
alert_allergen_component_id_list := ();
alert_drug_vendor_text_id_list := ();
alert_medication_category_id_list := ();
alert_medication_class_id_list := ();
alert_drug_is_combo_drug_list := ();
unmapped_allergen_error_code := "-1";
unmapped_drug_error_code := "-2";
invalid_cat_item_guid_and_generic_name_id_error := "-3";
classification_reaction_level := 3;
is_reverse_check := (exist input_parameter_xml AND exist allergy_decl_xml);
//convert unmapped_allergen_type_list into comma separated string so that we can pass it to SXADrugVendorAllergyAlertSelPr stored proc
unmapped_allergen_type_string := "";
if ((exists unmapped_allergen_type_list) and (count unmapped_allergen_type_list > 0))
then
string_length := count unmapped_allergen_type_list;
//unmapped_allergen_type_string := "{{{SINGLE-QUOTE}}}" || unmapped_allergen_type_list || "{{{SINGLE-QUOTE}}}";
FOR i in 1 seqto count unmapped_allergen_type_list DO
unmapped_allergen_type_item := TRIM(unmapped_allergen_type_list[i]);
unmapped_allergen_type_string := unmapped_allergen_type_string || unmapped_allergen_type_item;
if string_length <> i
then
unmapped_allergen_type_string := unmapped_allergen_type_string || ",";
endif;
ENDDO;
endif;
//---------------------
// Declare the Objects
//---------------------
//Declare the Med_Data_Object
Med_Data_Object := OBJECT [
rx_hx_typecode,
sort_field,
OrderName,
OrderOrAdditiveName,
PrescriptionName,
ComponentName,
ComboDrugName,
OrderGUID,
AdditiveGUID,
PrescriptionID,
StartDate,
StatusType,
TypeCode,
IsUnmapped,
allergen_msg,
msg_type,
IsComboDrug,
ExternalDrugCode,
DrugClassName,
DrugClassID,
IsIntentionallyNotMapped,
AlternateOrderType,
IsScript,
EnteredDate
];
// list that holds all of the objects that will be returned
mdo_list := ();
if is_reverse_check
then
(
temp_drug_vendor_allergen_IDs,
temp_alert_msg_list,
temp_drug_vendor_allergen_component_name_list,
temp_drug_vendor_combo_drug_name_list,
temp_drug_vendor_order_guid_list,
temp_drug_vendor_additive_guid_list,
temp_drug_vendor_prescription_id_list,
temp_order_name_list,
temp_OrderOrAdditive_name_list,
temp_prescription_name_list,
temp_start_date_list,
temp_status_type_list,
temp_type_code_list,
temp_is_combo_drug_list,
temp_drug_class_name_list,
temp_drug_vendor_drug_class_id_list,
temp_is_intentionally_not_mapped_list,
temp_alternate_order_type_list,
temp_is_script_list,
temp_entered_date_list,
temp_rx_hx_typecode_list
) := read { "EXEC SXADrugVendorAllergyAlertSelPr "
|| SQL(unmapped_allergen_type_string) || ", "
|| SQL(pending_community_allergy_alert_text) || ", "
|| SQL(retrieve_pending_imported_allergies) || ", "
|| SQL(enable_community_data_allergy_alerts) || ", "
|| SQL(cat_item_guid) || ", "
|| SQL(client_guid) || ", "
|| SQL(generic_nameID) || ", "
|| SQL(allergy_decl_xml) || ", "
|| SQL(input_parameter_xml) || ", "
|| SQL(Allergen_Classification_Check) || ", "
|| SQL(alert_if_unmapped) || ", "
|| SQL(DRUG_VENDOR_DATA_ALLERGY_CHECK) || ", "
|| SQL(is_reverse_check) || ", "
|| SQL(reverse_check_order) || ", "
|| SQL(reverse_check_rx) || ", "
|| SQL(reverse_check_outpatient_orders_flag)};
// populate mdo_list using data returned from the stored procedure
index_list := 1 seqto count (temp_drug_vendor_allergen_IDs);
for JJ in index_list do
instance := new Med_Data_Object;
instance.rx_hx_typecode := temp_rx_hx_typecode_list[JJ];
instance.OrderName := temp_order_name_list[JJ];
instance.OrderOrAdditiveName := temp_OrderOrAdditive_name_list[JJ];
instance.PrescriptionName := temp_prescription_name_list[JJ];
instance.ComponentName := temp_drug_vendor_allergen_component_name_list[JJ];
instance.ComboDrugName := temp_drug_vendor_combo_drug_name_list[JJ];
instance.OrderGUID := temp_drug_vendor_order_guid_list[JJ];
instance.AdditiveGUID := temp_drug_vendor_additive_guid_list[JJ];
instance.PrescriptionID := temp_drug_vendor_prescription_id_list[JJ];
instance.StartDate := temp_start_date_list[JJ];
instance.StatusType := temp_status_type_list[JJ];
instance.TypeCode := temp_type_code_list[JJ];
instance.allergen_msg := temp_alert_msg_list[JJ];
instance.msg_type := "DrugVendor";
instance.IsComboDrug := temp_is_combo_drug_list[JJ];
instance.ExternalDrugCode := temp_drug_vendor_allergen_IDs[JJ];//AlertRef
instance.DrugClassName := temp_drug_class_name_list[JJ];//AlertRef
instance.DrugClassID := temp_drug_vendor_drug_class_id_list[JJ];//AlertRef
instance.AlternateOrderType := temp_alternate_order_type_list[jj];
instance.IsScript := temp_is_script_list[jj];
instance.EnteredDate := temp_entered_date_list[jj];
if (temp_drug_vendor_allergen_IDs[JJ] = "-2") // unmapped drug
then
instance.IsUnmapped := true;
else
instance.IsUnmapped := false;
endif;
if (instance.IsComboDrug)
then
instance.sort_field :=
instance.ComponentName || " in " || instance.ComboDrugName || "|";
if (instance.PrescriptionID is not null AND instance.PrescriptionID <> -1)
then
instance.sort_field := instance.sort_field || instance.PrescriptionID;
elseif instance.AdditiveGUID is not null
then
instance.sort_field := instance.sort_field || instance.AdditiveGUID;
else
instance.sort_field := instance.sort_field || instance.OrderGUID;
endif;
instance.sort_field := instance.sort_field || "|{1}";
elseif (instance.AdditiveGUID is not null)
then
instance.sort_field :=
instance.OrderOrAdditiveName || "|" || instance.AdditiveGUID || "|{1}";
elseif (instance.PrescriptionID is not null AND instance.PrescriptionID <> -1)
then
instance.sort_field :=
instance.PrescriptionName || "|" || instance.PrescriptionID || "|{1}";
else
instance.sort_field :=
instance.OrderName || "|" || instance.OrderGUID || "|{1}";
endif;
if alert_if_unmapped = true
then
if instance.PrescriptionID = -1
then
if temp_is_intentionally_not_mapped_list[JJ] = true
OR temp_is_intentionally_not_mapped_list[JJ] is null// unmapped drug
then
mdo_list := mdo_list, instance;
endif;
else
mdo_list := mdo_list, instance;
endif;
else
mdo_list := mdo_list, instance;
endif;
enddo;
else
(
temp_drug_vendor_allergen_IDs,
temp_alert_msg_list,
temp_drug_vendor_allergen_reaction_level,
temp_drug_vendor_category_names,
temp_drug_vendor_class_names,
temp_allergen_categorytype_description,
temp_allergen_categorytype,
temp_allergen_onset_day_list,
temp_allergen_onset_month_list,
temp_allergen_onset_year_list,
temp_drug_vendor_allergen_component_name_list,
temp_drug_vendor_allergen_name_list,
temp_drug_vendor_component_allergen_id_list,
temp_drug_vendor_text_id_list,
temp_drug_vendor_drug_category_id_list,
temp_drug_vendor_drug_class_id_list,
temp_is_combo_drug_list
) := read { "EXEC SXADrugVendorAllergyAlertSelPr "
|| SQL(unmapped_allergen_type_string) || ", "
|| SQL(pending_community_allergy_alert_text) || ", "
|| SQL(retrieve_pending_imported_allergies) || ", "
|| SQL(enable_community_data_allergy_alerts) || ", "
|| SQL(cat_item_guid) || " , " || SQL(client_guid) || " ,"
|| SQL(generic_nameID) || ", " || SQL(allergy_decl_xml) || ", "
|| SQL(input_parameter_xml) || ", " || SQL(Allergen_Classification_Check) || ", "
|| SQL(alert_if_unmapped)};
endif;
;;
evoke: ;;
logic:
if (is_reverse_check)
then
conclude true;
elseif (not exist cat_item_guid AND not exist generic_nameID)
OR (not exist allergy_names)
then
conclude false;
endif;
num_allergies := count (temp_drug_vendor_allergen_IDs);
// Always conclude true to return information to the calling MLM
// Create the list of allergens that map to the Drug Vendor IDs.
for J in (1 seqto num_allergies ) do
one_drug_vendor_allergen_ID:= temp_drug_vendor_allergen_IDs[J];
one_drug_vendor_alert_msg := temp_alert_msg_list[J];
one_drug_vendor_reaction_level :=
temp_drug_vendor_allergen_reaction_level[J];
one_drug_vendor_category_name := temp_drug_vendor_category_names[J];
one_drug_vendor_class_name := temp_drug_vendor_class_names[J];
one_allergen_categorytype_description :=
temp_allergen_categorytype_description[J];
one_allergen_categorytype := temp_allergen_categorytype[J];
one_allergen_onset_day := temp_allergen_onset_day_list[J];
one_allergen_onset_month := temp_allergen_onset_month_list[J];
one_allergen_onset_year := temp_allergen_onset_year_list[J];
one_allergen_component_generic_name :=
temp_drug_vendor_allergen_component_name_list[j];
one_allergen_parent_generic_name := temp_drug_vendor_allergen_name_list[j];
one_drug_vendor_component_allergen_id :=
temp_drug_vendor_component_allergen_id_list[j];
one_drug_vendor_text_id := temp_drug_vendor_text_id_list[j];
one_drug_vendor_category_id := temp_drug_vendor_drug_category_id_list[j];
one_drug_vendor_class_id := temp_drug_vendor_drug_class_id_list[j];
one_drug_is_combo_drug := temp_is_combo_drug_list[j];
prev_temp_category := temp_allergen_categorytype_description[j-1];
prev_vendor_allergen_id := temp_drug_vendor_allergen_IDs[j-1];
prev_vendor_component_allergen_id := temp_drug_vendor_component_allergen_id_list[j-1];
// if not reverse checking, then proceed as normal.
//If the drug is not mapped the Drug_vendor_allergen_ID will be -2
if string(one_drug_vendor_allergen_ID) = unmapped_drug_error_code
then
if alert_if_unmapped and (not evoked_from_prescriptions)
then
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list:= alert_msg_list,
"The order listed below could not be checked against the"
|| " patient{{{SINGLE-QUOTE}}}s allergies."
|| " Please use an alternate plan to do the check. "
|| " Notify your system administrator for Sunrise Clinical Manager"
|| " that the Multum Allergy Checking could not be done because below order(s) is an Unmapped drug";
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := one_allergen_parent_generic_name;
alert_allergen_component_list := alert_allergen_component_list, NULL;
if exist one_drug_vendor_allergen_ID
then
alert_allergen_id_list := one_drug_vendor_allergen_ID;
endif;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
else
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list := alert_msg_list, NULL;
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
endif;
//If the allergen is not mapped or the external code is invalid,
//the Drug_vendor_allergen_ID will be -1
elseif string(one_drug_vendor_allergen_ID) = unmapped_allergen_error_code
then
if alert_if_unmapped
then
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list:= alert_msg_list,
"The order listed below could not be checked against the"
|| " patient{{{SINGLE-QUOTE}}}s allergies."
|| " Please use an alternate plan to do the check. "
|| " Notify your system administrator for Sunrise Clinical Manager"
|| " that the following error occurred with the Drug Data: "
|| one_drug_vendor_alert_msg;
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
else
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list := alert_msg_list, NULL;
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
endif;
//@CatItemGUID and @DrugGenericNameID parameters for the stored procedure
//are both null, the Drug_vendor_allergen_ID will be -3
elseif (string(one_drug_vendor_allergen_ID) =
invalid_cat_item_guid_and_generic_name_id_error)
then
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list:= alert_msg_list,
"The order listed below could not be checked against the"
|| " patient{{{SINGLE-QUOTE}}}s allergies."
|| " Please use an alternate plan to do the check. "
|| " Notify your system administrator for Sunrise Clinical Manager"
|| " that the following error occurred with the Drug Data: "
|| one_drug_vendor_alert_msg;
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
// external drug code = external drug code field in CV3Allergen (see config tools)
// return drug allergy messages that match the allergy{{{SINGLE-QUOTE}}}s drug id or drug category id
// also, will only return messages if allergy is in specified category type
// list (adverse event, intolerance)
elseif one_drug_vendor_allergen_ID is in allergy_external_drug_code_list
and one_allergen_categorytype_description is in display_alert_types
then
temp_allergy_list := allergy_names where one_drug_vendor_allergen_ID = allergy_external_drug_code_list
and one_allergen_categorytype = allergy_external_categorytype_list;
for temp_name in temp_allergy_list do
if (Allergen_Classification_Check = true
or (Allergen_Classification_Check = false
and one_drug_vendor_reaction_level <> classification_reaction_level))
then
if (one_allergen_categorytype_description = "Adverse Event" and
one_allergen_categorytype_description = prev_temp_category and
one_drug_vendor_allergen_ID = prev_vendor_allergen_id and
one_drug_vendor_component_allergen_id = prev_vendor_component_allergen_id)
then
alert_allergen_list:= alert_allergen_list, null;
alert_msg_list := alert_msg_list, null;
alert_category_list := alert_category_list, null;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
else
alert_allergen_list:= alert_allergen_list, temp_name;
alert_msg_list := alert_msg_list, one_drug_vendor_alert_msg;
alert_category_list :=
alert_category_list, one_allergen_categorytype_description;
alert_adverse_event_year :=
alert_adverse_event_year, one_allergen_onset_year;
alert_adverse_event_month :=
alert_adverse_event_month, one_allergen_onset_month;
alert_adverse_event_day :=
alert_adverse_event_day, one_allergen_onset_day;
alert_allergen_generic_name_list := alert_allergen_generic_name_list,
one_allergen_parent_generic_name;
alert_allergen_component_list := alert_allergen_component_list,
one_allergen_component_generic_name;
alert_allergen_id_list := alert_allergen_id_list, one_drug_vendor_allergen_ID;
alert_reaction_level_list := alert_reaction_level_list, one_drug_vendor_reaction_level;
alert_medication_category_name_list := alert_medication_category_name_list, one_drug_vendor_category_name;
alert_medication_class_name_list :=alert_medication_class_name_list, one_drug_vendor_class_name;
alert_allergen_category_type_list := alert_allergen_category_type_list, one_allergen_categorytype;
alert_allergen_component_id_list := alert_allergen_component_id_list, one_drug_vendor_component_allergen_id;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, one_drug_vendor_text_id;
alert_medication_category_id_list := alert_medication_category_id_list, one_drug_vendor_category_id;
alert_medication_class_id_list := alert_medication_class_id_list, one_drug_vendor_class_id;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, one_drug_is_combo_drug;
endif;
endif;
enddo;
elseif one_drug_vendor_allergen_ID
is in allergy_external_drug_category_list
and one_allergen_categorytype_description
is in display_alert_types
then
temp_allergy_list := allergy_names where
(one_drug_vendor_allergen_ID = allergy_external_drug_category_list
and one_allergen_categorytype = allergy_external_categorytype_list);
for temp_name in temp_allergy_list do
alert_allergen_list:= alert_allergen_list, temp_name;
alert_msg_list := alert_msg_list, one_drug_vendor_alert_msg;
alert_category_list := alert_category_list,
one_allergen_categorytype_description;
alert_adverse_event_year := alert_adverse_event_year,
one_allergen_onset_year;
alert_adverse_event_month := alert_adverse_event_month,
one_allergen_onset_month;
alert_adverse_event_day := alert_adverse_event_day,
one_allergen_onset_day;
alert_allergen_generic_name_list := alert_allergen_generic_name_list,
one_allergen_parent_generic_name;
alert_allergen_component_list := alert_allergen_component_list,
one_allergen_component_generic_name;
alert_allergen_id_list := alert_allergen_id_list, one_drug_vendor_allergen_ID;
alert_reaction_level_list := alert_reaction_level_list, one_drug_vendor_reaction_level;
alert_medication_category_name_list := alert_medication_category_name_list, one_drug_vendor_category_name;
alert_medication_class_name_list :=alert_medication_class_name_list, one_drug_vendor_class_name;
alert_allergen_category_type_list := alert_allergen_category_type_list, one_allergen_categorytype;
alert_allergen_component_id_list := alert_allergen_component_id_list, one_drug_vendor_component_allergen_id;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, one_drug_vendor_text_id;
alert_medication_category_id_list := alert_medication_category_id_list, one_drug_vendor_category_id;
alert_medication_class_id_list := alert_medication_class_id_list, one_drug_vendor_class_id;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, one_drug_is_combo_drug;
enddo;
else
alert_allergen_list:= alert_allergen_list, NULL;
alert_msg_list := alert_msg_list, NULL;
alert_category_list := alert_category_list, NULL;
alert_adverse_event_year := alert_adverse_event_year, NULL;
alert_adverse_event_month := alert_adverse_event_month, NULL;
alert_adverse_event_day := alert_adverse_event_day, NULL;
alert_allergen_generic_name_list := alert_allergen_generic_name_list, NULL;
alert_allergen_component_list := alert_allergen_component_list, NULL;
alert_allergen_id_list := alert_allergen_id_list, NULL;
alert_reaction_level_list := alert_reaction_level_list, NULL;
alert_medication_category_name_list := alert_medication_category_name_list, NULL;
alert_medication_class_name_list :=alert_medication_class_name_list, NULL;
alert_allergen_category_type_list := alert_allergen_category_type_list, NULL;
alert_allergen_component_id_list := alert_allergen_component_id_list, NULL;
alert_drug_vendor_text_id_list := alert_drug_vendor_text_id_list, NULL;
alert_medication_category_id_list := alert_medication_category_id_list, NULL;
alert_medication_class_id_list := alert_medication_class_id_list, NULL;
alert_drug_is_combo_drug_list := alert_drug_is_combo_drug_list, NULL;
endif; // if one_drug_vendor_allergen_ID
prev_vendor_allergen_id := one_drug_vendor_allergen_ID;
prev_temp_category := one_allergen_categorytype_description;
enddo; // for J
conclude true;
;;
action:
if (is_reverse_check) then
return ( mdo_list );
else
return (alert_allergen_list,
alert_msg_list,
alert_category_list,
alert_adverse_event_year,
alert_adverse_event_month,
alert_adverse_event_day,
alert_allergen_generic_name_list, // prescription name
alert_allergen_component_list, // component of prescription
alert_allergen_id_list,
alert_reaction_level_list,
alert_medication_category_name_list,
alert_medication_class_name_list,
alert_allergen_category_type_list,
alert_allergen_component_id_list,
alert_drug_vendor_text_id_list,
alert_medication_category_id_list,
alert_medication_class_id_list,
alert_drug_is_combo_drug_list);
endif;
;;
end:

View File

@@ -0,0 +1,120 @@
maintenance:
title: Build a result object;;
mlmname: STD_FUNC_BUILD_RESULT_OBJECT;;
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: This MLM will create one or more Result data objects based
on parameter data and any parent/child relationships found in the
database.
This MLM should be called by any MLM that calls the STD_FUNC_INSERT_REPORTABLE_SURVEILLANCE
MLM with result data.
;;
explanation:
;;
keywords:
;;
citations:
;;
knowledge:
type: data-driven;;
data:
(parentOrderKey,
childResultGUIDs,
reasonCode) := ARGUMENT;
log_execution_info := false;
// Common code to all Bio-Surveillance MLMs
ReportableType := OBJECT
[
ParentKey,
ChildKeys,
ObjectType,
Reason
];
resultsType := OBJECT [ resultGUID, orderGUID ];
// Call SQL function to find all parent/child orders and results for the
// parent order key passed in
if (childResultGUIDs is not null AND not childResultGUIDs is list) then
childResultGUIDs := ,childResultGUIDs;
endif;
// Build the XML field used to send in the list of results used to filter
childResultGUIDsXML := null;
if childResultGUIDs is list
then
childResultGUIDsXML := "<results>";
for guid in childResultGUIDs do
childResultGUIDsXML := childResultGUIDsXML || "<guid>" || guid || "</guid>";
enddo;
childResultGUIDsXML := childResultGUIDsXML || "</results>";
endif;
// Execute the SQL function to retrieve all parent and child orders
resultsObjects := read as resultsType { "select ord.* from dbo.SXAFindAllResultsFromParentOrderFn(" || SQL(parentOrderKey) || "," ||
SQL(parentOrderKey) || "," ||
SQL(childResultGUIDsXML) || ", 0) ord " };
resultObjectList := ();
orderGUIDs := ();
// Use the list of objects returned from the SQL function and build up ReportType objects containing all orders and their
// matching results.
for obj in resultsObjects do
if obj.OrderGUID is not in orderGUIDs then
orderGUIDs := orderGUIDs,obj.OrderGUID;
resultObject := new ReportableType;
resultObject.ParentKey := obj.OrderGUID;
resultObject.ChildKeys := resultsObjects.resultGUID where resultsObjects.OrderGUID = obj.OrderGUID;
resultObject.ObjectType := "result";
resultObject.reason := reasonCode;
resultObjectList := resultObjectList, resultObject;
endif;
enddo;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
// return the list of result objects
return resultObjectList;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,86 @@
maintenance:
title: Check for Past Alerts;;
mlmname: STD_FUNC_CHECK_PAST_ALERTS;;
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: This MLM will check for matching alert rule groups and rule numbers that were
stored in the database within the past interval of time.
;;
explanation: Locates alert matches on RuleGroup, RuleNumber and CreatedWhen that occur within
the alert interval. The MLM is passed the rule group, rule number, client,
and interval by the calling MLM and returns TRUE if a matching alert is found
within the interval.
;;
keywords: alert, interval, rule
;;
knowledge:
type: data-driven;;
data:
(client_guid, // Client indicator
chart_guid, // Chart indicator
rule_group, // The rule group for the alert to be matched
rule_number, // The rule number for the alert to be matched
alert_interval_start, // Start date &time to check for past alerts
alert_interval_stop // Stop date &time to check for past alerts
) := ARGUMENT;
// Get all matching alerts for the given interval
(AD_CreatedWhen,
AD_Status,
AD_ClientVisitGUID,
AD_ClientGUID,
AD_ChartGUID,
AD_Description,
AD_TypeCode,
AD_EventType,
AD_RuleGroup,
AD_RuleNumber) := read{ "SELECT CreatedWhen, Status, ClientVisitGUID, ClientGUID, "
|| " ChartGUID, Description, TypeCode, EventType, RuleGroup, RuleNumber"
|| " FROM CV3AlertDeclaration "
|| " WHERE ClientGUID = " || SQL(client_guid)
|| " AND ChartGUID = " || SQL(chart_guid)
|| " AND RuleGroup = " || SQL(rule_group)
|| " AND RuleNumber = " || SQL(rule_number)
|| " AND CreatedWhen >= " || SQL(alert_interval_start)
// || " AND CreatedWhen <= " || SQL(alert_interval_stop)||")"
,PrimaryTime = CreatedWhen};
;;
evoke:
;;
logic:
if exists AD_RuleGroup then
CheckForAlertInInterval := TRUE;
else
CheckForAlertInInterval := FALSE;
endif; // check to see if alert occurred within the time interval
conclude TRUE;
;;
action:
return CheckForAlertInInterval;
;;
end:

View File

@@ -0,0 +1,166 @@
maintenance:
title: Translation MLM required by the ClinSum Tile MLMs;;
mlmname: STD_FUNC_CLINSUM_TRANSLATE;;
arden: version 2.5;;
version: 18.4;;
institution: Allscripts, Standard ClinSum MLMs;;
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:
This MLM is called by all Clinical Summary MLMs that are used by the Tiles
functionality to convert row definitions and values that were created by the
parent CLINSUM_ mlm into data structures which can be process by the calling code.
;;
explanation:
You are required to load this MLM first before attempting to run
any sample or custom CLINSUM tile MLMs.
Do not make any changes to this MLM unless authorized by Allscripts.
;;
keywords: Clinical Summary Tiles
;;
knowledge:
type: data-driven;;
data:
(rowDefinition_obj, rows_obj) := argument;
log_execution_info := false;
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
using "SCM.CDS.Core";
using namespace "CDS";
using namespace "CDSData";
;;
priority: 50
;;
evoke:
;;
logic:
// For the MLM Editor
if rowDefinition_obj is NULL OR
rows_obj is NULL
then
conclude false;
endif;
// Define the schema of CDSDataObject that will contain the row definition.
// NOTE: This schema must match the fields defined in the parent MLM.
colDefinition := new net_object {{{SINGLE-QUOTE}}}DataObjectDefinition{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "FieldName", "CDSString" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "ColumnHeader", "CDSString" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "DisplaySeqNum", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "DataType", "CDSString" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "DisplayFormat", "CDSString" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "WidthDefaultPixel", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "WidthMinPixel", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "WidthMaxPixel", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "IsVisible", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call colDefinition.AddColumn with "IsSortable", "CDSInteger" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
x := call {{{SINGLE-QUOTE}}}CDSDataObject{{{SINGLE-QUOTE}}}.DeclareObjectSchema with "ColDefinitionType", colDefinition;
rowdefinition_dataobj := call {{{SINGLE-QUOTE}}}CDSDataObject{{{SINGLE-QUOTE}}}.CreateObject with "ColDefinitionType";
// Populate the row definition data object from the Arden object
colCounter := 1 seqto (count rowDefinition_obj);
for CC in colCounter do
x := call rowdefinition_dataobj.AppendEmptyRow;
x := call rowdefinition_dataobj.SetString with
"FieldName", rowDefinition_obj[cc].FieldName as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetString with
"ColumnHeader", rowDefinition_obj[cc].ColumnHeader as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetDouble with
"DisplaySeqNum", rowDefinition_obj[cc].DisplaySeqNum as {{{SINGLE-QUOTE}}}Int32{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetString with
"DataType", rowDefinition_obj[cc].DataType as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetString with
"DisplayFormat", rowDefinition_obj[cc].DisplayFormat as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetDouble with
"WidthDefaultPixel", rowDefinition_obj[cc].WidthDefaultPixel as {{{SINGLE-QUOTE}}}Int32{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetDouble with
"WidthMinPixel", rowDefinition_obj[cc].WidthMinPixel as {{{SINGLE-QUOTE}}}Double{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetDouble with
"WidthMaxPixel", rowDefinition_obj[cc].WidthMaxPixel as {{{SINGLE-QUOTE}}}Double{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetBoolean with
"IsVisible", rowDefinition_obj[cc].IsVisible as {{{SINGLE-QUOTE}}}Boolean{{{SINGLE-QUOTE}}};
x := call rowdefinition_dataobj.SetBoolean with
"IsSortable", rowDefinition_obj[cc].IsSortable as {{{SINGLE-QUOTE}}}Boolean{{{SINGLE-QUOTE}}};
enddo;
// Create a row definition schema based on the parent definition
rowDefinition := new net_object {{{SINGLE-QUOTE}}}DataObjectDefinition{{{SINGLE-QUOTE}}};
for CC in colCounter do
x := call rowDefinition.AddColumn with
rowDefinition_obj[cc].FieldName as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}}, "CDSString" as {{{SINGLE-QUOTE}}}CDSType{{{SINGLE-QUOTE}}};
enddo;
x := call {{{SINGLE-QUOTE}}}CDSDataObject{{{SINGLE-QUOTE}}}.DeclareObjectSchema with
"RowDefinitionType", rowDefinition;
rows_dataobj := call {{{SINGLE-QUOTE}}}CDSDataObject{{{SINGLE-QUOTE}}}.CreateObject with "RowDefinitionType";
// Take the data in the arden Object and populate the CDSDataObject
rowCounter := 1 seqto (count rows_obj);
for rr in rowCounter do
x := call rows_dataobj.AppendEmptyRow;
for cc in colCounter do
columnName := rowDefinition_obj[cc].FieldName as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
if rowDefinition_obj[cc].DataType = "DateTime" then
columnValue := (attribute rowDefinition_obj[cc].FieldName from
rows_obj[rr]) as {{{SINGLE-QUOTE}}}DateTime{{{SINGLE-QUOTE}}};
x := call rows_dataobj.SetDate with ColumnName, ColumnValue;
else
// Can default string for all other types since it can be cast easily
columnValue := (attribute rowDefinition_obj[cc].FieldName from
rows_obj[rr]) as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
x := call rows_dataobj.SetString with ColumnName, ColumnValue;
endif;
enddo;
enddo;
// Reset to the start of the collection
rowdefinition_dataobj.ActiveRowPosition := 1;
rows_dataobj.ActiveRowPosition := 1;
conclude true;
;;
action:
return rowdefinition_dataobj, rows_dataobj;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,247 @@
maintenance:
title: Community Data Retrieval Rules;;
mlmname: STD_FUNC_COMMUNITY_DATA_RETRIEVAL_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: This MLM centralizes the business rules to prevent over-alerting about
certain community data by using trigger names and rights to determine
if the calling MLM should continue to check for potential issues and
if the MLM should skip the database retrieval of certain community data.
This functional MLM is called by other MLMs that generate alerts,
and it returns data indicating whether the calling MLM should:
(1) continue performing the alert checking
(2) retrieve the specified community data
;;
explanation:
The arguments passed into the MLM are:
* evoking_object - the EvokingObject
* trigger_name - the trigger name
* mlm_name - the name of the MLM that was triggered
* community_data_excluded_triggers_list - the list of trigger names to exclude
from community data retrieval. Trigger names should be listed as strings.
The data returned by the MLM are:
* can_perform - Boolean.
Indicates if calling MLM should continue the alert checking.
* can_retrieve_data_obj - an object with the following:
.PendingImportedAllergies - Boolean.
Indicates if PENDING Imported Allergies should be retrieved
from the database.
.PendingImportedMedications - Boolean.
Indicates if PENDING Imported Medications should be
retrieved from the database.
.UnreconciledImportedHealthIssues - Boolean.
Indicates if UNRECONCILED Imported Health Issues should be
retrieved from the database.
.ImportedResults - Boolean.
Indicates if Imported Results should be retrieved from
the database.
In order to avoid over-alerting enterprise-wide, if the MLM is evoked at a trigger
which is listed the community_data_excluded_triggers_list
then the data in the can_retrieve_data_obj will be set to false so that
pending or unreconciled community data are not retrieved by the calling MLM.
In order to avoid over-alerting for specific users, if the user has an override right
for a specific MLM, that MLM will not alert about potential problems with
pending or unreconciled community data. These rights are:
* NoAlert-Allergy MLM for ImportedAllergies
* NoAlert-Allergy MLM for ImportedMeds
* NoAlert-DrugDiag MLM for ImportedMeds
* NoAlert-DrugDiag MLM for ImportedProblems
* NoAlert-DrugIntx MLM for ImportedMeds
* NoAlert-DupMedTh MLM for ImportedMeds
* NoAlert-PregLact MLM for ImportedMeds
* NoAlert-LabDrug MLM for CommunityResults
* NoAlert-DupLab MLM for CommunityResults
Specific rules for User Rights:
- When the Evoking Object is for a Pending Community Allergy or Unreconciled Community
Health Issue:
. The can_perform_check flag is FALSE, when the user has the
override right that corresponds to the MLM and Trigger
Example1: "NoAlert-Allergy MLM for ImportedAllergies" right is PRESENT
for the STD_Allergy MLM with an AllergyDeclaration Evoking Object
and a Pending status at the AllergyImport Trigger
Example2: "NoAlert-DrugDiag MLM for ImportedProblems" right is PRESENT
for the STD_Drug-Diagnosis_Conflict MLM with a Health Issue Evoking Object
and an Unreconciled status at the HealthIssueImport trigger.
. The can_perform_check flag is TRUE, when the user does NOT have the
override right that corresponds to the MLM and Trigger:
Example1: "NoAlert-Allergy MLM for ImportedAllergies" right is ABSENT
for the STD_Allergy MLM with an AllergyDeclaration Evoking Object
and a Pending status at the AllergyImport trigger.
Example2: "NoAlert-DrugDiag MLM for ImportedProblems" right is ABSENT
for the STD_Drug-Diagnosis_Conflict MLM with an Health Issue Evoking Object
and an Unreconciled status at the HealthIssueImport trigger.
. The MLM will not check pending or unreconciled community data against one another.
So the can_retrieve_data object will be FALSE for all the community data flags
that at the Import Triggers.
- When the Evoking Object is NOT for a Pending Community Allergy or Unreconciled Community
Health Issue:
. The can_perform_check flag will always be TRUE, so alert checking
will always occur.
. The flags settings within the can_retrieve_data object depend on whether
the user has the override right for the MLM that is calling this funtional MLM.
Example1: PendingImportedAllergies is TRUE
when the "NoAlert-Allergy MLM for ImportedAllergies" right
is ABSENT for the Allergy MLM.
Example2: PendingImportedAllergies is FALSE
when the "NoAlert-Allergy MLM for ImportedAllergies" right
is PRESENT for the Allergy MLM
Example3: PendingImportedMedications is TRUE
when the "NoAlert-DrugIntx MLM for ImportedMeds" right
is ABSENT for the Drug Interaction MLM.
Example4: PendingImportedMedications is FALSE
when the "NoAlert-DrugIntx MLM for ImportedMeds" right
is PRESENT for the Drug Interaction MLM.
Example5: UnreconciledImportedHealthIssues is TRUE
when the "NoAlert-DrugDiag MLM for ImportedProblems" right
is ABSENT for the Drug Diagnosis MLM.
Example6: UnreconciledImportedHealthIssues is FALSE
when the "NoAlert-DrugDiag MLM for ImportedProblems" right
is PRESENT for the Drug Diagnosis MLM
;;
keywords:
Fused Agent;
Community Data;
Pending Allergy Data;
Pending Medication Data;
Unreconciled Health Issue Data;
dbMotion Data;
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Set to true if logging is needed.
log_execution_info := false;
(
evoking_object,
trigger_name,
mlm_name,
community_data_excluded_triggers_list
) := argument;
//get user rights
using "Sunrise.Clinicals.CommunityData.Helper";
using namespace "Sunrise.Clinicals.CommunityData.Helper";
HasNoAlertAllergyImportedAllergiesRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertAllergyImportedAllergiesRight;
HasNoAlertAllergyImportedMedsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertAllergyImportedMedsRight;
HasNoAlertDrugDiagImportedMedsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertDrugDiagImportedMedsRight;
HasNoAlertDrugDiagImportedProblemsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertDrugDiagImportedProblemsRight;
HasNoAlertDrugIntxImportedMedsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertDrugIntxImportedMedsRight;
HasNoAlertDupMedThImportedMedsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertDupMedThImportedMedsRight;
HasNoAlertPregLactImportedMedsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertPregLactImportedMedsRight;
HasNoAlertLabDrugForCommunityResultsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertLabDrugCommunityResultsRight;
HasNoAlertDupLabCommunityResultsRight := {{{SINGLE-QUOTE}}}UserRights{{{SINGLE-QUOTE}}}.HasNoAlertDupLabCommunityResultsRight;
CommunityDataStruct := object [ CallingMlmName, ObjectType, UserOverrideRight];
rule_list := (
// mlm, type, right for the mlm and type
(new CommunityDataStruct with "STD_Allergy", "AllergyDeclaration", HasNoAlertAllergyImportedAllergiesRight),
(new CommunityDataStruct with "STD_Allergy", "Medication", HasNoAlertAllergyImportedMedsRight),
(new CommunityDataStruct with "STD_DRUG_DIAGNOSIS_CONFLICT", "Medication", HasNoAlertDrugDiagImportedMedsRight),
(new CommunityDataStruct with "STD_DRUG_DIAGNOSIS_CONFLICT", "HealthIssueDeclaration", HasNoAlertDrugDiagImportedProblemsRight),
(new CommunityDataStruct with "STD_DRUG_INTERACTION", "Medication", HasNoAlertDrugIntxImportedMedsRight),
(new CommunityDataStruct with "STD_DUPLICATE_MEDICATION_THERAPY", "Medication", HasNoAlertDupMedThImportedMedsRight),
(new CommunityDataStruct with "STD_PREGNANCY_AND_LACTATION", "Medication", HasNoAlertPregLactImportedMedsRight),
(new CommunityDataStruct with "STD_MAIN_LAB_DRUG_INTERACTIONS", "Medication", HasNoAlertLabDrugForCommunityResultsRight),
(new CommunityDataStruct with "STD_DUPLICATE", "Medication", HasNoAlertDupLabCommunityResultsRight)
);
can_perform := false;
is_community_data := false;
if evoking_object is AllergyDeclaration then evoking_object_type := "AllergyDeclaration";
elseif evoking_object is HealthIssueDeclaration then evoking_object_type := "HealthIssueDeclaration";
elseif evoking_object is ClientPrescription then evoking_object_type := "Medication";
elseif evoking_object is Order then evoking_object_type := "Medication";
else evoking_object_type := "Other";
endif;
if ( ( evoking_object is AllergyDeclaration AND evoking_object.status = "Pending" )
or ( evoking_object is HealthIssueDeclaration AND evoking_object.InternalStateType = 1 ) // internalStateType = 1 for unreconciled
)
then
is_community_data := true;
endif;
RightTypes := object [PendingImportedAllergies, PendingImportedMedications, UnreconciledImportedHealthIssues, ImportedResults];
can_retrieve_data_obj := new RightTypes;
is_trigger_excluded := trigger_name in community_data_excluded_triggers_list;
mlm_rule_list := rule_list where rule_list.CallingMlmName = mlm_name;
if is_community_data
then
// If evoking object is community data, the calling mlm can perform community data checking if the override right does not exist
override_right_exists := last (mlm_rule_list.UserOverrideRight where mlm_rule_list.ObjectType = evoking_object_type);
can_perform := not (override_right_exists or is_trigger_excluded);
// If evoking object is community data, the business rule says never perform checking community data against community data.
// Can retrieve is always false.
can_retrieve_data_obj := new RightTypes with (false, false, false);
else
// if not community data
can_perform := true;
if is_trigger_excluded
then
can_retrieve_data_obj := new RightTypes with (false, false, false);
else
can_retrieve_data_obj.PendingImportedAllergies := last(not mlm_rule_list.UserOverrideRight where mlm_rule_list.ObjectType = "AllergyDeclaration");
can_retrieve_data_obj.PendingImportedMedications := last(not mlm_rule_list.UserOverrideRight where mlm_rule_list.ObjectType = "Medication") ;
can_retrieve_data_obj.UnreconciledImportedHealthIssues := last(not mlm_rule_list.UserOverrideRight where mlm_rule_list.ObjectType = "HealthIssueDeclaration") ;
can_retrieve_data_obj.ImportedResults := last(not mlm_rule_list.UserOverrideRight where mlm_rule_list.ObjectType = "Medication") ;
endif;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return (can_perform, can_retrieve_data_obj );
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,125 @@
maintenance:
title: Create An Action Object;;
mlmname: STD_FUNC_CREATE_ALERT_ACTION_OBJECT;;
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: This MLM declares the AlertAction Object, creates a single instance
of the object, and partially populates it with data.
;;
explanation: This MLM is called by any MLM that wants an AlertAction Object created.
1. It sets the values for the fields that repeat in every object.
2. The two arguments are used to determine if the AlertAction object
is for an Order. If it is, certain data are defaulted.
3. It sets the remaining fields to NULL.
;;
keywords:
;;
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;
/********************************************************************************/
// Arguments
(evoking_object_table, //STRING--Name of Evoking Object{{{SINGLE-QUOTE}}}s table
action_item_table ) //STRING--Name of Action Item{{{SINGLE-QUOTE}}}s table
:= ARGUMENT;
//Declare the AlertAction Object
AlertAction := OBJECT [
EvokingEnterpriseItemTable,
EvokingEnterpriseItemID,
EvokingObjectTable,
EvokingObjectID,
EvokingObjectName,
HighLevelDecision,
ActionItemStatus,
ActionEvent,
ActionItemTable,
ActionItemID,
ActionItemName,
ActionEnterpriseItemTable,
ActionEnterpriseItemID,
MLMName,
ShortMessage ];
// Create on instance of the AlertAction object.
instance := new AlertAction;
// Set the value of the HighLevelDecision field.
// This field is always "Keep".
instance.HighLevelDecision := "Keep";
// Partiallly populate one instance of the AlertAction Object
// in the Evoking and HighLevelDecision fields of the object.
// Also, instantiate the unpopulated fields to NULL.
if evoking_object_table = "CV3Order"
then
instance.EvokingEnterpriseItemTable := "CV3OrderCatalogMasterItem";
instance.EvokingEnterpriseItemID := null;
instance.EvokingObjectTable := evoking_object_table;
instance.EvokingObjectID := null;
instance.EvokingObjectName := null;
endif; //if evoking_object_table
// Partiallly populate one instance of the AlertAction Object
// in the ActionItem fields of the object.
// Also instantiate the unpopulated fields to NULL.
if action_item_table = "CV3Order"
OR action_item_table = "CV3OrderCatalogItem"
then
instance.ActionItemStatus := null;
instance.ActionEvent := null;
instance.ActionItemTable := action_item_table;
instance.ActionItemID := null;
instance.ActionItemName := null;
instance.ActionEnterpriseItemTable := "CV3OrderCatalogMasterItem";
instance.ActionEnterpriseItemID := null;
instance.MLMName := null;
instance.ShortMessage := null;
endif; //if action_item_table
;;
evoke: //MLM is called, not evoked
;;
logic:
conclude true;
;;
action:
return instance;
;;
end:

View File

@@ -0,0 +1,90 @@
maintenance:
title: STD_FUNC_DOC_REPLACE_CHAR;;
mlmname: STD_FUNC_DOC_REPLACE_CHAR;;
arden: version 2.5;;
version: 18.4;;
institution: Allscripts,Standard Document called 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: this function takes 3 parameters, it searches all occurences of the str
in second parameter, and replaces them with str in third parameter
;;
explanation: Called by DOC_STD_HOME_MED_SUMMARY.MLM.
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(Str, ToBeRepld, insertStr) := argument;
/* Set to true if a decision.log is needed */
log_execution_info := false;
// default to " ", if not passed
if (not exists insertStr) then
insertStr := " ";
endif;
if (called_by_editor) then
Str:= "This is a\ntest string to be\npassed";
ToBeRepld:="\n";
insertStr:=" ";
endif;
tmpStr:="";
strLen:=LENGTH OF Str;
if (exists Str and strLen > 0) then
// do some replacement
prepos:=1;
pos:= FIND ToBeRepld IN STRING Str STARTING AT prepos;
while pos > 0 and prepos < strLen do
tmp:=SUBSTRING pos-prepos CHARACTERS STARTING AT prepos FROM Str;
tmpStr:=tmpStr || tmp || insertStr;
prepos:=pos +1;
// find
pos:= FIND ToBeRepld IN STRING Str STARTING AT prepos;
enddo;
tmp:=SUBSTRING strLen-prepos+1 CHARACTERS STARTING AT prepos FROM Str;
tmpStr:=tmpStr || tmp;
endif;
/* Set to true if a decision.log is needed.*/
log_execution_info := false;
/////////////////////////////////////////////////////////////////////////////////////////
;;
evoke:
;;
logic:
conclude true;
;;
action:
return tmpStr;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,179 @@
maintenance:
title: Starter MLM to Create Documents;;
mlmname: STD_FUNC_DOC_WRITE_TO_DOCUMENT;;
arden: version 2.5;;
version: 18.4;;
institution: Allscripts,Standard Document Called 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: This MLM identifies the current observation in a Structured Document
instantiates the parameter.
;;
explanation: This is a basic starter MLM for all document MLMs.
;;
keywords: RTF; Document Called MLM; list; multi-select
;;
knowledge:
type: data-driven;;
data:
(this_documentCommunication,parameter_name,newValue,sugg_txt_value,UpdateType) :=
argument;
/***************Make Changes To Spelling And Flags In This Section************/
/* Set to true if a decision.log is needed.*/
log_execution_info := false;
/*****************************************************************************/
//*** Variable and Constant Declaration ***//
(this_structuredNoteDoc) := this_documentCommunication.DocumentConfigurationObj;
(this_parameters) := this_structuredNoteDoc.ParametersList;
(this_chartedObservationsList) := this_structuredNoteDoc.ChartedObservationsList;
// if the parameter type is a text and the observation already exist the new data may
// be a Replace of Append to current valueObj.Value
if not exists UpdateType OR UpdateType NOT IN("Append","Replace") then
UpdateType := "Replace";
endif;
//////////////////////////////////////////////////////////////////////////////////
//*** Data Structures ***//
// The following data structures can be used to create new objects within the MLM
// itself. Not all data structures are represented here, only ones that can be
// created in the MLM. Parameter Types
NUMERICVALUE := "NumericValue";
FREETEXTVALUE := "FreeTextValue";
LISTVALUE := "ListValue";
LISTSETVALUE := "ListSetValue";
DATEVALUE := "DateValue";
IOVALUE := "IOValue" ;
GENERICDRIPVALUE := "GenericDripValue" ;
DRIPVALUE := "DripValue" ;
ObservationType := OBJECT
[ObservationGUID, ClientDocumentGUID, ParameterGUID, DataType, ValueObj];
ListValueType := OBJECT [ListGUID,ListItemsList, SuggestedTextValue];
ListValueListItemType := OBJECT [ListItemGUID, Value, IsSelected];
DateValueType := OBJECT [Value];
FreeTextValueType := OBJECT [Value];
NumericValueType := OBJECT [Value];
//
// This section of code will demonstrate how to write to FreeTextValue, DateValue,
// NumericValue and ListValue
parameter := FIRST OF (this_Parameters WHERE this_Parameters.Name = parameter_name );
IF EXISTS parameter THEN
//****************************************************************************
// Check for existing object
//****************************************************************************
obs := first of(this_ChartedObservationsList WHERE
this_ChartedObservationsList.parameterGUID = parameter.parameterGUID) ;
if not exist obs then
//Create a new Observation for the list
obs := NEW ObservationType;
obs.ClientDocumentGUID :=
this_documentCommunication.DocumentConfigurationObj.ClientDocumentGUID;
obs.ParameterGUID := parameter.ParameterGUID;
obs.DataType := parameter.DataType;
// Based on the parameter.DataType create the ValueObj Type and set
// the valueObj.value for
// (FREETEXTVALUETYPE,DATEVALUETYPE,NUMERICVALUETYPE)
// If the DataType is LISTVALUE then creat the valueObj
// of LISTVALUETYPE ABD ASSIGN
// THE paramter.configurationObj.ListGUID
if parameter.DataType = FREETEXTVALUE then
obs.ValueObj := NEW FreeTextValueType ;
elseif parameter.DataType = DATEVALUE then
obs.ValueObj := NEW DateValueType ;
elseif parameter.DataType = NUMERICVALUE then
obs.ValueObj := NEW NumericValueType ;
elseif parameter.DataType = LISTVALUE then
obs.ValueObj := NEW ListValueType;
obs.ValueObj.ListGUID := parameter.ConfigurationObj.ListGUID;
endif; // if parameter.DataType = FREETEXTVALUE then
// APPEND obs to the ChartedObservationsList
this_documentCommunication.DocumentConfigurationObj.ChartedObservationsList := (
this_documentCommunication.DocumentConfigurationObj.ChartedObservationsList,
obs);
endif;
if parameter.DataType = FREETEXTVALUE then
if UpdateType = "Append" then
if length of obs.ValueObj.Value > 0 then
obs.ValueObj.Value := obs.ValueObj.Value || "\n" || newValue ;
else
obs.ValueObj.Value := newValue;
endif;
else // UpdateType = "Replace"
obs.ValueObj.Value := newValue;
endif;
elseif parameter.DataType IN(DATEVALUE,NUMERICVALUE) then
if exists newValue then
obs.ValueObj.Value := newValue ;
else
obs.ValueObj := null;
endif;
elseif parameter.DataType = LISTVALUE then
// Populate the ListItemsList in the new observation object (obs)
// loop through each item in the parameter.ConfugurationObj.ListItemsList using
// "item"and append the item to the newly created object ListValueListItemType
// assign the item.listItemGUID to the selectedItem.ListItemGUID,
// the Item.value to the
// selectedItem.Value and set the SelectedItem.IsSelected := true
listItems := ();
FOR item IN parameter.ConfigurationObj.ListItemsList DO
IF item.Value IN newValue THEN
//Create a list item object for the selected list item
selectedItem := NEW ListValueListItemType;
selectedItem.ListItemGUID := item.ListItemGUID;
selectedItem.Value := item.Value;
selectedItem.IsSelected := true;
// Arden list append statement appending the new object to the listItems object
// of the ListValueListItemType Object
listItems := (listItems, selectedItem);
ENDIF;
// set the obs.valueObj.ListItemsList := listItems list object
Obs.ValueObj.ListItemsList := listItems;
if exists sugg_txt_value then
obs.ValueObj.SuggestedTextValue := sugg_txt_value ;
endif ;
ENDDO;
endif; //if parameter.DataType = LISTVALUE then
ENDIF; //IF EXISTS parameter THEN
/////////////////////////////////////////////////////////////////////////////////////////////////
;;
evoke:
;;
logic:
conclude true;
;;
action:
return this_documentCommunication;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,550 @@
maintenance:
title: : Creates the Estimated Dose Administrations;;
mlmname: STD_FUNC_DOSAGE_ADMIN_TIMES;;
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: The purpose of this MLM is to create the estimated Dose Administration Date-Times
for Frequencies such as BID, Q18H, <Variable Interval>, <User Schedule>, etc.
;;
explanation: Using the data that is passed into the MLM, plus the Frequency dictionary and
the Units of Measure dictionary, the ESTIMATED Dose Administrations date-times are
created, put into a list, and then returned to the calling MLM.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
(order_med_frequency,
start_dtm,
stop_dtm,
stop_after_value,
stop_after_option_type,
freq_from_time,
from_uom,
order_TaskScheduleDefinition_obj ):= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
// The facility must map its Dictionary Codes to the Core UOM in the
// Units of Measure Dictionary. The MLM converts the facility-defined units of measure
// to the system-defined values in the Unit of Measure Dictionary called CoreUOM.
day_string := "day";
hour_string := "hr";
minute_string := "min";
month_string := "month";
ounce_string := "oz";
second_string := "s";
week_string := "week";
year_string := "year";
shift_string := "shift";
// Declare C functions to parse the frequency string
func_get_token := interface {char* msvcrt:strtok(char*, char*)};
func_get_str := interface {char* msvcrt:strstr(char*, char*)};
// Declare Task_Schedule_Definition_Object
Task_Schedule_Definition_Object := OBJECT
[ scheduled_dtm, scheduled_time, day_of_week, parent_GUID, scheduled_duration ];
//================================================================
// <User Schedule> FREQUENCY
//================================================================
if order_med_frequency = "<User Schedule>"
then
//Task_Schedule_Definition_Object := OBJECT
//[ scheduled_dtm, scheduled_time, day_of_week, parent_GUID, scheduled_duration ];
task_schedule_definition_list := read AS Task_Schedule_Definition_Object
{ TaskScheduleDefinition: ScheduledDtm, ScheduledTime, DayOfWeek, ParentGUID
REFERENCING order_TaskScheduleDefinition_obj };
//================================================================
// <Variable Interval> FREQUENCY
//================================================================
elseif order_med_frequency = "<Variable Interval>"
then
frequency_type := 3;
time_from_value := freq_from_time as number;
time_core_uom := read last
{"SELECT CoreUOM "
|| " FROM CV3UnitOfMeasure"
|| " WHERE Code = " || SQL (from_uom)
|| " AND Active = 1 " };
//================================================================
// REGULAR FREQUENCY
//================================================================
else
// Gets the Frequency information from the Enterprise data
// Only gets the Active Frequencies and Active Units of Measures
(
frequency_type,
time_from_value,
time_core_uom):= read last
{"SELECT f.DefinitionType, f.TimeFromValue, u.CoreUOM "
|| " FROM CV3Frequency AS f "
|| " LEFT OUTER JOIN CV3UnitOfMeasure AS u"
|| " ON (f.TimeUom = u.Code and u.Active=1) "
|| " WHERE f.Code = " || SQL (order_med_frequency)
|| " AND f.Active = 1 " };
endif; // if order_med_frequency
;;
evoke:
;;
logic:
// If the frequency is shift based then do not
// do any calculations. Return an empty list
// of admin times.
if time_core_uom = shift_string
then
isShiftFrequency := true;
next_startDtm := start_dtm + 24 hours;
conclude true;
endif;
isShiftFrequency := false;
//==================================================================================
// <User Schedule> Frequency
//==================================================================================
if order_med_frequency = "<User Schedule>"
then
//---------------------------------
// Set Begin_DTM
//---------------------------------
//Calculate Begin_DTM
begin_dtm := start_dtm;
//---------------------------------
// Calculate End_DTM
//---------------------------------
if stop_after_option_type = 1 //days
then
end_dtm := begin_dtm + stop_after_value DAYS;
elseif stop_after_option_type = 2 //hours
then
end_dtm := begin_dtm + stop_after_value HOURS;
elseif stop_after_option_type = 3 //minutes
then
end_dtm := begin_dtm + stop_after_value MINUTES;
elseif stop_after_option_type = 4 //times
then
//end_dtm is unknown until the DTMs are generated.
//the end_dtm will be set after the DTMs are generated.
end_dtm := null;
elseif exist stop_dtm
then
end_dtm := stop_dtm ;
endif; //if stop_after_option_type
//=============================================
// <User Schedule> -- DAILY or WEEKLY
//=============================================
if from_uom is in ( "day", "week")
then
//----------------------------------------------
// Convert Scheduled_Time to Scheduled_Duration
//----------------------------------------------
duration_list := ();
for task_schedule_definition in task_schedule_definition_list do
//Convert the Number to a String
//Extract the Characters from the String
temp_string := (""|| task_schedule_definition.scheduled_time);
temp_characters := extract characters temp_string;
//Convert the front characters to the number of hours
//Convert the back character to the number of minutes
if count (temp_characters) = 4
then
num_hours := (temp_characters[1] || temp_characters[2]) AS NUMBER ;
num_minutes := (temp_characters[3] || temp_characters[4]) AS NUMBER ;
elseif count (temp_characters) = 3
then
num_hours := (temp_characters[1]) AS NUMBER ;
num_minutes := (temp_characters[2] || temp_characters[3]) AS NUMBER ;
elseif count (temp_characters) = 2
then
num_hours := 0;
num_minutes := (temp_characters[1] || temp_characters[2]) AS NUMBER ;
elseif count (temp_characters) = 1
then
num_hours := 0 ;
num_minutes := ("" || temp_characters[1]) AS NUMBER ;
endif;
//Add the Hours and Minutes and put them in a list
duration_list := duration_list, ( num_hours HOUR) + (num_minutes MINUTE) ;
enddo; //for task_schedule_definition
//Set the Scheduled_Duration in the Task_Schedule_Definition_Object
task_schedule_definition_list.scheduled_duration := duration_list;
//--------------------------------------------------------------
// Determine how to increment "Every X Days" or "Every Y Weeks"
//--------------------------------------------------------------
if from_uom = "day"
then
increment_duration := freq_from_time DAY;
elseif from_uom = "week"
then
increment_duration := freq_from_time WEEK;
endif; //if from_uom = "day"
//-----------------------------------------------------
// Generate the first set of DTMs based on the schedule
//-----------------------------------------------------
//task_schedule_definition_list.day_of_week values
// 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thur, 5=Fri, 6=Sat
// 7=DayOnly
//Initialize Variables
midnight_begin_dtm := day floor of begin_dtm;
original_schedule_dtm_list := ();
for task_schedule_definition in task_schedule_definition_list do
if task_schedule_definition.day_of_week < 7
then //Figure Out Which Day of the Week to Create
from_day_of_week := (day floor of begin_dtm - week floor of begin_dtm ) / 1 day;
to_day_of_week := task_schedule_definition.day_of_week;
if to_day_of_week >= from_day_of_week
then //it is this week
number_of_days := to_day_of_week - from_day_of_week ;
else //it is next week
number_of_days := (7 - from_day_of_week) + to_day_of_week;
endif; //if to_day_of_week
temp_dtm1 := midnight_begin_dtm + (number_of_days day)
+ task_schedule_definition.scheduled_duration ;
else //It is not a day of the week. It is the initial day.
temp_dtm1 := midnight_begin_dtm
+ task_schedule_definition.scheduled_duration ;
endif; //if task_schedule_definition.day_of_week < 7
//Append DTM to List
original_schedule_dtm_list := original_schedule_dtm_list, temp_dtm1;
enddo; //for task_schedule_definition
//--------------------------------------------
// Create a Valid Set of Sorted Scheduled DTMs
//--------------------------------------------
original_schedule_dtm_list := Sort DATA original_schedule_dtm_list;
//-----------------------------------------------------------------------
// For DAYS, move any DTMs forward when they are less than the Begin_DTM
//-----------------------------------------------------------------------
if from_uom = "day"
then
temp_past_dtm_list := original_schedule_dtm_list where it < begin_dtm;
temp_current_dtm_list := original_schedule_dtm_list where it >= begin_dtm ;
updated_schedule_dtm_list := temp_current_dtm_list;
for past_dtm in temp_past_dtm_list do
temp_future_dtm := past_dtm + 1 day;
updated_schedule_dtm_list := updated_schedule_dtm_list, temp_future_dtm;
enddo;
//-------------------------------------------------------------------------------
// For WEEKS, do not move any DTMs forward when they are less than the Begin_DTM
//-------------------------------------------------------------------------------
elseif from_uom = "week"
then
updated_schedule_dtm_list := original_schedule_dtm_list;
endif; //if from_uom
//-----------------------------------------
// Finish Creating all the rest of the DTM
//-----------------------------------------
//Get the last DTM in the list
new_dtm := last updated_schedule_dtm_list;
//Initialize Variables
admin_dtm_list := updated_schedule_dtm_list;
multiplier := 0;
if stop_after_option_type = 4 //4 = TIMES
then //Use the TIMES to stop generating DTMs
admin_dtm_list := updated_schedule_dtm_list where it >= begin_dtm;
count_of_dtm := count admin_dtm_list;
//If there aren{{{SINGLE-QUOTE}}}t enough DTM{{{SINGLE-QUOTE}}}s then generate more
if stop_after_value > count_of_dtm
then
num_of_dtm := count_of_dtm;
While num_of_dtm <= stop_after_value do
//Increment num_of_dtm
num_of_dtm := num_of_dtm + (count of updated_schedule_dtm_list);
//Increment the multiplier
multiplier := multiplier + 1;
//Generate new DTM by looping through the list DTMS and
//increasing the duration of each one
for temp_dtm2 in (updated_schedule_dtm_list) do
new_dtm := temp_dtm2 + (increment_duration * multiplier) ;
admin_dtm_list := admin_dtm_list, new_dtm;
enddo; //for temp_dtm2
enddo; //While num_of_dtm
endif; //if stop_after_value
//only keep the number of DTM{{{SINGLE-QUOTE}}}s needed
admin_dtm_list := first stop_after_value FROM admin_dtm_list;
//set the end_dtm
end_dtm := last admin_dtm_list;
else //Use the End_Dtm to stop generating DTMs
While new_dtm <= end_dtm do
//Increment the multiplier
multiplier := multiplier + 1;
//Generate new DTM by looping through the list DTMS and
//increasing the duration of each one
for temp_dtm2 in (updated_schedule_dtm_list) do
new_dtm := temp_dtm2 + (increment_duration * multiplier) ;
if new_dtm <= end_dtm
then
admin_dtm_list := admin_dtm_list, new_dtm;
endif; //if new_dtm
enddo; //for temp_dtm2
enddo; //While new_dtm
endif; //if stop_after_option_type = 4
//=============================================
// <User Schedule> -- IRREGULAR
//=============================================
else //Use the ScheduledDtm to set the Admin DTMS
if exist task_schedule_definition_list.scheduled_dtm
then
admin_dtm_list := Sort DATA task_schedule_definition_list.scheduled_dtm;
else
admin_dtm_list := null;
endif; //if exist task_schedule_definition_list.scheduled_dtm;
endif; //if from_uom
//---------------------------------------------------
// Remove any dates outside of Begin_DTM and End_DTM
//---------------------------------------------------
admin_dtm_list := admin_dtm_list where (it >= begin_dtm and it <= end_dtm);
//==================================================================================
// REGULAR OR <Variable Interval> FREQUENCY
//==================================================================================
else
//------------------------------------
// Frequency <QxH> and <QxM> Template
//------------------------------------
// Handle frequency templates <qxh> and <qxm> by parsing the frequency string
// If changes are made to this code, also change them in SYS_CALC_FREQMULT_AVERAGE
// This is a temporary workaround for frequency templates
If NOT Exist frequency_type
then
// Declare characters used for delimiting the string
// Delimiters are Case Sensitive
q_delim:= "Q";
h_delim:= "H";
m_delim:= "M";
// Determine if the letter in at the back of the string is H or M
get_H:= call func_get_str with (order_med_frequency, h_delim);
get_M:= call func_get_str with (order_med_frequency, m_delim);
// Remove the front Q, so xH or xM is left
trim_Q:= call func_get_token with (order_med_frequency, q_delim);
// Set the time_core_uom
// Remove the H or the M, leaving a string representation of a number
if exist get_H
then
time_core_uom := hour_string;
freq_num_str := call func_get_token with (trim_Q, h_delim);
elseif exist get_M
then time_core_uom := minute_string;
freq_num_str := call func_get_token with (trim_Q, m_delim);
endif; // if exist get_H
// Convert string to number
time_from_value := freq_num_str as number;
endif; // If NOT Exist frequency_type
//--------------------------------
// Convert Frequency to Durations
//--------------------------------
if time_core_uom = day_string then
if frequency_type = 1 // y times per day
then time_interval:= 1 DAY /time_from_value;
else time_interval:= time_from_value DAY ;
endif;
elseif time_core_uom = hour_string then
if frequency_type = 1 // y times per hour
then time_interval:= 1 HOUR /time_from_value;
else time_interval:= time_from_value HOUR ;
endif;
elseif time_core_uom = minute_string then
if frequency_type = 1 // y times per minute
then time_interval:= 1 MINUTE /time_from_value;
else time_interval:= time_from_value MINUTE ;
endif;
elseif time_core_uom = second_string then
if frequency_type = 1 // y times per second
then time_interval:= 1 SECOND /time_from_value;
else time_interval:= time_from_value SECOND ;
endif;
elseif time_core_uom = week_string then
if frequency_type = 1 // y times per week
then time_interval:= 1 WEEK /time_from_value;
else time_interval:= time_from_value WEEK ;
endif;
elseif time_core_uom = month_string then
if frequency_type = 1 // y times per month
then time_interval:= 1 MONTH /time_from_value;
else time_interval:= time_from_value MONTH ;
endif;
elseif time_core_uom = year_string then
if frequency_type = 1 // y times per year
then time_interval:= 1 YEAR /time_from_value;
else time_interval:= time_from_value YEAR ;
endif;
endif; // if time_core_uom
// Calculate the Number of Administrations
// Calculation uses CEILING to round the calculation up to
// the next whole number.
if NOT exist order_med_frequency OR frequency_type = 0
then
// Assume that one dose is administered if the frequency is NULL
// or NONE regardless of the values for StopDtm or a StopAfter.
number_of_admins := 1;
elseif stop_after_option_type = 1 //days
then
total_time := 1 day * stop_after_value;
number_of_admins := ceiling (total_time/time_interval);
elseif stop_after_option_type = 2 //hours
then
total_time := 1 hour * stop_after_value;
number_of_admins := ceiling (total_time/time_interval);
elseif stop_after_option_type = 3 //minutes
then
total_time := 1 minute * stop_after_value;
number_of_admins := ceiling (total_time/time_interval);
elseif stop_after_option_type = 4 //times
then
number_of_admins := truncate (stop_after_value);
elseif exist stop_dtm
and exist order_med_frequency
then
//Calculate the amount of time between the start_dtm and stop_dtm.
//Adjust by adding 1 minute because the orders application calculates the
//stop_dtm by multiplying the number of days by 24 hours and subtracting 1 minute.
//We have to restore the 1 minute because this algorithm truncates, rather than rounds up.
//Example: 1 day is 2005-11-05T00:00:00 to 2005-11-05T23:59:00,
//rather than 2005-11-06T00:00:00
total_time := stop_dtm - start_dtm + 1 minute;
number_of_admins := ceiling (total_time/time_interval); // rounds up
else
//If the time_interval greater than 24 hours
If (time_interval / 24 hours) > 1
then //There is only 1 administration during the time_interval
number_of_admins := 1;
else //Calculate the number of administrations in 24 hours
// by Rounding Up to the full day if there is a decimal
number_of_admins := ceiling (24 HOURS/ time_interval);
endif; //If (time_interval / 24 hours)
endif; //if NOT exist order_med_frequency
//----------------------------------------------
// Generate the Administration Date-Times (DTM)
//----------------------------------------------
//Initialize the list to append date-times
admin_dtm_list := ();
//Generate the date-times
for JJ in (1 seqto number_of_admins) do
if JJ = 1
then
temp_date := start_dtm;
else
temp_date := temp_date + time_interval;
endif;
admin_dtm_list := admin_dtm_list, temp_date;
enddo;
// Generate an end_dtm that can be used as
// the start date of the next component if needed.
next_startDtm := temp_date + time_interval;
endif; //if order_med_frequency = "<User Schedule>"
//-----------------
// Debug Variables
//-----------------
DEBUG_Number_Of_Days_In_Time_Interval := time_interval/ 1 DAY;
DEBUG_Number_Of_Hours_In_Time_Interval := time_interval/ 1 HOUR;
DEBUG_Number_Of_Minutes_In_Time_Interval := time_interval/ 1 MINUTE;
DEBUG_Number_Of_Seconds_In_Time_Interval := time_interval/ 1 SECOND;
DEBUG_admin_dtm_list := admin_dtm_list;
// If no next_startDtm at this point, take the last administration time
// and add 24 hours. This can be used as the start of next component
// for a complex order.
if next_startDtm is null then
next_startDtm := last admin_dtm_list + 24 hours;
endif;
// Always Conclude True
Conclude true;
;;
action:
return admin_dtm_list, next_startDtm, isShiftFrequency;
;;
end:

View File

@@ -0,0 +1,240 @@
maintenance:
title: Creates the Generated Administration Date-Times;;
mlmname: STD_FUNC_DOSAGE_ADMIN_TIMES_GENERATED;;
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: The purpose of this MLM is to calculate the Dose Administration Date-Times
for any order passed in.
;;
explanation: This MLM will call the methods that generate the administration times
based on business rules found on library SCMLib.CDS.
1. DetermineAdministrationSchedule is used to generate
Dose Administration Date-Times for Regular Orders and IV-Additives.
2. DetermineAdministrationScheduleForVarComponents is used to
generate Dose Administration Date-Times for
Complex Orders (Dosing Options).
There are two version of each method. If the Start Date-Time is null OR the
Stop Date-Time is null, the method is called without the date-times. The
missing date-times are set by the method and the Administration Date-Times
will be generated accordingly. If the Start Date-Time and the Stop Date-Time
are available, then the date-times are passed to the method and the method
will use them to generate the Administration Date-Times.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
(order_GUID,
component_GUID,
start_dtm,
stop_dtm,
isFirstComponent,
isLastComponent ):= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
// Set to true if task/occurences already generated should be considered
IncludePerformed := TRUE;
IncludeProvisionalAdminTimes := FALSE;
// Load the correct version of .NET 2.0
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using "SCMLib.CDS";
// List of admin times to be returned
admin_dtm_list := ();
// If the list of admin times was able to be calculated correctly. The list maybe empty
// which is a valid condition.
schedule_calculated := true;
// Get the order type from the EvokingObject
(complex_order_type) := read last
{ Order: ComplexOrderType
REFERENCING EvokingObject};
;;
evoke:
;;
logic:
isShiftAdmin := false;
if order_GUID is NULL then
conclude TRUE;
endif;
try
// Class defined in SCMLib OrderPObj.h
CalcObjType := "[SCMLib.CDS]SCMLib.CDS.OrderCalculations" as "System.Type";
// Create an order object and populate it with the current order
CalcObj := new net_object CalcObjType;
loadStatus := call CalcObj.Populate with order_GUID;
calculate_administrations := true;
while calculate_administrations do
// Loop only runs once unless logic later on specifies
// that it needs to be run a second time.
calculate_administrations := false;
// Process as a Regular order or IV-Additive
if component_GUID is null
then
if start_dtm is null OR stop_dtm is null
then
adminScheduleObj := call CalcObj.DetermineAdministrationSchedule
with IncludePerformed as "System.Boolean";
else
adminScheduleObj := call CalcObj.DetermineAdministrationSchedule
with start_dtm as "System.DateTime",
stop_dtm as "System.DateTime",
IncludePerformed as "System.Boolean";
endif;
else // Process as a Complex Order
if start_dtm is null OR stop_dtm is null
then
adminScheduleObj := call CalcObj.DetermineAdministrationScheduleForVarComponents
with component_GUID as "System.String",
IncludePerformed as "System.Boolean";
else
adminScheduleObj := call CalcObj.DetermineAdministrationScheduleForVarComponents
with component_GUID as "System.String",
start_dtm as "System.DateTime",
stop_dtm as "System.DateTime",
IncludePerformed as "System.Boolean";
endif;
endif; // If component_GUID is null
// Take the information returned by the .NET call to get the list of admin times
if adminScheduleObj is not null
then
foundAdminTimes := first adminScheduleObj.AdministrationOccur is not NULL;
AdminTimes := count of (adminScheduleObj.AdministrationOccur);
// If the frequence is shift based then ignore any admin times generated and
// return false to the calling MLM
isShiftAdmin := adminScheduleObj.FrequencySchedule is not NULL AND
adminScheduleObj.FrequencySchedule.FreqUOM = "Shift";
if foundAdminTimes AND not isShiftAdmin
then
for occ in adminScheduleObj.AdministrationOccur do
fromDtm := occ.AdminFromDtm;
// Only reset the admin time for a unscheduled recurring if it a regular
// or concurrent order or if it is the first component of a sequential.
if complex_order_type is in (0,3) OR // Regular or Concurrent
( complex_order_type is in (1,5) AND isFirstComponent ) // Sequential or Multiple and first
then
// If the frequency is unscheduled recurring it can throw the 24 hour range off
// Therefore for the first {{{SINGLE-QUOTE}}}day{{{SINGLE-QUOTE}}} of administrations set the from time of the
// occurrence for calcuations purposes to be 00:00 or the start of shift
if adminScheduleObj.AdminScheduleType = "Unscheduled" AND
adminScheduleObj.AdminProcessType = "Recurring" AND
adminScheduleObj.StartDtm = occ.AdminFromDtm
then
fromDtm := day floor of fromDtm;
endif;
endif;
// Provisional Admin times are generated when the order date/time is
// outside a time range specified when creating the frequency translation
// The hospital can configure if they want to include this provisional admin
// in the calculations.
isProvisionalAdmin := occ.AdminToDtm is NOT NULL AND
adminScheduleObj.AdminScheduleType = "Scheduled" AND
adminScheduleObj.AdminProcessType = "Recurring";
// Add the calculated admin time to the list of times. The Provisional admin
// time can be skipped
if (isProvisionalAdmin = true AND IncludeProvisionalAdminTimes = true) OR
isProvisionalAdmin = false
then
admin_dtm_list := admin_dtm_list, fromDtm;
endif;
enddo; // for occ
else // if No admin times
// For complex sequential order, if the last component didn{{{SINGLE-QUOTE}}}t have a
// a stop date and the order object was unable to determine any administration
// times, set a stop date of 3 days from the start of the component and try
// the calculations again.
if stop_dtm is NULL AND
adminScheduleObj.StartDtm is not NULL AND
complex_order_type is in (1,5) AND
isLastComponent AND
not isShiftAdmin
then
start_dtm := adminScheduleObj.StartDtm;
stop_dtm := adminScheduleObj.StartDtm + (3 Day - 1 minute);
calculate_administrations := true; // try again.
else
// Report no admin times as an error in all cases
schedule_calculated := false;
endif;
endif;
else
schedule_calculated := false;
endif;
enddo; // while calculate_administrations
endtry;
catch exception ex
// error trying to access the object, return an empty list
admin_dtm_list := ();
schedule_calculated := false;
endcatch;
Conclude true;
;;
action:
return admin_dtm_list, schedule_calculated, isShiftAdmin;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,205 @@
maintenance:
title: Create Lists of the Weights for the Dose Basis;;
mlmname: STD_FUNC_DOSAGE_BASIS;;
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: The MLM determines which Weight should be used for dosage-range checking.
;;
explanation: In the Dosage Calculation UI, the user can specify which type of weight
or BSA should be used to calculate the dose. Examples of the types are:
actual KG, KG (ADJUSTED), KG (IDEAL), actual M2, M2 (ADJUSTED), M2 (IDEAL)
The correct weight is determined by calling a system MLM that calcuates the
differnt types of weight. The information is then passed back to the calling program.
NOTE: When a facility adds codes to the CALCULATION OPTION Dictionary,
this MLM will NOT automatically adjust for any codes that use IDEAL or
ADJUSTED weights in them. You must manually added the codes to the following
variables: ADJUSTED_COMPARE_STRING and/or IDEAL_COMPARE_STRING
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
(ht_cm, //A number. Patient{{{SINGLE-QUOTE}}}s height in centimeter
wt_kg, //A number. Patient{{{SINGLE-QUOTE}}}s weight in kilograms
calc_med_per_uom_list //A list that is the DOSE BASIS such as "kg (ideal)", "m2 (adjusted)"
) := ARGUMENT;
/* Set to true if logging is needed.*/
log_execution_info := false;
/* Lists to determine which weight dose basis uses: ideal, adjusted, actual, or unspecified */
/* DO NOT CHANGE the values in the kg_compare_string and the m2_compare_string */
kg_compare_string := ("kg", "kg (ideal)", "kg (adjusted)");
m2_compare_string := ("m2", "m2 (ideal)", "m2 (adjusted)");
actual_compare_string := ("kg", "m2");
adjusted_compare_string := ("kg (adjusted)", "m2 (adjusted)",
"AUC (Cockcroft-Gault adjusted)", "AUC (Jelliffe adjusted)");
ideal_compare_string := ("kg (ideal)", "m2 (ideal)",
"AUC (Cockcroft-Gault ideal)", "AUC (Jelliffe ideal)" );
/* Declare the MLMs that can be called */
calculate_weight := MLM {{{SINGLE-QUOTE}}}sys_calc_WT{{{SINGLE-QUOTE}}};
/* Get ClientInfo Object */
client_info_obj := read last {ClientInfo: This };
;;
evoke:
;;
logic:
/*-----------------------------------------*/
/* Modify Lists For Ideal & Adjust Weights */
/*-----------------------------------------*/
/* Initalize Variables */
calc_text_list := ();
dose_basis := "";
dose_basis_list := ();
wt_kg_list := ();
updated_calc_med_per_uom_list := ();
index_list:= 1 seqto(count calc_med_per_uom_list);
for M in index_list do
user_value_item := first (calc_med_per_uom_list where index_list = M);
if user_value_item is in kg_compare_string
then
if user_value_item is in ideal_compare_string
then
temp_user_value_item := "kg";
dose_basis := "Ideal";
calc_text_list := calc_text_list, " (using ideal weight).";
elseif user_value_item is in adjusted_compare_string
then
temp_user_value_item := "kg";
dose_basis := "Adjusted";
calc_text_list := calc_text_list, " (using adjusted weight).";
elseif user_value_item is in actual_compare_string
then
temp_user_value_item := "kg";
dose_basis := "Actual";
calc_text_list := calc_text_list, ".";
else
temp_user_value_item := NULL;
dose_basis := "Unspecified";
calc_text_list := calc_text_list, ".";
endif; // if user_value_item is in ideal_compare_string
elseif user_value_item is in m2_compare_string
then
if user_value_item is in ideal_compare_string
then
temp_user_value_item := "m2";
dose_basis:= "Ideal";
calc_text_list := calc_text_list, " (using ideal BSA).";
elseif user_value_item is in adjusted_compare_string
then
temp_user_value_item := "m2";
dose_basis := "Adjusted";
calc_text_list := calc_text_list, " (using adjusted BSA).";
elseif user_value_item is in actual_compare_string
then
temp_user_value_item := "m2";
dose_basis := "Actual";
calc_text_list := calc_text_list, ".";
else
temp_user_value_item := NULL;
dose_basis := "Unspecified";
calc_text_list := calc_text_list, ".";
endif; //user_value_item is in ideal_compare_string
else
//This is a customer supplied entry in the CV3CalculationOption table
//Or a dose basis from the AUC group
if user_value_item is in ideal_compare_string
then
temp_user_value_item := NULL;
dose_basis := "Ideal";
calc_text_list := calc_text_list, " (using ideal weight).";
elseif user_value_item is in adjusted_compare_string
then
temp_user_value_item := NULL;
dose_basis := "Adjusted";
calc_text_list := calc_text_list, " (using adjusted weight).";
else
temp_user_value_item := NULL;
dose_basis := "Unspecified";
calc_text_list := calc_text_list, ".";
endif; // if user_value_item is in ideal_compare_string
endif; //if user_value_item is in kg_compare_string
/*--------------------------------------------------------*/
/* Append the DOSE BASIS and the Updated PER UOM to Lists */
/*--------------------------------------------------------*/
dose_basis_list := dose_basis_list, dose_basis;
/* Changes calc_med_per_uom_list to KG or M2 where values include (ideal) or (adjusted) */
/* Note: temp_user_value_item should be NULL, except for the values listed */
/* in the kg_compare_string and the m2_compare_string */
/* The purpose of this statement is to replace the IDEAL and ADJUSTED values */
/* in the strings such as "KG (ideal)" so that dosage-range checking will continue to */
/* match the KG or M2 in the "PER WT OR M2" field dosage-range configuration */
updated_calc_med_per_uom_list := updated_calc_med_per_uom_list, temp_user_value_item;
/*---------------------------------------------------------*/
/* Get the WEIGHT-- null, actual, ideal or adjusted weight */
/*---------------------------------------------------------*/
if dose_basis is in ( "Ideal", "Adjusted" )
then
(wt_kg_str, Tooltip_formula, display_message) := call calculate_weight
with (dose_basis, ht_cm, wt_kg, client_info_obj);
wt_kg_list := wt_kg_list, (wt_kg_str AS NUMBER);
elseif dose_basis = "Actual"
then
wt_kg_list := wt_kg_list, (wt_kg AS NUMBER);
else
wt_kg_list := wt_kg_list, (wt_kg AS NUMBER);
endif; //if dose_basis
enddo; //for M in index_list do
/*-------------------------------------------*/
/* Always conclude true to return the values */
/*-------------------------------------------*/
conclude true;
;;
action:
return
(calc_text_list,
dose_basis_list,
wt_kg_list,
updated_calc_med_per_uom_list );
;;
end:

View File

@@ -0,0 +1,121 @@
maintenance:
title: Summed Dose Versus Conversion Factor Methods;;
mlmname: STD_FUNC_DOSAGE_CALC_METHOD;;
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: Returns a string indicating the type of dosage range calculation to use:
SUMMED OR CONVERSION
;;
explanation: This MLM determines if the Dosage Range check should be done
using the SUMMED DOSE or the CONVERSION FACTOR approach.
If the following conditions are met, the calculation type used will be SUMMED.
if the order type is "Complex Order"
if the order type is "IV-Additive" AND the first component is "Complex Order"
If the order duration is less than 24 hours
If the order frequency is <User Scheduled> or <Multiple>
If the stop after option for the order is TIMES (4)
;;
keywords: Dosage Range
;;
knowledge:
type: data-driven;;
data:
( med_data_list ) := ARGUMENT;
/* Set to true if logging is needed.*/
log_execution_info := false;
return_value := "SUMMED";
from_uom := med_data_list[1].freq_uom;
order_med_frequency := med_data_list[1].order_med_frequency;
if order_med_frequency <> "<User Schedule>"
then
(time_core_uom) := read last
{"SELECT u.Code, u.CoreUOM"
|| " FROM CV3UnitOfMeasure u"
|| " INNER JOIN CV3Frequency f"
|| " ON (f.Code like {{{SINGLE-QUOTE}}}Variable Interval{{{SINGLE-QUOTE}}} AND u.Code = " || SQL(from_uom) || ")"
|| " OR (f.Code = " || SQL(order_med_frequency) || " AND f.TimeUom = u.Code ) "
|| " WHERE u.Active = 1"
};
endif;
;;
evoke:
;;
logic:
//------------------------------------
//Calculate the Duration of the Order
//------------------------------------
if med_data_list[1].stop_after_option_type = 1
then order_duration := med_data_list[1].stop_after_value DAY;
elseif med_data_list[1].stop_after_option_type = 2
then order_duration := med_data_list[1].stop_after_value HOUR;
elseif med_data_list[1].stop_after_option_type = 3
then order_duration := med_data_list[1].stop_after_value MINUTE;
elseif exist med_data_list[1].stop_dtm
then order_duration := med_data_list[1].stop_dtm
- med_data_list[1].order_med_significant_date;
else
order_duration := NULL;
endif;
//***************
// CLINICAL RULE
//***************
if med_data_list[1].is_order
AND
(med_data_list[1].med_order_type = "Complex Order"
OR (med_data_list[1].med_order_type = "IV-Additive"
AND med_data_list[2].med_order_type = "Complex Order")
OR order_duration < 24 hours
OR med_data_list[1].order_med_frequency is in ("<User Schedule>","<Multiple>")
OR med_data_list[1].stop_after_option_type = 4 // Stop after X times(
OR time_core_uom = "shift" // Shift based frequency
)
then
return_value := "SUMMED"; // Summed dose
else
return_value := "CONVERSION"; // Conversion factor
endif;
conclude true;
;;
action:
return return_value;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,286 @@
maintenance:
title: Calculates the stop date/time for an order;;
mlmname: STD_FUNC_DOSAGE_CALC_STOPDTM;;
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: Calculates the stop date for an order that does not have one.
;;
explanation: This MLM will calculate the StopDtm for an order based on
information in the orders{{{SINGLE-QUOTE}}}s frequency.
Stop After (except for Stop after X Times)
<User Schedule>
Daily, Weekly, Irregular
<Variable Interval>
Every M to N UNITS
QnH and QnM templates
Standard Frequencies without a stop after
Every N UNITS
Every M to N UNITS
N Times per UNIT
Does not work for orders that are <Continous> or <EventBased> when
there is no Stop After or Frequency configured.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// Set to true if logging is needed.
log_execution_info := false;
// Declare C functions to parse the frequency string
func_get_token := interface {char* msvcrt:strtok(char*, char*)};
func_get_str := interface {char* msvcrt:strstr(char*, char*)};
// The facility must map its Dictionary Codes to the Core UOM in the
// Units of Measure Dictionary. The MLM converts the facility-defined units of measure
// to the system-defined values in the Unit of Measure Dictionary called CoreUOM.
DAY_STRING := "day";
HOUR_STRING := "hr";
MINUTE_STRING := "min";
MONTH_STRING := "month";
SECOND_STRING := "s";
WEEK_STRING := "week";
YEAR_STRING := "year";
// Frequency Types
NONE := 0;
N_TIMES_PER_UNIT := 1;
EVERY_N_UNITS := 2;
EVERY_X_TO_Y_UNITS := 3;
STOP_AFTER_DAYS := 1;
STOP_AFTER_HOURS := 2;
STOP_AFTER_MINUTES := 3;
STOP_AFTER_TIMES := 4;
// Parameter list
( FrequencyCode,
StartDtm,
FreqUOM,
FreqFromTime,
FreqToTime,
StopAfterValue,
StopAfterOption,
TaskSchedObj ) := ARGUMENT;
//----------------------------------------------------------
// Load some data first based on the freqency type
//----------------------------------------------------------
// If Irregular, need to retrieve and sort the list of Scheduled Times.
if FrequencyCode = "<User Schedule>"
then
if FreqUom is NULL // = "Irregular"
then
ScheduledDtmList := read { TaskScheduleDefinition: ScheduledDtm referencing TaskSchedObj };
ScheduledDtmList := sort data ScheduledDtmList;
endif;
elseif FrequencyCode = "<Variable Interval>"
then
frequency_type := EVERY_X_TO_Y_UNITS;
time_core_uom := read last
{"SELECT CoreUOM "
|| " FROM CV3UnitOfMeasure"
|| " WHERE Code = " || SQL (FreqUom)
|| " AND Active = 1 " };
else
// Gets the Frequency information from the Enterprise data
// Only gets the Active Frequencies and Active Units of Measures
(frequency_type,
FreqFromTime,
FreqToTime,
time_core_uom):= read last
{"SELECT f.DefinitionType, f.TimeFromValue, f.TimeToValue, u.CoreUOM "
|| " FROM CV3Frequency AS f "
|| " LEFT OUTER JOIN CV3UnitOfMeasure AS u"
|| " ON (f.TimeUom = u.Code and u.Active=1) "
|| " WHERE f.Code = " || SQL (FrequencyCode)
|| " AND f.Active = 1 " };
endif;
// If there is a TO value use it for any calculations
if FreqToTime > 0
then
freq_time := FreqToTime;
else
freq_time := FreqFromTime;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
dateOffset := 0 minutes;
//--------------------------------------------------
// Calculate Stop After Days/Hours/Minutes.
// Does not handle times
// This calculation overrides any other calculation
//--------------------------------------------------
if StopAfterOption > 0
then
if StopAfterOption = STOP_AFTER_DAYS
then dateOffset := StopAfterValue DAYS;
elseif StopAfterOption = STOP_AFTER_HOURS
then dateOffset := StopAfterValue HOURS;
elseif StopAfterOption = STOP_AFTER_MINUTES
then dateOffset := StopAftervalue MINUTES;
elseif StopAfterOption = STOP_AFTER_TIMES // Do not calculate
then dateOffset := 0 DAYS;
endif;
else
// For user scheduled orders
if ( FrequencyCode = "<User Schedule>" )
then
//-------------------------------------
// Calculate Every X UNITS based on
// Frequence of <User Scheduled>
//-------------------------------------
if FreqUOM = "day"
then dateOffset := freq_time DAYS; // Every X days
elseif FreqUOM = "week"
then dateOffset := freq_time WEEKS; // Every X weeks
else calculated_stopDtm := last of ScheduledDtmList; // Irregular
endif;
elseif FrequencyCode = "<Multiple>"
then
; // Do nothing for Multiple
else // All other Frequency Codes
//-------------------------------------------------------
// Frequency <QxH> and <QxM> Template
// Handle frequency templates <qxh> and <qxm> by
// parsing the frequency string
// Set the frequency_type, time_core_uom and freq_time
// values to be passed on to the next calculation
If NOT Exist frequency_type AND dateOffset <= 0 minutes
then
frequency_type := EVERY_N_UNITS ;
// Declare characters used for delimiting the string
// Delimiters are Case Sensitive
q_delim:= "Q";
h_delim:= "H";
m_delim:= "M";
// Determine if the letter in at the back of the string is H or M
get_H:= call func_get_str with (FrequencyCode, h_delim);
get_M:= call func_get_str with (FrequencyCode, m_delim);
// Remove the front Q, so xH or xM is left
trim_Q:= call func_get_token with (FrequencyCode, q_delim);
// Set the time_core_uom
// Remove the H or the M, leaving a string representation of a number
if exist get_H
then
time_core_uom := HOUR_STRING;
freq_num_str := call func_get_token with (trim_Q, h_delim);
elseif exist get_M
then time_core_uom := MINUTE_STRING;
freq_num_str := call func_get_token with (trim_Q, m_delim);
endif; // if exist get_H
// Convert string to number
freq_time := freq_num_str as number;
endif; // If NOT Exist frequency_type
//-----------------------------------------------
// Convert Frequency to Durations
// frequency_type of 1 = N times per UNIT
// 2 = Every N UNITS
// 3 = Every X to Y UNITS (Use Y in calculations)
//-----------------------------------------------
if frequency_type = N_TIMES_PER_UNIT
then
// Assume only a single day
if time_core_uom is in ( DAY_STRING, HOUR_STRING, MINUTE_STRING, SECOND_STRING )
then dateOffset := 1 DAY;
endif;
elseif frequency_type = NONE
then
// If frequency type is NONE then assume a single day.
dateOffset := 1 DAY;
else // Type 2 and 3
// Rounds up to the next whole day
if time_core_uom = DAY_STRING
then dateOffset := ceiling (freq_time DAY / 1 DAY) DAYS;
elseif time_core_uom = HOUR_STRING
then dateOffset := ceiling (freq_time HOUR / 1 DAY) DAYS;
elseif time_core_uom = MINUTE_STRING
then dateOffset := ceiling (freq_time MINUTE / 1 DAY) DAYS;
elseif time_core_uom = SECOND_STRING
then dateOffset := ceiling (freq_time SECOND / 1 DAY) DAYS;
endif;
endif; // Frequency Type
endif; // Frequency Code
endif; // StopAfterOption
//-----------------------------------------------------------
// Calculate the stop date by adding the calculated offset
//-----------------------------------------------------------
if calculated_stopDtm is null AND dateOffset > 0 minutes
then
calculated_stopDtm := (startDtm + dateOffset) - 1 MINUTE;
endif;
conclude true;
;;
action:
return calculated_stopDtm;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,321 @@
maintenance:
title: Extraction of Dosage Range Criteria;;
mlmname: STD_FUNC_DOSAGE_CAT;;
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: Finds the appropriate dose-range criteria from the order{{{SINGLE-QUOTE}}}s item-catalog and
returns the information to the calling MLM.
;;
explanation: This MLM assists the STD_Dosage MLM with dose-range checking.
A large list of arguments is passed to this MLM, and they are used to find
all the appropriate dose-range criteria (AGE, BSA, or WEIGHT)
for the patient.
If the ORDERED-DOSE is being checking and the "PER WT OR M2" field has a
valid uom (kg,lb,oz,g,m2), then the upper and lower dose-ranges will be
(1) multiplied by the patient{{{SINGLE-QUOTE}}}s weight or BSA and
(2) rounded using the rules found in the SYS_round_dosage MLM,
if there is a valid route.
If the DOSE-PER is being checking and the "PER WT OR M2" field has a
valid uom (kg,lb,oz,g,m2), then the upper and lower dose-ranges will NOT be
multiplied or rounded.
The dose-ranges and other pertinent information are returned to the calling MLM.
See the STD_Dosage MLM for further information.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// include common data structures
std_dosage_includes := MLM {{{SINGLE-QUOTE}}}std_func_dosage_includes{{{SINGLE-QUOTE}}};
include std_dosage_includes;
(
drug_name,
is_order,
catalog_item_obj,
drc_grouper_id,
multum_dnum,
multum_mmdc,
order_med_route,
order_med_route_id,
is_generic_route,
order_med_significant_date,
order_med_units,
order_med_uom_id,
single_order_calc_per_uom,
average_order_calc_per_uom,
total_order_calc_per_uom,
patient_birthday_info_on_order,
has_valid_birthdate,
wt_kg,
BSA_number_rounded,
intl_patient_gender,
core_uom_const,
alert_if_missing_flags,
patient_info
):= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
/* Declare the MLMs that can be called */
xml_params := MLM {{{SINGLE-QUOTE}}}STD_Func_Dosage_XML_Params{{{SINGLE-QUOTE}}};
// XML parameter
( input_param_xml,
missing_route,
unmapped_route,
missing_uom,
unmapped_uom
) := call xml_params with
(
// Common medication data
drc_grouper_id,
multum_dnum,
multum_mmdc,
order_med_route,
order_med_route_id,
is_generic_route,
order_med_significant_date,
order_med_units,
order_med_uom_id,
null, // multum_freq_id not needed
null, // med_order_type not needed
is_order,
// Patient data
patient_birthday_info_on_order,
has_valid_birthdate,
wt_kg,
BSA_number_rounded,
intl_patient_gender,
// Item Catalog only
true, //for_item_catalog
catalog_item_obj,
// Multum only
null, //has_liver_disease_bit,
null, //dialysis_type_str,
null, //serum_creatinine,
// Flags and constants
alert_if_missing_flags,
patient_info,
core_uom_const
);
debug_sql_str := "SCMGetItemCatDosageRangePr "
|| SQL(input_param_xml);
if exists drug_name
then
(match_found_list,
dose_type_list,
gender_codes,
facility_gender_codes,
criteria_type_names,
criteria_type_codes,
criteria_type_low_codes,
criteria_type_high_codes,
criteria_type_facility_uoms,
routes,
route_ids,
range_low_codes,
range_high_codes,
range_uoms,
range_uom_ids,
is_PER_WT_list,
is_PER_M2_list,
range_per_facility_uoms,
range_per_core_uoms,
uom_conversion_factor_list,
uom_conversion_issue_list,
route_conversion_issue_list,
cat_item_match_list,
estimated_age_used_list
) := read {"SCMGetItemCatDosageRangePr "
|| SQL(input_param_xml)
};
endif;
;;
evoke:
;;
logic:
/* Intializes variables */
dose_per_string:= "Dose Per";
dose_reg_string:= "Dose Reg";
found_criteria:= false;
item_cat_dosage_range_list := ();
if exists match_found_list
then
row_count := count match_found_list;
list_indices := 1 seqto row_count;
for ind in list_indices
do
// Put the dosage range values into the dosage range object
dosage_range_item := new Dosage_Range_Object;
item_cat_dosage_range_list := item_cat_dosage_range_list, dosage_range_item;
dosage_range_item.med_name := drug_name;
dosage_range_item.match_found := (match_found_list[ind] = true) or (match_found_list[ind]=1);
dosage_range_item.dosage_type := dose_type_list[ind];
dosage_range_item.is_range := true; // ItemCatalog is always a range value
dosage_range_item.lower_dose := range_low_codes[ind];
dosage_range_item.upper_dose := range_high_codes[ind];
dosage_range_item.is_PER_WT := is_PER_WT_list[ind];
dosage_range_item.is_PER_M2 := is_PER_M2_list[ind];
uom_conversion_factor := uom_conversion_factor_list[ind];
conversion_factor := uom_conversion_factor;
if (dosage_range_item.dosage_type = "single") then order_med_per_uom := single_order_calc_per_uom;
elseif (dosage_range_item.dosage_type = "average") then order_med_per_uom := average_order_calc_per_uom;
else order_med_per_uom := total_order_calc_per_uom;
endif;
per_units := range_per_core_uoms[ind];
if (order_med_per_uom = per_units) // dose per
then
dosage_range_item.dose_calc_method := dose_per_string;
corrected_uom := range_uoms[ind] || "/" || per_units;
else // dose reg
dosage_range_item.dose_calc_method := dose_reg_string;
if per_units is null
then
corrected_uom := range_uoms[ind];
dosage_range_item.unit_of_measure := range_uoms[ind];
else
corrected_uom := range_uoms[ind] || "/" || per_units;
dosage_range_item.unit_of_measure := range_uoms[ind] || "/" || per_units;
per_weight_list := (core_uom_const.kg_string, core_uom_const.gm_string, core_uom_const.lb_string, core_uom_const.ounce_string);
per_weight_conversion := (1000, 1, 453.6, 28.35);
if (per_units in per_weight_list)
then
dosage_range_item.is_PER_WT := true;
dosage_range_item.unit_of_measure := range_uoms[ind] || "/" || per_units;
if wt_kg is number and wt_kg > 0
then
wt_gm := wt_kg * 1000;
weight_conv_factor := (last (per_weight_conversion where per_units = per_weight_list));
per_weight := wt_gm / weight_conv_factor;
conversion_factor := conversion_factor / per_weight;
else
conversion_factor := -1 * abs(conversion_factor);
dosage_range_item.match_found := false;
endif;
elseif per_units = core_uom_const.M2_string
then
dosage_range_item.is_PER_M2 := true;
dosage_range_item.unit_of_measure := range_uoms[ind] || "/" || per_units;
if BSA_number_rounded is number
and BSA_number_rounded > 0
then
conversion_factor := conversion_factor / BSA_number_rounded;
else
conversion_factor := -1 * abs(conversion_factor);
dosage_range_item.match_found := false;
endif;
endif;
endif;
endif;
dosage_range_item.corrected_uom := corrected_uom;
dosage_range_item.calc_per_core_uom := per_units;
dosage_range_item.is_multum := false;
dosage_range_item.route := routes[ind];
dosage_range_item.route_id := route_ids[ind];
dosage_range_item.med_route := order_med_route;
dosage_range_item.med_route_id := order_med_route_id;
dosage_range_item.dnum_ic_match_found := cat_item_match_list[ind] not in (1, true);
dosage_range_item.estimated_age_used := estimated_age_used_list[ind];
route_conversion_issue := route_conversion_issue_list[ind] in (1, true);
if is_generic_route
then
dosage_range_item.unrecognized_route_conversion_issue := route_conversion_issue;
else
dosage_range_item.inapplicable_route_conversion_issue := route_conversion_issue;
endif;
dosage_range_item.uom_conversion_factor := uom_conversion_factor;
dosage_range_item.conversion_factor := conversion_factor;
dosage_range_item.uom_conversion_issue := uom_conversion_issue_list[ind] in (1, true);
criteria_type := criteria_type_codes[ind];
dosage_range_item.is_default := criteria_type = "age" and
(gender_codes[ind] in (null, "", "U"));
criteria_low_str := criteria_type_low_codes[ind];
criteria_high_str := criteria_type_high_codes[ind];
criteria_uom_str := criteria_type_facility_uoms[ind];
criteria_str := ">=" || criteria_low_str || " " || criteria_uom_str || " and " ||
"<" || criteria_high_str || " " || criteria_uom_str;
if criteria_type = "age"
then
dosage_range_item.age_criteria:= criteria_str;
elseif criteria_type = "bsa"
then
dosage_range_item.BSA_criteria:= criteria_str;
elseif criteria_type = "weight"
then
dosage_range_item.weight_criteria:= criteria_str;
endif;
case_id := criteria_str;
gender_criteria := facility_gender_codes[ind];
if facility_gender_codes[ind] not in (null, "", "U")
then
dosage_range_item.gender_criteria := gender_criteria;
case_id := case_id || gender_criteria;
endif;
dosage_range_item.case_id := case_id;
enddo;
uom_conversion_issue := any item_cat_dosage_range_list.uom_conversion_issue;
endif;
/* Always conclude true to return variables to calling MLM */
CONCLUDE TRUE;
;;
action:
return (item_cat_dosage_range_list, missing_route, unmapped_route, missing_uom, unmapped_uom, uom_conversion_issue);
;;
end:

View File

@@ -0,0 +1,376 @@
maintenance:
title: Order Modification Comparison for the Dosage-Range Checking MLM;;
mlmname: STD_FUNC_DOSAGE_COMPARE;;
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: When an order is modified, this MLM compares information in the
current Order, Order Component, and Order Variable Component Objects and the
backup Order, its Order Components, and its Order Variable Component Objects
to determine if the dosage information have been modified.
Order Component Objects are used for IV-Additives.
Order Variable Component Objects are used for Complex Orders.
;;
explanation: The comparison is as follows for the current order and its backup order:
Order Object: DosageLow, DosageHigh, UOM, Frequency, Route
Order Component Object: IV Additive{{{SINGLE-QUOTE}}}s DosageLow, UOM
Order Variable Component Object:
Complex Order{{{SINGLE-QUOTE}}}s DosageLow, DosageHigh, UOM, Route, and Frequency data.
In addition, if the Order is a Concurrent Order,
the data affecting the Start and Stop Dates will also be compared.
If the information has changed, set the flag to return
to calling MLM to indicate that dosage has changed.
If the Order Variable Component Objects were created, return the current list
of these objects to the calling MLM.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
time_offset_limit //An Arden Duration that is used with Complex Orders.
:= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
// Executes only when this MLM is called by the editor
if called_by_editor then
EvokingObject := read last
{ Order: This
};
endif;
// Declare the MLM that will be called by this MLM
func_dosage_retrieve_components := MLM {{{SINGLE-QUOTE}}}std_func_dosage_retrieve_components{{{SINGLE-QUOTE}}};
// Initialize flag used to indicate of dose was modified
medication_dose_modified := false;
// Get the current order{{{SINGLE-QUOTE}}}s Dosage information
(order_name,
order_med_uom,
order_med_dose_low_str,
order_med_dose_high_str,
order_med_route,
order_med_frequency,
order_med_significant_date,
client_guid,
chart_guid,
order_complex_order_type,
order_catalog_item_obj,
order_component_obj,
order_user_data_obj,
order_variable_component_obj,
order_backup_obj ) := read last
{ Order: Name, UOM, DosageLow, DosageHigh, OrderRouteCode, FrequencyCode,
SignificantDtm, ClientGUID, ChartGUID, ComplexOrderType,
OrderCatalogMasterItem, OrderComponent,
OrderUserData, OrderVariableComponent, Backup
REFERENCING EvokingObject};
// Get the backup order{{{SINGLE-QUOTE}}}s Dosage information
(backup_order_name,
backup_order_med_uom,
backup_order_med_dose_low_str,
backup_order_med_dose_high_str,
backup_order_med_route,
backup_order_med_frequency,
backup_order_component_obj,
backup_order_user_data_obj,
backup_order_variable_component_obj ) := read last
{ Order: Name, UOM, DosageLow, DosageHigh, OrderRouteCode, FrequencyCode
OrderComponent,OrderUserData, OrderVariableComponent
REFERENCING order_backup_obj};
// Get the current order{{{SINGLE-QUOTE}}}s Component information
(comp_name_list,
comp_type_list,
comp_low_dose_list,
comp_hi_dose_list,
comp_uom_list,
comp_calc_actual_dose_list,
comp_calc_uom_per_list,
comp_catalog_item_obj_list ):= read
{OrderComponent: Name, Type, Dosage, DosageTo, UOM,
CalcActualDose, CalcUOMPer, OrderCatalogMasterItem
REFERENCING order_component_obj
where (Dosage AS number) > 0};
// Get the backup order{{{SINGLE-QUOTE}}}s Component information
(oc_backup_name_list,
oc_backup_type_list,
oc_backup_low_dose_list,
oc_backup_hi_dose_list,
oc_backup_uom_list,
oc_backup_calc_actual_dose_list,
oc_backup_calc_uom_per_list,
oc_backup_catalog_item_obj_list ):= read
{OrderComponent: Name, Type, Dosage, DosageTo, UOM,
CalcActualDose, CalcUOMPer, OrderCatalogMasterItem
REFERENCING backup_order_component_obj
where (Dosage AS number) > 0 };
user_data_weight_string:= "Weight";
user_data_height_string:= "Height";
// Get the current OrderUserData information for weight and height
(weight_user_data_code,
weight_user_value) := read
{OrderUserData: UserDataCode, Value
REFERENCING order_user_data_obj
WHERE user_data_code = user_data_weight_string };
(height_user_data_code,
height_user_value) := read
{OrderUserData: UserDataCode, Value
REFERENCING order_user_data_obj
WHERE user_data_code = user_data_height_string };
// Get the back up OrderUserData information for weight and height
(backup_weight_user_data_code,
backup_weight_user_value) := read
{OrderUserData: UserDataCode, Value
REFERENCING backup_order_user_data_obj
WHERE user_data_code = user_data_weight_string
};
(backup_height_user_data_code,
backup_height_user_value) := read
{OrderUserData: UserDataCode, Value
REFERENCING backup_order_user_data_obj
WHERE user_data_code = user_data_height_string
};
;;
evoke:
;;
logic:
// Convert back up and current med order doses to numbers
original_low_dose := backup_order_med_dose_low_str as number;
current_low_dose := order_med_dose_low_str as number;
original_high_dose := backup_order_med_dose_high_str as number;
current_high_dose := order_med_dose_high_str as number;
// If the current order dosage has changed from previous dosage set modification flag.
// Existance tests were added to the condition so that if the change was
// from NULL to a non-NULL value, the MLM would recheck the dosage range.
If (original_low_dose <> current_low_dose)
OR (exist original_low_dose <> exist current_low_dose)
OR (original_high_dose <> current_high_dose)
OR (exist original_high_dose <> exist current_high_dose)
OR (backup_order_med_uom <> order_med_uom)
OR (exist backup_order_med_uom <> exist order_med_uom)
OR (backup_order_med_route <> order_med_route)
OR (exist backup_order_med_route <> exist order_med_route)
OR (backup_order_med_frequency <> order_med_frequency)
OR (exist backup_order_med_frequency <> exist order_med_frequency)
then
medication_dose_modified := TRUE;
endif;
//------------------------------
// Check order user data
//------------------------------
// If the weight or height data has changed, then
// medication dosage information can change
if ( (exists weight_user_value and not exists backup_weight_user_value)
or (not exists weight_user_value and exists backup_weight_user_value)
or (weight_user_value <> backup_weight_user_value)
or (exists height_user_value and not exists backup_height_user_value)
or (not exists height_user_value and exists backup_height_user_value)
or (height_user_value <> backup_height_user_value)
)
then
medication_dose_modified := TRUE;
endif;
//------------------------------
// Check OrderComponent Objects
//------------------------------
// If the order has OrderComponent Objects then
// Continue checking if the main item has not had its dose modifed
If exist order_component_obj
and exist comp_name_list
and NOT medication_dose_modified then
// If count or dosage has changed from previous set modification flag.
// Check component item count and then step through list of components.
If (count comp_name_list) = (count oc_backup_name_list) then
current_additive_index := 1 seqto (count comp_name_list);
// Step through list of IV-Additive components and compare
for JJ in current_additive_index do
comp_name := first(comp_name_list where current_additive_index = JJ);
backup_name := first(oc_backup_name_list where current_additive_index = JJ);
// Make certain they are the same item.
if comp_name = backup_name then
// Get the values
comp_low_dose := comp_low_dose_list[JJ] as number;
backup_low_dose := oc_backup_low_dose_list[JJ] as number;
comp_uom := comp_uom_list[JJ];
backup_uom := oc_backup_uom_list[JJ];
// Compare the values, set flag if different
if (comp_low_dose <> backup_low_dose)
OR (comp_uom <> backup_uom) then
medication_dose_modified := TRUE;
endif;
else // Not the same name so set flag indicating change
medication_dose_modified := TRUE;
endif; //if comp_name = backup_name
enddo; // for JJ
else // Number of items different so set flag indicating change
medication_dose_modified := TRUE;
endif; //If (count comp_name_list) =
endif; //If exist order_component_obj
//---------------------------------
// Check Order Variable Components
//---------------------------------
// If the order has OrderVariable Component Objects then
// Continue checking if the main item has not had its dose modifed
If exist order_variable_component_obj
and NOT medication_dose_modified then
// Retrieve the Order_Variable_Component Objects
(current_ovc_list,
backup_ovc_list ) := call func_dosage_retrieve_components;
// Check the details of the Order Components
// when there are the same number of components
If count current_ovc_list = count backup_ovc_list then
// Step through list of Complex Order components and compare
for KK in (1 seqto count current_ovc_list) do
// Make certain they are the same components by checking GUIDs
if current_ovc_list[KK].GUID = backup_ovc_list[KK].GUID then
// Compare the values, set flag if different
// Compensate for the possibility that one or both values can be NULL.
// For Example:
// var1 := NULL <> 1 returns NULL
// var2 := Exist 1 <> Exist NULL returns TRUE
// var3 := var1 or var2 returns TRUE
if current_ovc_list[KK].dosage_low <> backup_ovc_list[KK].dosage_low
OR (exist current_ovc_list[KK].dosage_low
<> exist backup_ovc_list[KK].dosage_low)
OR current_ovc_list[KK].dosage_high <> backup_ovc_list[KK].dosage_high
OR (exist current_ovc_list[KK].dosage_high
<> exist backup_ovc_list[KK].dosage_high)
OR current_ovc_list[KK].uom <> backup_ovc_list[KK].uom
OR (exist current_ovc_list[KK].uom
<> exist backup_ovc_list[KK].uom)
OR current_ovc_list[KK].order_route_code <> backup_ovc_list[KK].order_route_code
OR (exist current_ovc_list[KK].order_route_code
<> exist backup_ovc_list[KK].order_route_code)
OR current_ovc_list[KK].frequency_code <> backup_ovc_list[KK].frequency_code
OR (exist current_ovc_list[KK].frequency_code
<> exist backup_ovc_list[KK].frequency_code)
OR current_ovc_list[KK].freq_from_time <> backup_ovc_list[KK].freq_from_time
OR (exist current_ovc_list[KK].freq_from_time
<> exist backup_ovc_list[KK].freq_from_time)
OR current_ovc_list[KK].freq_uom <> backup_ovc_list[KK].freq_uom
OR (exist current_ovc_list[KK].freq_uom
<> exist backup_ovc_list[KK].freq_uom)
then
medication_dose_modified := TRUE;
endif;
else // Not the same GUIDs so set flag indicating change
medication_dose_modified := TRUE;
endif; //if comp_name = backup_name
// If the order is a complex order, a change to the
// CalculatedStartDtm, the StopDtm, or the StopAfter can affect
// the Total Daily Dose by shifting the DTMs and affecting the totals.
// Calculate the difference between the current and backup DTMs
// can convert the duration to an absolute number by dividing by 1 minute.
diff_calculated_start_dtm := ABS ((current_ovc_list[KK].calculated_start_dtm -
backup_ovc_list[KK].calculated_start_dtm)/ 1 minute);
diff_estimated_stop_dtm := ABS ((current_ovc_list[KK].estimated_stop_dtm -
backup_ovc_list[KK].estimated_stop_dtm)/ 1 minute) ;
// Convert the time_offset_limit to an absolute number by dividing 1 minute;
time_offset_limit_num := ABS (time_offset_limit/ 1 minute) ;
// If the calucated values are off by more than the time_offset_limit_num
// or the Stop After Value or Stop After Option Type have changed
// then this is a modification that will affect the Total Daily Dose.
if diff_calculated_start_dtm > time_offset_limit_num
OR diff_estimated_stop_dtm > time_offset_limit_num
OR current_ovc_list[KK].stop_after_value
<> backup_ovc_list[KK].stop_after_value
OR (exist current_ovc_list[KK].stop_after_value
<> exist backup_ovc_list[KK].stop_after_value)
OR current_ovc_list[KK].stop_after_option_type
<> backup_ovc_list[KK].stop_after_option_type
OR (exist current_ovc_list[KK].stop_after_option_type
<> exist backup_ovc_list[KK].stop_after_option_type) then
medication_dose_modified := TRUE;
endif; //if diff_calculated_start_dtm
enddo; // for KK
else // Number of complex order components different so set flag indicating change
medication_dose_modified := TRUE;
endif; //If count current_ovc_list
endif; //If exist order_variable_component_obj
// Always Conclude True to Return Answer
conclude TRUE;
;;
action:
return medication_dose_modified, current_ovc_list ;
;;
end:

View File

@@ -0,0 +1,132 @@
maintenance:
title: CSS style sheet for STD_FUNC_DOSAGE_MESSAGES;;
mlmname: STD_FUNC_DOSAGE_CSS;;
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: This MLM contains the CSS style sheet for STD_FUNC_DOSAGE_MESSAGES.
;;
explanation: Dose range alert messages are in HTML format. This MLM contains
the CSS styles used to format the message.
;;
keywords: single dose; average daily dose; total daily dose; dosage range; HTML
;;
knowledge:
type: data-driven;;
data:
// Define the CSS to be used for the HTML dose range check alerts
Standard_CSS :=
"<style type={{{SINGLE-QUOTE}}}text/css{{{SINGLE-QUOTE}}}> " ||
// general style applied to entire alert message
" body " ||
" { color:black; " ||
" font-size:12pt; " ||
" font-family:Segoe UI,sans-serif; " ||
" margin-top: 0px; }" ||
// generic styles
" #PaddingLeft" ||
" { padding-left:50px; } " ||
" #NormalText" ||
" { font-weight:Normal; " ||
" color:black; } " ||
// header styles
" #Title" ||
" { color:Red; " ||
" font-size:14pt; " ||
" font-weight:bold; } " ||
" #MedicationHeader" ||
" { color:Blue; } " ||
// specific message styles
" #BasedOnMsg" ||
" { font-size:12pt; } " ||
" #BasedOnAdditionalInfoMsg" ||
" { font-size:12pt; } " ||
// table styles
" #ContraindicationTable" ||
" { font-size:12pt; } " ||
" #OutsideDoseRangeTable" ||
" { font-size:12pt; } " ||
" #AdditionalInfoTable" ||
" { font-size:12pt; } " ||
// table column style
" #TableColumnHeader" ||
" { text-align:left;" ||
" padding-right:50px; } " ||
" #AdditionalInfoColumnHeader" ||
" { text-align:left; " ||
" font-weight:normal} " ||
// table cell styles
" #TableCellPaddingRight" ||
" { padding-right:50px; } " ||
// highlighted data styles
" #MedicationName" ||
" { color:Blue; } " ||
" #OutsideDoseRangeValue" ||
" { color:Red; } " ||
" #WithinDoseRangeValue" ||
" { color:Black; } " ||
" #ContraindicationPatientInfo" ||
" { color:Red; } " ||
" #CreatinineClearanceNote" ||
" { color:rgb(31,73,125); } " ||
" #FrequencyIssue" ||
" { color:Red; } " ||
// debug section style
" #DebugSection" ||
" { font-size:10pt; " ||
" font-family:Segoe UI,sans-serif; }" ||
// list margin
" ul" ||
" {margin-top:0px; " ||
" margin-bottom:0px; } " ||
// breakpoint height
" br" ||
" {line-height:85%; }" ||
"</style> ";
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return Standard_CSS;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,305 @@
maintenance:
title: Regression test include definitions;;
mlmname: STD_FUNC_DOSAGE_INCLUDES;;
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: The purpose of this MLM is to include the common data structures needed by dosage range MLMs
;;
explanation: Include this MLM at the start of any MLM that will
be making using the objects in the MLM
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// Core UOM Constant Object
Core_UOM_OBJECT := OBJECT [
lb_string,
gm_string,
kg_string,
M2_string,
ounce_string,
day_string,
hour_string,
minute_string,
month_string,
second_string,
week_string,
year_string
];
// Item catalog criteria type string object
Catalog_DRC_Criteria_Type_String_Object := OBJECT [
age_average_daily_dose_string,
age_string,
age_total_daily_dose_string,
BSA_average_daily_dose_string,
Body_Surface_Area_string,
BSA_total_daily_dose_string,
weight_average_daily_dose_string,
weight_string,
weight_total_daily_dose_string
];
//Declare the Med_Data_Object
//Note: Med_Data_GUID is the
//CV3Order.GUID, CV3OrderComponent.GUID or CV3OrderVariableComponent.GUID
//Depending on whether this is a Regular Order, IV-Additive Order, or Complex Order
Med_Data_Object := OBJECT [
sort_number,
med_order_type,
med_data_guid,
grouper_id,
multum_dnum,
multum_mmdc,
order_med_significant_date, // CalculatedStartDtm when component
order_med_name,
order_med_route,
order_med_route_id, // multum drug key for the order_med_route
order_med_dose_low,
order_med_dose_high,
order_med_units,
order_med_uom_id, // multum drug key for the order_med_units
order_med_frequency,
multum_freq_id, // multum drug key for frequency
order_interval,
calc_dose_method,
calc_med_dose_low,
calc_med_dose_high,
calc_med_per_uom,
updated_calc_med_per_uom, //Populated by DoseBasis MLM
wt_kg, //Populated by DoseBasis MLM
calc_text, //Populated by DoseBasis MLM
dose_basis, //Populated by DoseBasis MLM
stop_dtm,
calcStop_dtm, //Debug info
calcStart_dtm, //Debug info
calculation_method, //Debug info
stop_after_value,
stop_after_option_type,
freq_from_time,
freq_to_time,
freq_uom,
freq_multiplier, // only used by Prescription
isShiftFrequency,
admin_dtm_list,
admin_dtm_list_calc_method, // ORDER or MLM - Debug Info
order_catalog_item_obj,
retrieved_dose_range_data,
missing_route,
unmapped_route,
generic_route,
missing_uom,
unmapped_uom,
uom_conversion_issue,
unmapped_drug,
unmapped_grouper,
processed_missing_data_msg,
processed_for_printing,
outside_single_dosage_range,
contraindication_found,
alert_msg_for_single,
is_order,
is_outpatient_order, //indicate whether this order is outpatient order or not
is_script, //used for outpatient order
is_iv_additive,
rx_instructions
];
// Declare dosage range object
Dosage_Range_Object := OBJECT [
sort_number,
match_found, // true if matching dose range found. false if missing age/weight/gender/route
dosage_type, // single, average, total, or contraindication
med_name,
age_criteria,
BSA_criteria,
weight_criteria,
gender_criteria,
renal_criteria,
creatinine_criteria,
liver_criteria,
contraindication_msg, // for dosage_type = contraindication
recommendation_msg, // for dosage type = single/average/total
is_range,
lower_dose, // for dosage_type = single/average/total
upper_dose, // for dosage_type = single/average/total
unit_of_measure,
conversion_factor,
uom_conversion_factor, // Keep the pure UOM conversion factor based on the SXAUnitOfMeasureConversion table
// This is used only used for Catalog DRC checking in STD_FUNC_DOSAGE_CAT, because
// STD_FUNC_DOSAGE_CAT has logic to override conversion_factor value for "per weight" scenario.
// uom_conversion_factor is currently not used in STD_FUNC_DOSAGE_MULTUM.
uom_conversion_issue,
Is_PER_WT,
Is_PER_M2,
dose_calc_method,
corrected_uom,
calc_per_core_uom,
is_multum,
grouper_id,
case_id,
route,
route_id,
// Populated in STD_FUNC_DOSAGE_MULTUM.mlm and STD_FUNC_DOSAGE_CAT.mlm
// Contains the medication route and route ID used to retrieve this
// dosage range by the two MLMs mentioned above
med_route,
med_route_id,
display_route, // the route to display to the user. Populated by
// STD_FUNC_DOSAGE_MESSAGES.MLM.
//cannot_match_to_generic_route,
unrecognized_route_conversion_issue,
inapplicable_route_conversion_issue,
is_default,
hard_stop_high,
hard_stop_low,
crcl_within_range,
patient_age_at_order,
dnum_ic_match_found,
dose_frequency, // e.g. "once a day"
frequency_issue, // "too frequent", "unmapped", or null
//[New born birth-time missing]
// 0: alert not using estimated ages; 1: using estimated min age; 2: using estimated max age max; 3: using both estimated age min/max.
estimated_age_used
];
// medication dosage range map object
Medication_Dosage_Range_Map := OBJECT [
sort_number,
med_sort_number,
dosage_range_sort_number,
dosage_type,
match_found,
above_range,
below_range,
med_name,
med_dose_low,
med_dose_high,
med_dose_uom,
adjusted_dose_high,
adjusted_dose_low,
adjusted_dose_uom,
hard_stop_low,
hard_stop_high,
dose_frequency, // e.g. "once a day"
frequency_issue // "too frequent", "unmapped", or null
];
Alert_If_Missing_Obj := OBJECT [
patient_age,
patient_gender,
patient_height,
patient_weight,
uom,
route,
uom_conversion,
unmapped_drug,
unmapped_grouper,
unmapped_gender,
unmapped_route,
unmapped_uom,
unmapped_frequency,
cannot_check_DNUM_Rx_to_Multum,
cannot_check_Rx_to_IC,
cannot_check_generic_route,
inapplicable_route
];
//[New born birth-time missing]Holding info of birthday and max estimated_birthday
//the age values are patient_age_at_order calcualted by birthday and order order_med_significant_date
Patient_Birthday_Info_Obj := OBJECT [
birthday,
age_year_value,
age_month_value,
age_week_value,
age_day_value,
age_hour_value,
age_str,
// from here only used when is_estimated_birthday is true
is_estimated_birthday,
age_max_inhour_str,
estimated_birthday_to,
age_year_min_value,
age_month_min_value,
age_week_min_value,
age_day_min_value,
age_hour_min_value,
age_min_inhour_str
];
// weight, 68 kg, entered on 2011-nov-22, false, false
// height,
Patient_Property_Obj := OBJECT [
type,
value,
date,
is_missing,
is_unmapped,
not_current,
unknown_other
];
// Holds patient property objects
Patient_Info_Obj := Object [
Age,
Weight,
Height,
BSA,
Gender,
Liver,
Renal,
Creatinine,
DNum_Grouper,
ICD9_List
];
// Holds the currentness duration
Validity_Duration := OBJECT [
duration,
toAge,
fromAge ]; // Note fromAge is set by the system
Grouper_Info_Object := OBJECT [
grouper_id,
grouper_name,
dosage_range_found
];
;;
priority: 50
;;
evoke:
;;
logic:
;;
action:
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,914 @@
maintenance:
title: Creates a List of Objects with Medication Data;;
mlmname: STD_FUNC_DOSAGE_LISTS;;
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: Gathers the dosing data for the medication order.
;;
explanation: The dosing data for a medication are stored in several tables/objects.
Regular medications, IV-Additive, and Complex Orders have some tables they jointly use
and other tables that are specific to the type of order. This MLM gathers all the data
from the various sources and consolidates them into an object called Med_Data_Object.
There can be one or more Med_Data_Objects for an order. A regular medication order
only has one object for its data. IV-Additives and Complex Orders can have
two or more objects for their data.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// include common data structures
std_dosage_includes := MLM {{{SINGLE-QUOTE}}}std_func_dosage_includes{{{SINGLE-QUOTE}}};
include std_dosage_includes;
(ht_cm,
wt_kg,
current_ovc_list,
order_TaskScheduleDefinition_obj ) := ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
//--------------
// Declare MLMs
//--------------
func_dosage_basis := MLM {{{SINGLE-QUOTE}}}std_func_dosage_basis{{{SINGLE-QUOTE}}};
func_dosage_admin_times := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_admin_times{{{SINGLE-QUOTE}}};
func_dosage_admin_times_generated := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_ADMIN_TIMES_GENERATED{{{SINGLE-QUOTE}}};
calc_freqmult_daily := MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_daily{{{SINGLE-QUOTE}}};
// Declare the MLM that will be called by this MLM
func_dosage_retrieve_components := MLM {{{SINGLE-QUOTE}}}std_func_dosage_retrieve_components{{{SINGLE-QUOTE}}};
func_calc_method := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_CALC_METHOD{{{SINGLE-QUOTE}}};
func_dosage_calc_stopdtm := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_CALC_STOPDTM{{{SINGLE-QUOTE}}};
//---------------------
// Declare the Objects
//---------------------
//The Med_Data_Object declaration moved to STD_FUNC_DOSAGE_INCLUDES
//Note: Med_Data_GUID is the
//CV3Order.GUID, CV3OrderComponent.GUID or CV3OrderVariableComponent.GUID
//Depending on whether this is a Regular Order, IV-Additive Order, or Complex Order
//--------------------------------------------
// Get the current order{{{SINGLE-QUOTE}}}s Dosage information
//--------------------------------------------
(client_guid,
order_name,
order_med_uom,
order_med_dose_low_str,
order_med_dose_high_str,
order_med_route,
order_med_frequency,
order_med_significant_date,
order_StopDtm,
order_guid,
order_is_held,
order_complex_order_type,
order_catalog_item_obj,
order_component_obj,
order_user_data_obj,
order_Interval,
order_AdditionalInfo_obj,
order_variable_component_obj,
order_backup_obj ) := read last
{ Order: ClientGUID, Name, UOM, DosageLow, DosageHigh, OrderRouteCode,
FrequencyCode, SignificantDtm, StopDtm, GUID, IsHeld, ComplexOrderType
OrderCatalogMasterItem, OrderComponent, OrderUserData,
Interval, OrderAdditionalInfo,
OrderVariableComponent, Backup
REFERENCING EvokingObject};
// Get information for frequency for "<Variable Interaval>" and StopAfter Data
(OrderInfo_order_stop_after_value,
OrderInfo_order_stop_after_option,
OrderInfo_FreqFromTime,
OrderInfo_FreqToTime,
OrderInfo_FreqUOM,
OrderInfo_Dosing_Option_GUID ) := read last
{OrderAdditionalInfo: StopAfterValue, StopAfterOption
FreqFromTime, FreqToTime, FreqUOM,
DosingOptionGUID
REFERENCING order_AdditionalInfo_obj };
// Get the current order{{{SINGLE-QUOTE}}}s IV-Additive Component information
(comp_guid_list,
comp_name_list,
comp_type_list,
comp_low_dose_list,
comp_hi_dose_list,
comp_uom_list,
comp_calc_actual_dose_list,
comp_calc_uom_per_list,
comp_catalog_item_obj_list ):= read
{OrderComponent: GUID, Name, Type, Dosage, DosageTo, UOM,
CalcActualDose, CalcUOMPer, OrderCatalogMasterItem
REFERENCING order_component_obj
where (Dosage AS number) > 0 };
// For Irregular intervals get the total number of doses given
ScheduleDTM_list := read
{TaskScheduleDefinition: SCHEDULEDDTM
REFERENCING order_TaskScheduleDefinition_obj };
// Get the current OrderUserData information
(user_data_code,
user_value) := read
{OrderUserData: UserDataCode, Value
REFERENCING order_user_data_obj };
// If the Order is a Concurrent Complex Order and its is on HOLD
// then retrieve the Template for the Dates
if order_is_held
and order_complex_order_type = 3 //Concurrent
and exist OrderInfo_Dosing_Option_GUID
then
// Retrieve the Template for the Dates
requested_date_template_list := read
{"Select RequestedDate "
||" FROM CV3DosingOptionGridRow "
||" WHERE DosingOptionGUID = " || SQLEX(OrderInfo_Dosing_Option_GUID) };
endif; //if order_is_held
// Retrieve and populate the data for the Complex Order{{{SINGLE-QUOTE}}}s Order_Variable_Component Objects
if exist current_ovc_list
then
// The data was already constructed when the modifed order was compared to the backup data
complex_order_list := current_ovc_list;
else
// Retrieve the data, since the data was not created previously.
complex_order_list := call func_dosage_retrieve_components;
endif;
/* Get the Units of Measure info */
(uom_facility_code,
uom_sys_code,
uom_drug_catalog_key):= read
{"SELECT Code, CoreUOM, DrugCatalogKey "
|| " FROM CV3UnitOfMeasure"
|| " WHERE Active = 1" };
/* Get Route Dictionary ID info */
(route_code,
route_drug_catalog_key):= read
{"SELECT Code, DrugCatalogKey "
|| " FROM CV3OrderRoute"
|| " WHERE Active = 1" };
/* Get Frequency Dictionary ID info */
(frequency_code,
frequency_drug_catalog_key):= read
{"SELECT f.Code, f.DrugCatalogKey "
|| " FROM CV3Frequency f"
|| " INNER JOIN SXAMTmultum_frequencySYN mf on mf.frequency_code = f.DrugCatalogKey "
|| " WHERE Active = 1" };
;;
evoke:
;;
logic:
//--------------------------------
// Update HELD Complex Order DTMs
//---------------------------------
// If the Order is a Complex Order and its is on HOLD
// then correct the CalculatedStartDtm and the EstimatedStopDtm
if order_is_held
and order_complex_order_type > 0
then
HH := 0;
prior_estimated_stop_dtm := null;
complex_order_stop_after_duration := null;
If exist requested_date_template_list
then
alternating_day_start_dtm_list := ();
//Try to Match it to a "T" or "T+n" Pattern
for date_template in requested_date_template_list do
character_list := extract characters date_template;
if count character_list = 1
and character_list[1] = "T"
then
temp_start_dtm := order_med_significant_date;
alternating_day_start_dtm_list :=
alternating_day_start_dtm_list, temp_start_dtm;
elseif count character_list > 2
and character_list[1] = "T"
and character_list[2] = "+"
then
new_num := (STRING (character_list where it is not in ("T", "+"))) AS NUMBER;
temp_start_dtm := order_med_significant_date + new_num DAY;
alternating_day_start_dtm_list :=
alternating_day_start_dtm_list, temp_start_dtm;
endif; //if count character_list = 1
enddo; //for date_template
endif; //If exist requested_date_template_list
for complex_order in complex_order_list do
// Increment Counter
HH := HH + 1;
// Calculate the Duration of the StopAfter
if complex_order.stop_after_option_type = 1 // Days
then complex_order_stop_after_duration := complex_order.stop_after_value DAYS;
elseif complex_order.stop_after_option_type = 2 // Hours
then complex_order_stop_after_duration := complex_order.stop_after_value HOURS;
elseif complex_order.stop_after_option_type = 3 // Minutes
then complex_order_stop_after_duration := complex_order.stop_after_value MINUTES;
elseif complex_order.stop_after_option_type = 4 // Times
then
// Create a list of dose admin times based on x-times. Use the estimation
// method instead of the order as hold orders do not calculate
(temp_admin_time_list,
temp_next_start_dtm) := call func_dosage_admin_times with
complex_order.frequency_code,
complex_order.calculated_start_dtm,
complex_order.estimated_stop_dtm,
complex_order.stop_after_value,
complex_order.stop_after_option_type,
complex_order.freq_from_time,
complex_order.freq_uom,
null;
// Calculate the duration from the first admin-time to the last admin-time.
temp_duration1 := (last temp_admin_time_list)
- (first temp_admin_time_list);
//Calculate the duration from the last admin-time to when the
// child order should stop
temp_duration2 := (last temp_admin_time_list)
- first (last 2 from temp_admin_time_list);
// Add the two durations
complex_order_stop_after_duration := temp_duration1 + temp_duration2;
endif; //if complex_order.stop_after_option_type
if order_complex_order_type is in ( 1, 5) //Sequential or <Multiple> Frequency
and exist complex_order_stop_after_duration
then
// Calculate and Set the DTMs
if HH = 1
then
complex_order.calculated_start_dtm := order_med_significant_date;
complex_order.estimated_stop_dtm := order_med_significant_date
+ complex_order_stop_after_duration - 1 minute;
else
// Add 1 minute back to the prior stop dtm to calculate the new start dtm
complex_order.calculated_start_dtm := prior_estimated_stop_dtm
+ 1 minute;
complex_order.estimated_stop_dtm := prior_estimated_stop_dtm
+ complex_order_stop_after_duration;
endif; // if HH
// Reset the Prior DTM
prior_estimated_stop_dtm := complex_order.estimated_stop_dtm;
elseif order_complex_order_type = 3 //Concurrent
then
if exist alternating_day_start_dtm_list[HH]
then
complex_order.calculated_start_dtm := alternating_day_start_dtm_list[HH];
endif;
if exist complex_order_stop_after_duration
then
complex_order.estimated_stop_dtm := complex_order.calculated_start_dtm
+ complex_order_stop_after_duration - 1 minute;
endif; //if exist complex_order_stop_after_duration
endif; //if order_complex_order_type
enddo; //for complex_order
endif; //if order_is_held
//-------------------------------------------------------------------
// Remove Discontinued/Canceled Order Variable Components, if needed
//-------------------------------------------------------------------
// If any of the child orders have been discontinued/canceled
// the dosage range should ignored the discontinued/ canceled doses.
// This is handled by removing the discontinued/canceled object(s)
// from the list of Order Variable Components.
// A discontinued/canceled order has an OrderStatusLevelNum of 69.
if exist complex_order_list
and any (complex_order_list.child_order_status_level_num = 69)
then
// Find the Order Variable Component Objects that are NOT Discontinued
complex_order_list := complex_order_list where
(complex_order_list.child_order_status_level_num <> 69
or complex_order_list.child_order_status_level_num is NULL);
endif; //if exist complex_order_list
//------------------------------------------------------------------
// Create and Populate Med_Data_Object for the Main Order (CV3Order)
//------------------------------------------------------------------
// This is the MAIN Order. It can be a Regular, IV-Additive or Complex Order
//Create One Med_Data_Object
mdo_main_order_list := ();
instance := new Med_Data_Object;
mdo_main_order_list := mdo_main_order_list, instance;
// Support for outpatient order: populate outpatient order properties
if EvokingObject.AlternateOrderType = 2
then
mdo_main_order_list.is_outpatient_order := TRUE;
mdo_main_order_list.is_script := order_AdditionalInfo_obj.IsScript;
else
mdo_main_order_list.is_outpatient_order := FALSE;
endif;
// If the Main Order is a Complex Order with a frequency of <Multiple>
// Do not populate the dose information on this instance of the object.
// Instead, transfer the data to the other instances of the object for the Complex Order.
// This transfer is done in the STD_Func_Dosage_Retrieve_Components MLM.
if order_med_frequency = "<Multiple>"
and exist complex_order_list
then
transfer_dose_to_complex_order_child_component := TRUE;
else
transfer_dose_to_complex_order_child_component := FALSE;
// Populate Med_Data_Object with Main Order Data
mdo_main_order_list.order_med_dose_low := (order_med_dose_low_str AS NUMBER);
mdo_main_order_list.order_med_units := order_med_uom;
mdo_main_order_list.calc_med_per_uom := last (user_value
where (user_data_code = "CalcUOMPer"));
// Select the Calc Dose Method and set it in the Med_Data_Object
temp_calc_dose_method := (last (user_value
where (user_data_code = "CalcDoseMethod"))) AS NUMBER;
mdo_main_order_list.calc_dose_method := temp_calc_dose_method;
// Find the CalcDoseMethod and
// Set the calculated-doses based on the CalcDoseMethod
// 0 means the dose is stored as a single-dose-per-xx
// 1 means the dose is stored as a total-daily-dose-per-xx
// Convert to single-dose-per-xx by dividing the total-daily-dose-per-xx
// by the conversion_factor_total
if temp_calc_dose_method = 0
then
mdo_main_order_list.calc_med_dose_high := (last (user_value
where (user_data_code = "CalcActualDose")))AS NUMBER;
mdo_main_order_list.calc_med_dose_low := (last (user_value
where (user_data_code = "CalcActualDose")))AS NUMBER;
elseif temp_calc_dose_method = 1
then
conversion_factor_total := call calc_freqmult_daily with
order_med_frequency, OrderInfo_FreqFromTime, OrderInfo_FreqUOM;
temp_calc_med_dose := ((last (user_value
where (user_data_code = "CalcActualDose")))AS NUMBER) / conversion_factor_total;
mdo_main_order_list.calc_med_dose_high := temp_calc_med_dose;
mdo_main_order_list.calc_med_dose_low := temp_calc_med_dose;
endif; //if temp_calc_dose_method = 0
//When the high dose is NULL, substitute the low dose.
if exist order_med_dose_high_str
then mdo_main_order_list.order_med_dose_high := (order_med_dose_high_str AS NUMBER);
else mdo_main_order_list.order_med_dose_high := (order_med_dose_low_str AS NUMBER);
endif; //if exist order_med_dose_high_str
endif; //if order_med_frequency = "<Multiple>"
// Populate the object with the remaining data
mdo_main_order_list.med_data_guid := order_guid;
mdo_main_order_list.order_med_frequency := order_med_frequency;
mdo_main_order_list.order_interval := order_interval;
mdo_main_order_list.order_med_name := order_name;
mdo_main_order_list.order_med_route := order_med_route;
mdo_main_order_list.order_med_significant_date := order_med_significant_date;
mdo_main_order_list.stop_dtm := order_stopdtm;
mdo_main_order_list.stop_after_value := (OrderInfo_order_stop_after_value AS NUMBER) ;
mdo_main_order_list.stop_after_option_type := (OrderInfo_order_stop_after_option AS NUMBER);
mdo_main_order_list.freq_from_time := orderinfo_freqfromtime AS NUMBER;
mdo_main_order_list.freq_to_time := orderinfo_freqtotime AS NUMBER;
mdo_main_order_list.freq_uom := orderinfo_frequom;
mdo_main_order_list.order_catalog_item_obj := order_catalog_item_obj;
//Determine the Med_Order_Type
if exist comp_name_list
then mdo_main_order_list.med_order_type := "IV-Additive";
elseif exist complex_order_list
then mdo_main_order_list.med_order_type := "Complex Order";
else
mdo_main_order_list.med_order_type := "Regular";
endif; // if exist complex_order_list
//----------------------------------------------------------
// Create and Populate Med_Data_Objects with IV-Additives
//----------------------------------------------------------
mdo_iv_additive_list := ();
//Only execute this code if there are IV-Additives that
//are not part of a complex order.
if exist comp_name_list AND not exist complex_order_list
then
for AA in (1 seqto count (comp_name_list)) do
instance := new Med_Data_Object;
mdo_iv_additive_list := mdo_iv_additive_list, instance;
//If the dose is calculated for the IV-Additive,
//then a calc_dose_method of zero is the only one allowed.
if exist comp_calc_actual_dose_list[AA]
then instance.calc_dose_method := 0;
endif; //if exist comp_calc_actual_dose_list[AA]
//When the high dose is NULL, substitute the low dose.
if exist comp_hi_dose_list[AA]
then instance.order_med_dose_high := comp_hi_dose_list[AA] AS NUMBER;
else instance.order_med_dose_high := comp_low_dose_list[AA] AS NUMBER;
endif; //if exist comp_hi_dose_list[AA]
enddo; // for AA
mdo_iv_additive_list.med_order_type := "IV-Additive";
mdo_iv_additive_list.med_data_guid := comp_guid_list;
mdo_iv_additive_list.calc_med_dose_high := (comp_calc_actual_dose_list AS NUMBER);
mdo_iv_additive_list.calc_med_dose_low := (comp_calc_actual_dose_list AS NUMBER);
mdo_iv_additive_list.calc_med_per_uom := comp_calc_uom_per_list;
mdo_iv_additive_list.order_med_dose_low := (comp_low_dose_list AS NUMBER);
mdo_iv_additive_list.order_med_frequency := order_med_frequency;
mdo_iv_additive_list.order_interval := order_interval;
mdo_iv_additive_list.order_med_name := comp_name_list;
mdo_iv_additive_list.order_med_route := order_med_route;
mdo_iv_additive_list.order_med_units := comp_uom_list;
mdo_iv_additive_list.order_med_significant_date := order_med_significant_date;
mdo_iv_additive_list.stop_dtm := order_stopdtm;
mdo_iv_additive_list.stop_after_value := (OrderInfo_order_stop_after_value AS NUMBER) ;
mdo_iv_additive_list.stop_after_option_type :=
(OrderInfo_order_stop_after_option AS NUMBER);
mdo_iv_additive_list.freq_from_time := orderinfo_freqfromtime AS NUMBER;
mdo_iv_additive_list.freq_to_time := orderinfo_freqtotime AS NUMBER;
mdo_iv_additive_list.freq_uom := orderinfo_frequom;
mdo_iv_additive_list.order_catalog_item_obj := comp_catalog_item_obj_list;
mdo_iv_additive_list.is_iv_additive := true;
endif; //if exist comp_name_list
//----------------------------------------------------------
// Create and Populate Med_Data_Objects with Complex Orders
//----------------------------------------------------------
//Create Med_Data_Objects
mdo_complex_order_list := ();
numComplexItems := 0;
//Only execute this code if there are Complex Order Components
if exist complex_order_list
then
complexIVOrder := exists comp_name_list;
numIVItems := 0;
numComplexItems := count complex_order_list;
if ( complexIVOrder )
then
numIVItems := count comp_name_list;
endif;
for BB in ( 1 seqto numComplexItems ) do
instance := new Med_Data_Object;
mdo_complex_order_list := mdo_complex_order_list, instance;
// Populate the High and Low Doses
// Use the Doses from the Complex Order Component (OrderVariableComponent)
dosageLow := complex_order_list[BB].dosage_low AS NUMBER;
dosageHigh := complex_order_list[BB].dosage_high AS NUMBER;
instance.order_med_dose_low := dosageLow;
//When the HIGH DOSE is NULL, substitute the low dose from the Component
if exist dosageHigh
then instance.order_med_dose_high := dosageHigh;
else instance.order_med_dose_high := dosageLow;
endif; //if exist complex_order_list[BB].calc_actual_dose
// Select the Calc Dose Method and set it in the Med_Data_Object
temp_calc_dose_method := complex_order_list[BB].calc_dose_method AS NUMBER;
instance.calc_dose_method := temp_calc_dose_method;
// Find the CalcDoseMethod and
// Set the calculated-doses based on the CalcDoseMethod
// 0 means the dose is stored as a single-dose-per-xx
// 1 means the dose is stored as a total-daily-dose-per-xx
// Convert to single-dose-per-xx by dividing the total-daily-dose-per-xx
// by the conversion_factor_total
if temp_calc_dose_method = 0
then
instance.calc_med_dose_high := complex_order_list[BB].calc_actual_dose AS NUMBER;
instance.calc_med_dose_low := complex_order_list[BB].calc_actual_dose AS NUMBER;
elseif temp_calc_dose_method = 1
then
conversion_factor_total := call calc_freqmult_daily with
complex_order_list[BB].frequency_code,
(complex_order_list[BB].freq_from_time AS NUMBER),
complex_order_list[BB].freq_uom;
temp_calc_med_dose :=
(complex_order_list[BB].calc_actual_dose AS NUMBER) / conversion_factor_total;
instance.calc_med_dose_high := temp_calc_med_dose;
instance.calc_med_dose_low := temp_calc_med_dose;
endif; //if temp_calc_dose_method = 0
//Populate Med_Data_Object Instances with Complex_Order data
instance.order_med_units := complex_order_list[BB].uom;
instance.calc_med_per_uom := complex_order_list[BB].calc_uom_per;
instance.order_med_route := complex_order_list[BB].order_route_code;
instance.order_med_frequency := complex_order_list[BB].frequency_code;
instance.order_med_significant_date := complex_order_list[BB].calculated_start_dtm;
instance.stop_dtm := complex_order_list[BB].Estimated_Stop_Dtm;
instance.stop_after_value := complex_order_list[BB].stop_after_value AS NUMBER;
instance.stop_after_option_type :=
complex_order_list[BB].stop_after_option_type AS NUMBER;
instance.freq_from_time := complex_order_list[BB].freq_from_time AS NUMBER;
instance.freq_to_time := complex_order_list[BB].freq_to_time AS NUMBER;
instance.freq_uom := complex_order_list[BB].freq_uom;
instance.med_data_guid := complex_order_list[BB].guid;
instance.order_med_name := order_name;
instance.order_catalog_item_obj := order_catalog_item_obj;
//Populate Med_Data from OTHER Sources
instance.med_order_type := "Complex Order";
instance.order_interval := NULL;
for IV in ( 1 seqto numIVItems ) do
// Create an IV Order instance
if numIVItems >= 1
then
IV_instance := new Med_Data_Object;
dosageLow := comp_low_dose_list[IV] AS NUMBER;
dosageHigh := comp_hi_dose_list[IV] AS NUMBER;
//When the HIGH DOSE is NULL, substitute the low dose from the Component
if exist dosageHigh
then IV_instance.order_med_dose_high := dosageHigh;
else IV_instance.order_med_dose_high := dosageLow;
endif;
IV_instance.order_med_dose_low := dosageLow;
IV_instance.order_med_units := comp_uom_list[IV];
IV_instance.calc_med_per_uom := comp_calc_uom_per_list[IV];
IV_instance.order_med_name := comp_name_list[IV];
IV_instance.order_catalog_item_obj := comp_catalog_item_obj_list[IV];
// Get rest of information from the current component
IV_instance.order_med_route := complex_order_list[BB].order_route_code;
IV_instance.order_med_frequency := complex_order_list[BB].frequency_code;
IV_instance.order_med_significant_date := complex_order_list[BB].calculated_start_dtm;
IV_instance.stop_dtm := complex_order_list[BB].Estimated_Stop_Dtm;
IV_instance.stop_after_value := complex_order_list[BB].stop_after_value AS NUMBER;
IV_instance.stop_after_option_type :=
complex_order_list[BB].stop_after_option_type AS NUMBER;
IV_instance.freq_from_time := complex_order_list[BB].freq_from_time AS NUMBER;
IV_instance.freq_to_time := complex_order_list[BB].freq_to_time AS NUMBER;
IV_instance.freq_uom := complex_order_list[BB].freq_uom;
IV_instance.med_data_guid := complex_order_list[BB].guid;
IV_instance.med_order_type := "Complex Order";
IV_instance.is_iv_additive := true;
mdo_complex_order_list := mdo_complex_order_list, IV_instance;
endif;
enddo; // for IV
enddo; // for BB
endif; //if exist complex_order_list
//-----------------------------------
//Create One List of Med_Data_Objects
//-----------------------------------
med_data_list := mdo_main_order_list, mdo_iv_additive_list, mdo_complex_order_list;
//-----------------------
//Create the Sort Numbers
//-----------------------
med_data_list.sort_number := 1 seqto count med_data_list;
//-----------------------
//Get values used for multum support
//-----------------------
med_data_list.is_order := true;
// Look up the multum drug catalog key for unit and route
for med_data in med_data_list
do
med_data.order_med_uom_id := last(uom_drug_catalog_key where (uom_facility_code = med_data.order_med_units)) as NUMBER;
med_data.order_med_route_id := last(route_drug_catalog_key where (route_code = med_data.order_med_route)) as NUMBER;
enddo;
med_data_list.grouper_id := med_data_list.order_catalog_item_obj.DrcGrouperID;
//-------------------------------------------
// Determine DOSE BASIS and Calculate WEIGHT
//-------------------------------------------
(calc_text_list,
dose_basis_list,
wt_kg_list,
updated_calc_med_per_uom_list) :=
call func_dosage_basis with (ht_cm, wt_kg, med_data_list.calc_med_per_uom);
//Set DoseBasis data in the Med Data object
med_data_list.calc_text := calc_text_list;
med_data_list.updated_calc_med_per_uom := updated_calc_med_per_uom_list;
med_data_list.dose_basis := dose_basis_list;
med_data_list.wt_kg := wt_kg_list;
// If the MLM is going to use the conversion factor logic then
// the admin_times are not needed.
Calculation_Method := call func_calc_method with med_data_list;
med_data_list.calculation_method := Calculation_Method;
if Calculation_Method = "SUMMED"
then
//---------------------------------------------------------
//Populate the Administration Times in the Med_Data_Object
//---------------------------------------------------------
orderCalculationFailed := true;
performOrderCalculation := true;
performMLMCalculation := false;
next_StartTime := "";
FirstComponentPosition := 2;
CalculateAdministration := true;
numMedItems := count med_data_list;
// Get the latest estimated Start and Stop dates from the complex order.
// Make sure any NULL dates are removed
if order_complex_order_type = 3 then
latest_startDtm := max (med_data_list.order_med_significant_date where it is not NULL);
latest_stopDtm := (max (med_data_list.stop_dtm where it is not NULL)) + 1 minute;
latest_calcDtm := max ((latest_startDtm, latest_stopDtm) where it is not NULL);
endif;
// First attempt to calculate the admin times using the order calculation object.
// If any one of the calculations, throw all away and then calculate using
// the MLM estimation method.
while orderCalculationFailed do
for CC in med_data_list do
// If a Complex order or a complex IV Additive order skip the first
// object as it is the master and contains no dosage information.
if ( CC.med_order_type = "Complex order" OR complexIVOrder ) AND
CC.sort_number = 1
then
CC.admin_dtm_list_calc_method := "Master";
CalculateAdministration := false;
else
CalculateAdministration := true;
// Optimization: For IV and Complex IV orders only need to calculate the
// the administration times once per administration.
if med_data_list[1].med_order_type = "IV-Additive"
then
// If the current IV component has the same name as the master item
// then it is the start of a new component block
if med_data_list[1].Order_med_name = CC.Order_med_name
then
FirstComponentPosition := CC.sort_number;
CalculateAdministration := true;
else
// If a reqular IV-Additive, just always copy the first additive.
if CC.med_order_type = "IV-Additive"
then
if exists med_data_list[1].admin_dtm_list
then
//copy first object{{{SINGLE-QUOTE}}}s DTMs to the current object since they are both the same
CC.admin_dtm_list := med_data_list[1].admin_dtm_list;
CC.admin_dtm_list_calc_method := med_data_list[1].admin_dtm_list_calc_method;
CalculateAdministration := false;
endif;
// If a Complex IV-Additive, copy the first additive of the current component
elseif CC.med_order_type = "Complex order" AND complexIVOrder = true
then
// Copy the previously calculated DTMs
CC.admin_dtm_list := med_data_list[FirstComponentPosition].admin_dtm_list;
CC.admin_dtm_list_calc_method := med_data_list[FirstComponentPosition].admin_dtm_list_calc_method;
CalculateAdministration := false;
endif;
endif;
endif;
endif;
if CalculateAdministration
then
isShiftFrequency := false;
// Set the calcStart_dtm to the calculated start date.
// If this is a sequential order then only set it if not null,
// otherwise for concurrent orders always set; it might be NULL.
if CC.order_med_significant_date is not null OR
order_complex_order_type = 3
then
calcStart_dtm := CC.order_med_significant_date;
endif;
// Initialize the calculated stop date. For sequential orders
// this value will be reset to null. For concurrent orders the
// date will be calculated based on the latest start or stop information.
calcStop_dtm := CC.stop_dtm;
if order_guid = CC.med_data_guid then
componentGUID := null;
else
componentGUID := CC.med_data_guid;
endif;
// First try to calculate all adminstrations using the order object
if performOrderCalculation
then
// If a complex order and the type is sequential or <Multiple> then
// do not trust the EstimatedStopDtm calcuated by the order object.
// It can sometimes be wrong. Instead pass a NULL to the DetermineAdministrationTimes
// function and let the order figure it out.
if order_complex_order_type is in (1,5) AND // Sequential or <Multiple>
CC.med_order_type = "Complex order"
then
calcStop_dtm := null;
else
// If the Stop date is null and stop after type is not times (4)
// then the code needs to calculate a stop date or the order calculations will fail.
if CC.stop_after_option_type <> 4 // Times
then
if CC.stop_dtm is NULL
then
// For concurrent orders that do not have a defined stop date
// the MLM will estimate a stop date based on 24 hours after
// the last stop or start date, which ever is greater.
if order_complex_order_type = 3 then
calcStop_dtm := latest_calcDtm + (1 day - 1 minute);
else
// For sequential orders calculate a new stop date
// based on the frequency and stop information.
calcStop_dtm := call func_dosage_calc_stopdtm with
CC.order_med_frequency,
calcStart_dtm, //CC.order_med_significant_date,
CC.freq_uom,
CC.freq_from_time,
CC.freq_to_time,
CC.stop_after_value,
CC.stop_after_option_type,
order_TaskScheduleDefinition_obj;
endif;
else
calcStop_dtm := CC.stop_dtm;
endif;
else
// If stop after option is times, then ignore any calculated
// stop date from the order.
calcStop_dtm := null;
endif;
endif;
// Need a flag to indicate when we are on the first and last
// complex item component.
isFirstComponent := (CC.sort_number = 2);
isLastComponent := (CC.sort_number = numMedItems - numIVItems);
// Calculate the admin times using the cached order object. These times
// are more accurate.
(admin_answer,
calc_success,
isShiftFrequency) := call func_dosage_admin_times_generated with
order_guid,
componentGUID,
calcStart_dtm, // CC.order_med_significant_date,
calcStop_dtm,
isFirstComponent,
isLastComponent;
// If the calculation succeeds then continue processing. if it fails
// Then discard previous calculations and revert to MLM estimation
// method.
if NOT calc_success OR first admin_answer is NULL
then
// If a concurrent order then switch for this component to
// MLM calculation logic, then switch back to try the order calculation
// for the next component.
if order_complex_order_type = 3 then
performMLMCalculation := true;
else
orderCalculationFailed := true;
performOrderCalculation := false;
next_StartTime := "";
endif;
else // Success
CC.admin_dtm_list_calc_method := "Order";
CC.calcStop_dtm := calcStop_dtm;
orderCalculationFailed := false;
performMLMCalculation := false;
endif;
endif; // PerformOrderCalculation
// If the order object calculation fails then
// calculate using the MLM estimation method.
if performMLMCalculation
then
// reset the admin times
CC.admin_dtm_list := null;
(admin_answer,
next_StartTime,
isShiftFrequency) := call func_dosage_admin_times with
CC.order_med_frequency,
calcStart_dtm, // CC.order_med_significant_date,
calcStop_dtm, // CC.stop_dtm,
CC.stop_after_value,
CC.stop_after_option_type,
CC.freq_from_time,
CC.freq_uom,
order_TaskScheduleDefinition_obj ;
CC.admin_dtm_list_calc_method := "MLM";
orderCalculationFailed := false; // always success
// Capture for debug, the calculated Start and stop times.
CC.calcStart_dtm := calcStart_dtm;
if calcStop_dtm is NULL
then
CC.calcStop_dtm := next_StartTime - 1 minute;
else
CC.calcStop_dtm := calcStop_dtm;
endif;
// Set the start Dtm for the next sequential component
// value can be overridden by the component{{{SINGLE-QUOTE}}}s CalculatedStartDtm.
calcStart_dtm := next_StartTime;
endif;
// Only populate admin_dtm_list when DTMs exist
if exist admin_answer
then CC.admin_dtm_list := admin_answer;
endif;
CC.isShiftFrequency := isShiftFrequency;
endif; // CalculateAdministration
enddo; //for CC
performMLMCalculation := true;
performOrderCalculation := false;
enddo; // orderCalculationFailed
endif; // Use_conversion_factor
// Set the multum frequency id
for med_data_item in med_data_list
do
med_data_item.multum_freq_id := last (frequency_drug_catalog_key where (frequency_code = med_data_item.order_med_frequency));
enddo;
//Always Conclude True
Conclude True;
;;
action:
return med_data_list;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,323 @@
maintenance:
title: Creates a List of Objects with Medication Data;;
mlmname: STD_FUNC_DOSAGE_LISTS_RX;;
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: Gathers the dosing data for the prescription.
;;
explanation: The dosing data for a prescription are stored in several tables/objects.
This MLM gathers all the data from the various sources and consolidates them into
an object called Med_Data_Object.
There can be one Med_Data_Objects for a prescription.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// include common data structures
std_dosage_includes := MLM {{{SINGLE-QUOTE}}}std_func_dosage_includes{{{SINGLE-QUOTE}}};
include std_dosage_includes;
(
ht_cm,
wt_kg
) := ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
//--------------
// Declare MLMs
//--------------
func_dosage_basis := MLM {{{SINGLE-QUOTE}}}std_func_dosage_basis{{{SINGLE-QUOTE}}};
calc_freqmult_daily := MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_daily{{{SINGLE-QUOTE}}};
func_calc_method := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_CALC_METHOD{{{SINGLE-QUOTE}}};
//---------------------
// Declare the Objects
//---------------------
//The Med_Data_Object declaration moved to STD_FUNC_DOSAGE_INCLUDES
//Note: Med_Data_GUID is the SXAAMBClientPrescription.CDSUniqueIDGUID
//--------------------------------------------
// Get the current order{{{SINGLE-QUOTE}}}s Dosage information
//--------------------------------------------
(rx_name,
rx_dose_str,
rx_dose_uom,
rx_dose_uom_id,
rx_frequency,
rx_frequency_multiplier,
rx_frequency_id,
rx_route,
rx_route_id,
rx_start_date,
rx_stop_date,
rx_renewal_date,
rx_cds_unique_guid,
rx_status_type,
rx_prescription_type,
rx_formulary_drug_key,
rx_formulary_brand_key,
rx_generic_item_id,
rx_generic_name_id,
rx_instructions,
backup) := read last {ClientPrescription:
DrugName,
DoseAmount,
DoseUOM,
DoseUOMID,
Frequency,
FrequencyMultiplier,
ScriptFrequencyID,
Route,
RouteID,
StartDate,
EndDate,
RenewalDate,
CDSUniqueIDGUID,
StatusType,
PrescriptionType,
FormularyDrugKey,
FormularyBrandKey,
GenericItemID,
GenericNameID,
Instructions,
BackUp
REFERENCING EvokingObject
WHERE PrescriptionTypeDescription in ("Rx", "Hx", "E") };
// Dnum value can be found in SXAAMBClientPrescription table
// when the formulary brand key does not exist and
// the formulary drug key exists
if ((rx_formulary_brand_key is null or rx_formulary_brand_key = "")
and (exists rx_formulary_drug_key and rx_formulary_drug_key <> "")
)
then
multum_dnum := rx_formulary_drug_key;
else
(multum_dnum) := read last {
"SELECT name.DrugCatalogKey "
|| "FROM SXARxGenericName name "
|| "WHERE name.GenericNameID = " || SQLEX(rx_generic_name_id)
};
endif;
// MMDC value is not always filled in the SXAAMBClientPrescription table
// The value can be found when the formulary brand key exists
if (exists rx_formulary_brand_key
and rx_formulary_brand_key <> "")
then
multum_mmdc := rx_formulary_drug_key;
else
(multum_mmdc) := read last {
"SELECT item.DrugCatalogKey "
|| "FROM SXARxGenericItem item "
|| "WHERE item.GenericItemID = " || SQLEX(rx_generic_item_id)
};
endif;
(multum_route_desc, multum_route_id) := read last {
"SELECT rxRoute.RouteDescription, rxRoute.DrugCatalogKey "
|| "FROM SXARxRoute rxRoute "
|| "WHERE rxRoute.RxRouteID = " || SQLEX(rx_route_id)
};
if (multum_route_id is NULL)
then
(multum_route_desc, multum_route_id) := read last {
"SELECT route_description, route_code "
|| "FROM SXAMTmultum_clinical_routeSYN "
|| "WHERE route_description = " || SQLEX(rx_route) || "\n"
|| "UNION "
|| "SELECT route_description, route_code "
|| "FROM SXAMTmultum_product_routeSYN "
|| "WHERE route_description =" || SQLEX(rx_route) || "\n"
|| "UNION "
|| "SELECT ne.nomenclature_description, ne.nomenclature_id "
|| "FROM SXAMTdrc_nomenclatureSYN ne "
|| "WHERE ne.nomenclature_description = " || SQLEX(rx_route)
};
endif;
multum_route_id := multum_route_id as NUMBER;
(multum_unit, multum_uom_id) := read last {
"SELECT unit.Name, unit.DrugCatalogKey "
|| "FROM SXARxUnitOfMeasure unit "
|| "WHERE (unit.RxUOMID = " || SQLEX(rx_dose_uom_id) || ") "
|| "or (unit.Name = " || SQLEX(rx_dose_uom) || ")"
};
if (multum_uom_id is null)
then
(multum_unit, multum_uom_id) := read last {
"SELECT ne.nomenclature_description, ne.nomenclature_id "
||"FROM SXAMTdrc_nomenclatureSYN ne "
||"WHERE ne.nomenclature_description = " || SQLEX(rx_dose_uom)
};
endif;
// Extract multum frequency id
(multum_frequency, multum_frequency_id) := read last {
"SELECT f.Description, f.DrugCatalogKey "
||"FROM SXAAMBScriptFrequency f "
||"INNER JOIN SXAMTmultum_frequencySYN mf on mf.frequency_code = f.DrugCatalogKey "
||"WHERE f.ScriptFrequencyID = " || SQLEX(rx_frequency_id)
};
if multum_mmdc is not NULL
then
// SXAABMClientPrescription.FormularyDrugKey stores both mmdc and dnum
(multum_grouper_id) := read last {
"SELECT drc.grouper_id "
|| "FROM SXAMTdrc_grouper_route_mmdcSYN drc "
|| "WHERE drc.main_multum_drug_code = " || SQLEX(multum_mmdc)
};
else
(grouper_id_list, grouper_name_list) := read {
"SELECT grp.grouper_id, grp.grouper_name "
|| "FROM SXAMTdrc_grouperSYN grp "
|| "WHERE grp.drug_id = " || SQLEX(multum_dnum)
};
grouper_count := count grouper_id_list;
if grouper_count = 1
then
multum_grouper_id := grouper_id_list[1];
else
multum_grouper_id := last (grouper_id_list WHERE grouper_name_list = rx_name);
if (multum_grouper_id is NULL)
then
grouper_info_list := ();
for ind in (1 seqto grouper_count)
do
grouper_info_instance := new Grouper_Info_Object;
grouper_info_instance.grouper_id := grouper_id_list[ind];
grouper_info_instance.grouper_name := grouper_name_list[ind];
grouper_info_list := grouper_info_list, grouper_info_instance;
enddo;
dnum_grouper_info := new Patient_Property_Obj;
dnum_grouper_info.type := "Dnum-Grouper";
dnum_grouper_info.value := grouper_info_list;
dnum_grouper_info.is_unmapped := true;
endif;
endif;
endif;
// Get the evoking object{{{SINGLE-QUOTE}}}s visit TimeZone
(visit_time_zone) := read last { ClientVisit: TimeZone };
;;
evoke:
;;
logic:
//------------------------------------------------------------------
// Create and Populate Med_Data_Object for the Prescription (SXAAMBClientPrescription)
//------------------------------------------------------------------
//Create One Med_Data_Object
med_data_list := ();
instance := new Med_Data_Object;
med_data_list := med_data_list, instance;
if (rx_renewal_date is not null)
then
rx_significant_dtm := rx_renewal_date;
else
rx_significant_dtm := rx_start_date;
endif;
if rx_significant_dtm is null
then
rx_significant_dtm := (day floor of (now AS TIME visit_time_zone));
endif;
// Populate the object with the remaining data
med_data_list.med_data_guid := rx_cds_unique_guid;
med_data_list.order_med_frequency := rx_frequency;
med_data_list.multum_freq_id := multum_frequency_id;
med_data_list.order_med_name := rx_name;
med_data_list.order_med_route := rx_route;
med_data_list.order_med_significant_date := rx_significant_dtm;
med_data_list.stop_dtm := rx_stop_date;
med_data_list.rx_instructions := rx_instructions;
med_data_list.freq_multiplier := (rx_frequency_multiplier AS NUMBER);
med_data_list.order_med_dose_high := (rx_dose_str AS NUMBER);
med_data_list.order_med_dose_low := (rx_dose_str AS NUMBER);
med_data_list.order_med_units := rx_dose_uom;
med_data_list.order_med_route := rx_route;
// Map multum values
med_data_list.order_med_route_id := multum_route_id AS NUMBER;
med_data_list.order_med_uom_id := multum_uom_id AS NUMBER;
med_data_list.grouper_id := multum_grouper_id;
med_data_list.multum_mmdc := multum_mmdc AS NUMBER;
med_data_list.multum_dnum := multum_dnum;
//-------------------------------------------
// Determine DOSE BASIS and Calculate WEIGHT
//-------------------------------------------
(calc_text_list,
dose_basis_list,
wt_kg_list,
updated_calc_med_per_uom_list) :=
call func_dosage_basis with (ht_cm, wt_kg, "");
//Set DoseBasis data in the Med Data object
med_data_list.calc_text := calc_text_list;
med_data_list.updated_calc_med_per_uom := updated_calc_med_per_uom_list;
med_data_list.dose_basis := dose_basis_list;
med_data_list.wt_kg := wt_kg_list;
// If the MLM is going to use the conversion factor logic then
// the admin_times are not needed.
Calculation_Method := call func_calc_method with med_data_list;
med_data_list.calculation_method := Calculation_Method;
//-----------------------
//Create the Sort Numbers
//-----------------------
med_data_list.sort_number := 1 seqto count med_data_list;
med_data_list.med_order_type := "Prescription";
med_data_list.is_order := false;
//Always Conclude True
Conclude True;
;;
action:
return med_data_list, dnum_grouper_info;
;;
Urgency: 50;;
end:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
maintenance:
title: ;;
mlmname: STD_FUNC_DOSAGE_MSG_FORMAT_DOSE_RANGE;;
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: Creates the dose detail string for the Dosage-Range checking MLM.
;;
explanation: This MLM creates the dose string:
- Formats the dose value for display
- When lower and upper doses are different, it shows as "lower dose" - "upper dose"
- When the doses are the same, it shows the single dose
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
add_commas := MLM {{{SINGLE-QUOTE}}}SYS_FORMAT_NUMBER{{{SINGLE-QUOTE}}};
(lower_dose, upper_dose) := ARGUMENT;
;;
priority: 50
;;
evoke:
;;
logic:
if lower_dose = upper_dose
then
formatted_lower_dose:= call add_commas with (,lower_dose);
printable_dose_range:= formatted_lower_dose ;
else
formatted_lower_dose := call add_commas with (,lower_dose);
formatted_upper_dose := call add_commas with (,upper_dose);
printable_dose_range := formatted_lower_dose || "-"
|| formatted_upper_dose ;
endif; //if lower_dose = upper_dose
// Always Conclude True
conclude true;
;;
action:
return printable_dose_range;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,298 @@
maintenance:
title: Executes the stored procedure that retrieves Multum dosage ranges from the database;;
mlmname: STD_FUNC_DOSAGE_MULTUM;;
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: Finds the appropriate dose-range from the multum grouper dose ranges and
returns the information to the calling MLM.
;;
explanation: The MLM assists the STD_Func_Dosage_Rules MLM to retrieve Multum dosage ranges
from the database that may be out of range
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// include common data structures
std_dosage_includes := MLM {{{SINGLE-QUOTE}}}std_func_dosage_includes{{{SINGLE-QUOTE}}};
include std_dosage_includes;
(
drc_grouper_id,
drug_name,
multum_dnum,
multum_mmdc,
order_med_route,
order_med_route_id,
is_generic_route,
order_med_significant_date,
order_med_units,
order_med_uom_id,
order_med_frequency,
multum_freq_id,
med_order_type,
patient_birthday_info_on_order,
wt_kg,
BSA_value,
intl_patient_gender,
has_liver_disease_bit,
dialysis_type_str,
serum_creatinine,
intentionally_unmapped_frequency_list,
alert_if_missing_flags,
is_order,
patient_info,
core_uom_const
) := ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
// Declare the MLMs that can be called
xml_params := MLM {{{SINGLE-QUOTE}}}STD_Func_Dosage_XML_Params{{{SINGLE-QUOTE}}};
// Change the internal patient gender to XML
if (intl_patient_gender = "O")
then
patient_gender := "U";
else
patient_gender := intl_patient_gender;
endif;
// Need User GUID for security purposes
//user_GUID := read last { UserInfo: GUID }; // fails under specflow
user_GUID := read last { StateInfo: UserGUID };
// XML parameter
( input_param_xml,
missing_route,
unmapped_route,
missing_uom,
unmapped_uom
) := call xml_params with
(
// Common medication data
drc_grouper_id,
multum_dnum,
multum_mmdc,
order_med_route,
order_med_route_id,
is_generic_route,
order_med_significant_date,
order_med_units,
order_med_uom_id,
multum_freq_id,
med_order_type,
is_order,
// Patient data
patient_birthday_info_on_order,
true, //has_valid_birthdate,
wt_kg,
BSA_value,
patient_gender,
// Item Catalog only
false, //for_item_catalog
null, //catalog_item_obj,
// Multum only
has_liver_disease_bit,
dialysis_type_str,
serum_creatinine,
// Flags and constants
alert_if_missing_flags,
patient_info,
core_uom_const
);
debug_db_str:="EXEC SCMMultumGrouperDosageRangePR "
|| SQL(input_param_xml) || ", "
|| SQL(user_GUID);
if (exists drc_grouper_id
or alert_if_missing_flags.cannot_check_DNUM_Rx_to_Multum)
then
// Call the stored procedure
(
found_matching_case_list,
dosage_type_list,
case_id_list,
grouper_id_list,
route_id_list,
route_list,
contraindication_list,
recommendation_list,
actual_lower_dose_list,
actual_upper_dose_list,
actual_uom_id_list,
actual_dose_uom_list,
conversion_factor_list,
actual_dose_freq_list,
is_PER_WT_list,
is_PER_M2_list,
age_criteria_list,
weight_criteria_list,
gender_criteria_list,
renal_criteria_list,
creatinine_criteria_list,
liver_criteria_list,
condition_criteria_list,
uom_conversion_issue_list,
route_conversion_issue_list,
frequency_issue_list,
is_default_list,
hard_stop_high_list,
hard_stop_low_list,
crcl_within_range_list,
estimated_age_used_list
) := read { "EXEC SCMMultumGrouperDosageRangePR "
|| SQL(input_param_xml) || ", "
|| SQL(user_GUID)
};
endif;
;;
evoke:
;;
logic:
multum_dosage_range_list := ();
if exists found_matching_case_list
then
row_count := count found_matching_case_list;
list_indices := 1 seqto row_count;
// Step through the multum results and create the dosage range list
for ind in list_indices
do
dosage_range_item := new Dosage_Range_Object;
multum_dosage_range_list := multum_dosage_range_list, dosage_range_item;
dosage_range_item.med_name := drug_name;
if found_matching_case_list[ind] = 1 or found_matching_case_list[ind] = true
then
dosage_range_item.match_found := true;
else
dosage_range_item.match_found := false;
endif;
if ((dosage_type_list[ind] = "daily dose range checking (metric)" ) or
(dosage_type_list[ind] = "daily dose range checking (formulation)" ))
then
dosage_range_item.dosage_type := "total";
dosage_range_item.is_range := true;
elseif ((dosage_type_list[ind] = "single dose range checking (metric)" ) or
(dosage_type_list[ind] = "single dose range checking (formulation)" ))
then
dosage_range_item.dosage_type := "single";
dosage_range_item.is_range := true;
else
dosage_range_item.dosage_type := "contraindication";
dosage_range_item.is_range := false;
endif;
dosage_range_item.contraindication_msg := contraindication_list[ind];
dosage_range_item.recommendation_msg := recommendation_list[ind];
dosage_range_item.lower_dose := actual_lower_dose_list[ind];
dosage_range_item.upper_dose := actual_upper_dose_list[ind];
dosage_range_item.unit_of_measure := actual_dose_uom_list[ind];
dosage_range_item.age_criteria := age_criteria_list[ind];
dosage_range_item.weight_criteria := weight_criteria_list[ind];
dosage_range_item.gender_criteria := gender_criteria_list[ind];
dosage_range_item.renal_criteria := renal_criteria_list[ind];
dosage_range_item.creatinine_criteria := creatinine_criteria_list[ind];
dosage_range_item.liver_criteria := liver_criteria_list[ind];
dosage_range_item.condition_criteria := condition_criteria_list[ind];
dosage_range_item.is_PER_WT := is_PER_WT_list[ind];
dosage_range_item.is_PER_M2 := is_PER_M2_list[ind];
dosage_range_item.conversion_factor := conversion_factor_list[ind];
dosage_range_item.uom_conversion_issue := uom_conversion_issue_list[ind] in (1, true);
dosage_range_item.crcl_within_range := crcl_within_range_list[ind] in (1, true);
route_conversion_issue := route_conversion_issue_list[ind] in (1, true);
if is_generic_route
then
dosage_range_item.unrecognized_route_conversion_issue := route_conversion_issue;
else
dosage_range_item.inapplicable_route_conversion_issue := route_conversion_issue;
endif;
// Dose range frequency
dosage_range_item.dose_frequency := actual_dose_freq_list[ind];
if multum_freq_id is null
then
if ( order_med_frequency not in (intentionally_unmapped_frequency_list, null)
and alert_if_missing_flags.unmapped_frequency )
then
dosage_range_item.frequency_issue := "unmapped";
endif;
else
if frequency_issue_list[ind] in (1, true)
then
dosage_range_item.frequency_issue := "too frequent";
endif;
endif;
// multum data will always be "Dose Reg", as the denominator will be multiplied
dosage_range_item.dose_calc_method := "Dose Reg";
dosage_range_item.corrected_uom := actual_dose_uom_list[ind];
dosage_range_item.is_multum := true;
dosage_range_item.grouper_id := grouper_id_list[ind];
dosage_range_item.case_id := case_id_list[ind];
dosage_range_item.route := route_list[ind];
dosage_range_item.route_id := route_id_list[ind];
dosage_range_item.med_route := order_med_route;
dosage_range_item.med_route_id := order_med_route_id;
is_default := false;
if (is_default_list[ind] = 1)
then
is_default := true;
endif;
dosage_range_item.is_default := is_default;
dosage_range_item.hard_stop_high := hard_stop_high_list[ind];
dosage_range_item.hard_stop_low := hard_stop_low_list[ind];
dosage_range_item.estimated_age_used := estimated_age_used_list[ind];
enddo;
uom_conversion_issue := any (uom_conversion_issue_list = 1);
endif;
/* Always conclude true to return variables to calling MLM */
CONCLUDE TRUE;
;;
action:
return (multum_dosage_range_list, missing_route, unmapped_route, missing_uom, unmapped_uom, uom_conversion_issue);
;;
end:

View File

@@ -0,0 +1,694 @@
maintenance:
title: Retrieve Dosage Data for Complex Order Components ;;
mlmname: STD_FUNC_DOSAGE_RETRIEVE_COMPONENTS;;
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: Retrieves dosage data for Complex Order components.
;;
explanation: The data for complex orders are located in several objects and tables.
This MLM retrieves data from the Evoking Object, Backup Object, Unsubmitted Orders, and the
database from the following tables: CV3Order, CV3OrderAddnIlnfo, CV3OrderUserData, and
CV3OrderVariableComponent. The data are consolidated into the Order_Variable_Component
object.
When the Master Order is first created, all the data in the CV3OrderVariableComponent
table are up to date. However, as the Child Orders are generated and later modified,
the data in the CV3OrderVariableComponent table can become out of date. This MLM uses
data from the Evoking Object, Backup Object, Unsubmitted Orders, and the Database
to create Order_Variable_Component objects that have the most current dosing information.
Two lists of Order_Variable_Component objects are created--one for the current order
and the other for the backup order. These lists are passed back to the calling MLM.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
// Set to true if logging is needed.
log_execution_info := false;
// Get the current order
(client_guid,
order_guid,
order_name,
order_dosage_low,
order_dosage_high,
order_uom,
order_route_code,
order_frequency_code,
order_significant_dtm,
order_stop_dtm,
order_additional_info_obj,
order_user_data_obj,
order_variable_component_obj,
order_backup_obj ) := read last
{ Order: ClientGUID, GUID, Name,
DosageLow, DosageHigh, UOM, OrderRouteCode, FrequencyCode,
SignificantDtm, StopDtm,
OrderAdditionalInfo, OrderUserData,
OrderVariableComponent, Backup
REFERENCING EvokingObject};
// Get the backup order
(backup_order_name,
backup_order_dosage_low,
backup_order_dosage_high,
backup_order_uom,
backup_order_route_code,
backup_order_frequency_code,
backup_order_significant_dtm,
backup_order_stop_dtm,
backup_order_additional_info_obj,
backup_order_user_data_obj,
backup_order_variable_component_obj ) := read last
{ Order: Name,
DosageLow, DosageHigh, UOM, OrderRouteCode, FrequencyCode,
SignificantDtm, StopDtm,
OrderAdditionalInfo, OrderUserData,
OrderVariableComponent
REFERENCING order_backup_obj};
// Get the current order{{{SINGLE-QUOTE}}}s data from OrderAdditionalInfo object
(order_freq_from_time,
order_freq_to_time,
order_freq_uom,
order_stop_after_option,
order_stop_after_value,
order_dosing_option_guid ) := read last
{ OrderAdditionalInfo:
FreqFromTime, FreqToTime, FreqUom,
StopAfterOption, StopAfterValue, DosingOptionGuid
REFERENCING order_additional_info_obj };
// Get the backup order{{{SINGLE-QUOTE}}}s data from OrderAdditionalInfo object
(backup_order_freq_from_time,
backup_order_freq_to_time,
backup_order_freq_uom,
backup_order_stop_after_option,
backup_order_stop_after_value ) := read last
{ OrderAdditionalInfo:
FreqFromTime, FreqToTime, FreqUom,
StopAfterOption, StopAfterValue
REFERENCING backup_order_additional_info_obj };
// Get the current order{{{SINGLE-QUOTE}}}s data from OrderUserData object
(order_user_data_code_list,
order_user_data_value_list ) := read
{ OrderUserData: UserDataCode, Value
REFERENCING order_user_data_obj
Where UserDataCode is in ("CalcDoseMethod" , "CalcActualDose", "CalcUOMPer" ) };
// Get the backup order{{{SINGLE-QUOTE}}}s data from OrderUserData object
(backup_order_user_data_code_list,
backup_order_user_data_value_list ) := read
{ OrderUserData: UserDataCode, Value
REFERENCING backup_order_user_data_obj
Where UserDataCode is in ("CalcDoseMethod" , "CalcActualDose", "CalcUOMPer" ) };
// Get DosingOptionGridColumn Info
dosing_option_data_item_code_list := read
{"Select DataItemCode "
||" From CV3DosingOptionGridColumn "
||" Where DosingOptionGUID = " || SQLEX(order_dosing_option_guid) };
// Declare Order_Variable_Component Object
Order_Variable_Component := OBJECT
[Sequence_Number, Complex_Order_Type, GUID, Order_GUID, Child_Order_GUID,
Dosage_Low, Dosage_High, UOM, Order_Route_Code,
Frequency_Code, Freq_From_Time, Freq_To_Time, Freq_Uom,
Calculated_Start_Dtm, Estimated_Stop_Dtm,
Stop_After_Value, Stop_After_Option_Type,
Calc_Dose_Method, Calc_Actual_Dose, Calc_UOM_Per,
// The following object fields are place holders.
// The data are populated after the READ statement.
Child_Order_Status_Level_Num ];
// Populate Order_Variable_Component
current_ovc_list := read as Order_Variable_Component
{OrderVariableComponent:
SequenceNumber, ComplexOrderType, GUID, OrderGUID, ChildOrderGUID,
DosageLow, DosageHigh, UOM, OrderRouteCode,
FrequencyCode, FreqFromTime, FreqToTime, FreqUom,
CalculatedStartDtm, EstimatedStopDtm,
StopAfterValue, StopAfterOptionType,
CalcDoseMethod, CalcActualDose, CalcUOMPer
REFERENCING order_variable_component_obj};
// Populate Order_Variable_Component object with BACK Data
backup_ovc_list := read as Order_Variable_Component
{OrderVariableComponent:
SequenceNumber, ComplexOrderType, GUID, OrderGUID, ChildOrderGUID,
DosageLow, DosageHigh, UOM, OrderRouteCode,
FrequencyCode, FreqFromTime, FreqToTime, FreqUom,
CalculatedStartDtm, EstimatedStopDtm,
StopAfterValue, StopAfterOptionType,
CalcDoseMethod, CalcActualDose, CalcUOMPer
REFERENCING backup_order_variable_component_obj };
// Get the OrderVariableComponent Objects in the Correct Sequence before using the data.
// The identical CalculatedStartDtm could cause them to be out of order.
current_ovc_list := SORT sequence_number DATA current_ovc_list;
backup_ovc_list := SORT Sequence_Number DATA backup_ovc_list;
// Make a copy of the OrderVariableComponent Objects before they are changed.
// This will assist in Debugging problems
debug_current_ovc_list := CLONE current_ovc_list;
debug_backup_ovc_list := CLONE backup_ovc_list;
// Check if the Complex Order{{{SINGLE-QUOTE}}}s Master Order has any Child Orders
complex_order_child_order_guid_list := current_ovc_list.Child_Order_GUID where it is present;
// If the Complex Order Child Orders generated
// then look up DTM information on the Child Orders.
if exist complex_order_child_order_guid_list
then
// Set Flag to update OrderVariableComponent data before making comparisons
update_order_variable_component_data := TRUE;
// If there is only 1 Child Order GUID,
// Make it a singleton so that the SQL query works correctly
if count complex_order_child_order_guid_list = 1 then
complex_order_child_order_guid_list := first complex_order_child_order_guid_list;
endif;
// Retrieve Data for the Child Orders from the Database
(db_complex_child_order_guid_list,
db_complex_child_order_name_list,
db_complex_child_order_dosage_low_list,
db_complex_child_order_dosage_high_list,
db_complex_child_order_uom_list,
db_complex_child_order_route_code_list,
db_complex_child_order_frequency_code_list,
db_complex_child_order_freq_from_time_list,
db_complex_child_order_freq_to_time_list,
db_complex_child_order_freq_uom_list,
db_complex_child_order_stop_after_option_list,
db_complex_child_order_stop_after_value_list,
db_complex_child_order_significant_dtm_list,
db_complex_child_order_stop_dtm_list,
db_complex_child_order_status_level_num_list ) := read
{ "Select O.GUID, O.Name, "
||" M.DosageLow, M.DosageHigh, M.UOM, M.OrderRouteCode, O.FrequencyCode, "
||" OA.FreqFromTime, OA.FreqToTime, OA.FreqUom, OA.StopAfterOption, OA.StopAfterValue, "
||" ConvSignificantDtm.TimeValue as SignificantDtm, "
||" ConvStopDtm.TimeValue as StopDtm, "
||" O.OrderStatusLevelNum "
||" From CV3Order AS O "
||" JOIN CV3MedicationExtension AS M "
||" ON O.ClientGUID = M.ClientGUID AND O.GUID = M.GUID "
||" JOIN CV3OrderAddnlInfo as OA "
||" ON O.ClientGUID = OA.ClientGUID AND O.GUID = OA.GUID "
||" INNER JOIN CV3ClientVisit AS CV "
||" ON O.ClientVisitGUID = CV.GUID "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(CV.TimeZone, O.SignificantDtm) AS ConvSignificantDtm "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(CV.TimeZone, O.StopDtm) AS ConvStopDtm "
||" WHERE O.ClientGUID = "|| SQLEX(client_guid)
||" AND O.GUID in ( " || complex_order_child_order_guid_list || ")" };
// Retrieve The Child Orders{{{SINGLE-QUOTE}}} OrderUserData Information from Database
(db_complex_child_order_user_data_code_guid_list,
db_complex_child_order_user_data_code_list,
db_complex_child_order_user_data_value_list ) := read
{ "Select OrderGUID, UserDataCode, Value "
||" From CV3OrderUserData "
||" Where ClientGUID = " || SQLEX(client_guid)
||" AND OrderGUID IN ( " || complex_order_child_order_guid_list || " )"
||" AND UserDataCode IN ({{{SINGLE-QUOTE}}}CalcDoseMethod{{{SINGLE-QUOTE}}} , {{{SINGLE-QUOTE}}}CalcActualDose{{{SINGLE-QUOTE}}}, {{{SINGLE-QUOTE}}}CalcUOMPer{{{SINGLE-QUOTE}}} ) " };
// Retrieve Child Orders{{{SINGLE-QUOTE}}} OrderAdditionalInfo data from Unsubmitted Orders
(unsub_complex_child_order_guid_list,
unsub_complex_child_order_name_list,
unsub_complex_child_order_dosage_low_list,
unsub_complex_child_order_dosage_high_list,
unsub_complex_child_order_uom_list,
unsub_complex_child_order_route_code_list,
unsub_complex_child_order_frequency_code_list,
unsub_complex_child_order_significant_dtm_list,
unsub_complex_child_order_stop_dtm_list,
unsub_complex_child_order_additional_info_obj_list,
unsub_complex_child_order_user_data_obj_list ) := read
{ Unsubmitted Order:
GUID, Name,
DosageLow, DosageHigh, UOM, OrderRouteCode, FrequencyCode
SignificantDtm, StopDtm, OrderAdditionalInfo, OrderUserData
Where GUID is in (complex_order_child_order_guid_list) };
unsub_complex_child_order_additional_guid_list := ();
unsub_complex_child_order_freq_from_time_list := ();
unsub_complex_child_order_freq_to_time_list := ();
unsub_complex_child_order_freq_uom_list := ();
unsub_complex_child_order_stop_after_option_list := ();
unsub_complex_child_order_stop_after_value_list := ();
for temp_unsub_order_additional_info_obj in
unsub_complex_child_order_additional_info_obj_list do
(temp_unsub_complex_child_order_additional_guid,
temp_unsub_complex_child_order_freq_from_time,
temp_unsub_complex_child_order_freq_to_time ,
temp_unsub_complex_child_order_freq_uom,
temp_unsub_complex_child_order_stop_after_option,
temp_unsub_complex_child_order_stop_after_value ) := read last
{ OrderAdditionalInfo:
GUID, FreqFromTime, FreqToTime, FreqUom,
StopAfterOption, StopAfterValue
REFERENCING temp_unsub_order_additional_info_obj };
unsub_complex_child_order_additional_guid_list :=
unsub_complex_child_order_additional_guid_list,
temp_unsub_complex_child_order_additional_guid;
unsub_complex_child_order_freq_from_time_list :=
unsub_complex_child_order_freq_from_time_list,
temp_unsub_complex_child_order_freq_from_time;
unsub_complex_child_order_freq_to_time_list :=
unsub_complex_child_order_freq_to_time_list,
temp_unsub_complex_child_order_freq_to_time;
unsub_complex_child_order_freq_uom_list :=
unsub_complex_child_order_freq_uom_list,
temp_unsub_complex_child_order_freq_uom;
unsub_complex_child_order_stop_after_option_list :=
unsub_complex_child_order_stop_after_option_list,
temp_unsub_complex_child_order_stop_after_option;
unsub_complex_child_order_stop_after_value_list :=
unsub_complex_child_order_stop_after_value_list,
temp_unsub_complex_child_order_stop_after_value;
enddo; //for temp_unsub_order_additional_info_obj
unsub_complex_child_order_user_data_code_guid_list := ();
unsub_complex_child_order_user_data_code_list := ();
unsub_complex_child_order_user_data_value_list := ();
for temp_unsub_order_user_data_obj in unsub_complex_child_order_user_data_obj_list do
// Get the unsumbitted order{{{SINGLE-QUOTE}}}s data from OrderUserData object
(temp_unsub_complex_child_order_user_data_code_guid_list,
temp_unsub_complex_child_order_user_data_code_list,
temp_unsub_complex_child_order_user_data_value_list ) := read
{ OrderUserData: OrderGUID, UserDataCode, Value
REFERENCING temp_unsub_order_user_data_obj
Where UserDataCode is in ("CalcDoseMethod" , "CalcActualDose", "CalcUOMPer" ) };
unsub_complex_child_order_user_data_code_guid_list :=
unsub_complex_child_order_user_data_code_guid_list,
temp_unsub_complex_child_order_user_data_code_guid_list;
unsub_complex_child_order_user_data_code_list :=
unsub_complex_child_order_user_data_code_list,
temp_unsub_complex_child_order_user_data_code_list ;
unsub_complex_child_order_user_data_value_list :=
unsub_complex_child_order_user_data_value_list,
temp_unsub_complex_child_order_user_data_value_list ;
enddo; //for temp_unsub_order_user_data_obj
endif; //if exist complex_order_child_order_guid_list
;;
evoke:
;;
logic:
//----------------------------------------------------------------------------
// Update the CURRENT Order Variable Components with the Main Order Form Data
//----------------------------------------------------------------------------
// The facility can choose which dosing data will appear on the Order Option Grid
// and which will appear on the Main Order Form. This algorithm consolidates
// all the dosing data for the CURRENT Complex Order onto the OrderVariableComponent Object,
// thus eliminating the need to look in more than one place for the data.
// Loop through the Current Order Variable Components and Consolidate Data
for current_ovc in current_ovc_list do
if not exist current_ovc.dosage_low
then current_ovc.dosage_low := order_dosage_low;
endif;
if not exist current_ovc.dosage_high
then current_ovc.dosage_high := order_dosage_high;
endif;
if not exist current_ovc.uom
then current_ovc.uom := order_uom;
endif;
if not exist current_ovc.order_route_code
then current_ovc.order_route_code := order_route_code;
endif;
if not exist current_ovc.frequency_code
then current_ovc.frequency_code := order_frequency_code;
endif;
if not exist current_ovc.freq_from_time
or (current_ovc.freq_from_time AS NUMBER) = 0
then current_ovc.freq_from_time := order_freq_from_time;
endif;
if not exist current_ovc.freq_to_time
or (current_ovc.freq_to_time AS NUMBER) = 0
then current_ovc.freq_to_time := order_freq_to_time;
endif;
if not exist current_ovc.freq_uom
then current_ovc.freq_uom := order_freq_uom;
endif;
// If StopAfter or StopDate are NOT in the Dosing Option Grid
// then get the data from the Main Order Form.
if NOT ANY (("StopAfter", "StopDate") IS IN dosing_option_data_item_code_list)
then
if (current_ovc.stop_after_value AS NUMBER) = 0
then current_ovc.stop_after_value := order_stop_after_value;
endif;
if (current_ovc.stop_after_option_type AS NUMBER) = 0
then current_ovc.stop_after_option_type := order_stop_after_option;
endif;
if not exist current_ovc.estimated_stop_dtm
then current_ovc.estimated_stop_dtm := order_stop_dtm;
endif;
endif; //if NOT ANY (("StopAfter", "StopDate")
if not exist current_ovc.calc_actual_dose
and not exist current_ovc.calc_uom_per
and "CalcDoseMethod" IS IN order_user_data_code_list
and "CalcActualDose" IS IN order_user_data_code_list
and "CalcUOMPer" IS IN order_user_data_code_list
then
current_ovc.calc_actual_dose := first (order_user_data_value_list
where order_user_data_code_list = "CalcActualDose");
current_ovc.calc_dose_method := first (order_user_data_value_list
where order_user_data_code_list = "CalcDoseMethod");
current_ovc.calc_uom_per := first (order_user_data_value_list
where order_user_data_code_list = "CalcUOMPer");
endif; //if not exist current_ovc.calc_actual_dose
enddo; //for current_ovc
//----------------------------------------------------------------------------
// Update the BACKUP Order Variable Components with the Main Order Form Data
//----------------------------------------------------------------------------
// The facility can choose which dosing data will appear on the Order Option Grid
// and which will appear on the Main Order Form. This algorithm consolidates
// all the dosing data for the BACKUP Complex Order onto the OrderVariableComponent Object,
// thus eliminating the need to look in more than one place for the data.
// Loop through the BackUp Order Variable Components and Consolidate Data
for backup_ovc in backup_ovc_list do
if not exist backup_ovc.dosage_low
then backup_ovc.dosage_low := backup_order_dosage_low;
endif;
if not exist backup_ovc.dosage_high
then backup_ovc.dosage_high := backup_order_dosage_high;
endif;
if not exist backup_ovc.uom
then backup_ovc.uom := backup_order_uom;
endif;
if not exist backup_ovc.order_route_code
then backup_ovc.order_route_code := backup_order_route_code;
endif;
if not exist backup_ovc.frequency_code
then backup_ovc.frequency_code := backup_order_frequency_code;
endif;
if not exist backup_ovc.freq_from_time
or (backup_ovc.freq_from_time AS NUMBER) = 0
then backup_ovc.freq_from_time := backup_order_freq_from_time;
endif;
if not exist backup_ovc.freq_to_time
or (backup_ovc.freq_to_time AS NUMBER) = 0
then backup_ovc.freq_to_time := backup_order_freq_to_time;
endif;
if not exist backup_ovc.freq_uom
then backup_ovc.freq_uom := backup_order_freq_uom;
endif;
// If StopAfter or StopDate are NOT in the Dosing Option Grid
// then get the data from the Main Order Form.
if NOT ANY (("StopAfter", "StopDate") IS IN dosing_option_data_item_code_list)
then
if (backup_ovc.stop_after_value AS NUMBER) = 0
then backup_ovc.stop_after_value := backup_order_stop_after_value;
endif;
if (backup_ovc.stop_after_option_type AS NUMBER) = 0
then backup_ovc.stop_after_option_type := backup_order_stop_after_option;
endif;
if not exist backup_ovc.estimated_stop_dtm
then backup_ovc.estimated_stop_dtm := backup_order_stop_dtm ;
endif;
endif; //if NOT ANY (("StopAfter", "StopDate")
if not exist backup_ovc.calc_actual_dose
and not exist backup_ovc.calc_uom_per
and "CalcActualDose" IS IN order_user_data_code_list
and "CalcUOMPer" IS IN order_user_data_code_list
and "CalcDoseMethod" IS IN order_user_data_code_list
then
backup_ovc.calc_actual_dose := first (backup_order_user_data_value_list
where backup_order_user_data_code_list = "CalcActualDose");
backup_ovc.calc_dose_method := first (backup_order_user_data_value_list
where backup_order_user_data_code_list= "CalcDoseMethod");
backup_ovc.calc_uom_per := first (backup_order_user_data_value_list
where backup_order_user_data_code_list = "CalcUOMPer");
endif; //if not exist backup_ovc.calc_actual_dose
enddo; //for backup_ovc
//---------------------------------------------------------------------------------
// Update CURRENT and BACKUP Order Variable Components with Data from the DATABASE
//---------------------------------------------------------------------------------
// When the Child Orders have been generated, the data from the Child Order are the
// actual data and are more accurate than the "estimated" data on the Master Order.
// For example, the CalculatedStartDtm and the StopDtm in the
// Complex Orders{{{SINGLE-QUOTE}}} Order Variable Component objects can get out of date,
// since it is not always updated from the Child Orders.
// This algorthim will update the Order Variable Component objects from the database.
// This algorthim will also add the Child Order{{{SINGLE-QUOTE}}}s OrderStatusLevelNum to objects.
if update_order_variable_component_data
then
// Loop Through the lists from the Database
for DD in (1 seqto count db_complex_child_order_guid_list) do
// Find the matching CURRENT Order Variable Component
found_current_ovc := current_ovc_list
where current_ovc_list.Child_Order_GUID =
db_complex_child_order_guid_list[DD];
// Find the matching BACKUP Order Variable Component
found_backup_ovc := backup_ovc_list
where backup_ovc_list.Child_Order_GUID =
db_complex_child_order_guid_list[DD];
// Add the OrderStatusLevelNum to the CURRENT Order Variable Component
found_current_ovc.child_order_status_level_num :=
db_complex_child_order_status_level_num_list[DD];
// Replace CalculatedStartDtm and StopDtm for the
// CURRENT and BACKUP Order Variable Component
found_current_ovc.calculated_start_dtm := db_complex_child_order_significant_dtm_list[DD];
found_backup_ovc.calculated_start_dtm := db_complex_child_order_significant_dtm_list[DD];
found_current_ovc.estimated_stop_dtm := db_complex_child_order_stop_dtm_list[DD];
found_backup_ovc.estimated_stop_dtm := db_complex_child_order_stop_dtm_list[DD];
//Replace the other Dosing Data for the CURRENT and BACKUP Order Variable Component
found_current_ovc.dosage_low := db_complex_child_order_dosage_low_list[DD];
found_backup_ovc.dosage_low := db_complex_child_order_dosage_low_list[DD];
found_current_ovc.dosage_high := db_complex_child_order_dosage_high_list[DD];
found_backup_ovc.dosage_high := db_complex_child_order_dosage_high_list[DD];
found_current_ovc.uom := db_complex_child_order_uom_list[DD];
found_backup_ovc.uom := db_complex_child_order_uom_list[DD];
found_current_ovc.order_route_code := db_complex_child_order_route_code_list[DD];
found_backup_ovc.order_route_code := db_complex_child_order_route_code_list[DD];
found_current_ovc.frequency_code := db_complex_child_order_frequency_code_list[DD];
found_backup_ovc.frequency_code := db_complex_child_order_frequency_code_list[DD];
found_current_ovc.freq_from_time := db_complex_child_order_freq_from_time_list[DD];
found_backup_ovc.freq_from_time := db_complex_child_order_freq_from_time_list[DD];
found_current_ovc.freq_to_time := db_complex_child_order_freq_to_time_list[DD];
found_backup_ovc.freq_to_time := db_complex_child_order_freq_to_time_list[DD];
found_current_ovc.freq_uom := db_complex_child_order_freq_uom_list[DD];
found_backup_ovc.freq_uom := db_complex_child_order_freq_uom_list[DD];
found_current_ovc.stop_after_value := db_complex_child_order_stop_after_value_list[DD];
found_backup_ovc.stop_after_value := db_complex_child_order_stop_after_value_list[DD];
found_current_ovc.stop_after_option_type :=
db_complex_child_order_stop_after_option_list[DD];
found_backup_ovc.stop_after_option_type :=
db_complex_child_order_stop_after_option_list[DD];
if "CalcActualDose" IS IN db_complex_child_order_user_data_code_list
and "CalcUOMPer" IS IN db_complex_child_order_user_data_code_list
and "CalcDoseMethod" IS IN db_complex_child_order_user_data_code_list
then
temp_db_calc_actual_dose := first (db_complex_child_order_user_data_value_list
where db_complex_child_order_user_data_code_list = "CalcActualDose"
and db_complex_child_order_user_data_code_guid_list =
db_complex_child_order_guid_list[DD]);
found_current_ovc.calc_actual_dose := temp_db_calc_actual_dose;
found_backup_ovc.calc_actual_dose := temp_db_calc_actual_dose;
temp_db_calc_dose_method := first (db_complex_child_order_user_data_value_list
where db_complex_child_order_user_data_code_list= "CalcDoseMethod"
and db_complex_child_order_user_data_code_guid_list =
db_complex_child_order_guid_list[DD]);
found_current_ovc.calc_dose_method := temp_db_calc_dose_method;
found_backup_ovc.calc_dose_method := temp_db_calc_dose_method;
temp_db_calc_uom_per := first (db_complex_child_order_user_data_value_list
where db_complex_child_order_user_data_code_list = "CalcUOMPer"
and db_complex_child_order_user_data_code_guid_list =
db_complex_child_order_guid_list[DD]);
found_current_ovc.calc_uom_per := temp_db_calc_uom_per;
found_backup_ovc.calc_uom_per := temp_db_calc_uom_per;
endif; //if "CalcActualDose"
enddo; //for DD
//-------------------------------------------------------------------------------------
// Update CURRENT Order Variable Components with Data from the UNSUBMITTED Child Order
//-------------------------------------------------------------------------------------
// When the Child Order is modified, the data from the Unsubmitted Child Order contains the
// changed data. The Child Order{{{SINGLE-QUOTE}}}s data are more accurate than the data on the Master Order.
// For example, if the Child Order{{{SINGLE-QUOTE}}}s route changed and the route field is NOT on the
// dosing option grid, then the route on the Master Order is not updated.
// The Master Order{{{SINGLE-QUOTE}}}s Order Variable Component objects can get out of date,
// since it is not always updated from the Child Orders.
// This algorthim will update the CURRENT Order Variable Component objects from the
// Unsubmitted Child Order.
// Note that the BACKUP Order Variable Component objects are not updated by this algorithm.
// Loop Through the lists from the Unsubmitted Orders
for UU in (1 seqto count unsub_complex_child_order_guid_list) do
// Find the matching CURRENT Order Variable Component
found_current_ovc := current_ovc_list
where current_ovc_list.Child_Order_GUID =
unsub_complex_child_order_guid_list[UU];
// Replace CalculatedStartDtm and StopDtm for the CURRENT Order Variable Component
// from the Unsubmitted Orders
found_current_ovc.calculated_start_dtm :=
unsub_complex_child_order_significant_dtm_list[UU];
found_current_ovc.estimated_stop_dtm :=
unsub_complex_child_order_stop_dtm_list[UU];
//Replace the other Dosing Data for the CURRENT Order Variable Component
found_current_ovc.dosage_low := unsub_complex_child_order_dosage_low_list[UU];
found_current_ovc.dosage_high := unsub_complex_child_order_dosage_high_list[UU];
found_current_ovc.uom := unsub_complex_child_order_uom_list[UU];
found_current_ovc.order_route_code := unsub_complex_child_order_route_code_list[UU];
found_current_ovc.frequency_code := unsub_complex_child_order_frequency_code_list[UU];
if exist unsub_complex_child_order_additional_guid_list
then
found_current_ovc.freq_from_time :=
first (unsub_complex_child_order_freq_from_time_list
where unsub_complex_child_order_additional_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.freq_to_time :=
first (unsub_complex_child_order_freq_to_time_list
where unsub_complex_child_order_additional_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.freq_uom :=
first (unsub_complex_child_order_freq_uom_list
where unsub_complex_child_order_additional_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.stop_after_value :=
first (unsub_complex_child_order_stop_after_value_list
where unsub_complex_child_order_additional_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.stop_after_option_type :=
first (unsub_complex_child_order_stop_after_option_list
where unsub_complex_child_order_additional_guid_list =
unsub_complex_child_order_guid_list [UU]);
endif; //if exist unsub_complex_child_order_additional_guid_list
if "CalcActualDose" IS IN unsub_complex_child_order_user_data_code_list
and "CalcUOMPer" IS IN unsub_complex_child_order_user_data_code_list
and "CalcDoseMethod" IS IN unsub_complex_child_order_user_data_code_list
then
found_current_ovc.calc_actual_dose :=
first (unsub_complex_child_order_user_data_value_list
where unsub_complex_child_order_user_data_code_list = "CalcActualDose"
and unsub_complex_child_order_user_data_code_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.calc_dose_method :=
first (unsub_complex_child_order_user_data_value_list
where unsub_complex_child_order_user_data_code_list = "CalcDoseMethod"
and unsub_complex_child_order_user_data_code_guid_list =
unsub_complex_child_order_guid_list [UU]);
found_current_ovc.calc_uom_per :=
first (unsub_complex_child_order_user_data_value_list
where unsub_complex_child_order_user_data_code_list = "CalcUOMPer"
and unsub_complex_child_order_user_data_code_guid_list =
unsub_complex_child_order_guid_list [UU]);
endif; //if "CalcActualDose"
enddo; //for UU
endif; //if update_order_variable_component_data
//Always Conclude True
Conclude True;
;;
action:
// Return the list of CURRENT and BACKUP Order_Variable_Compenent Objects
return current_ovc_list, backup_ovc_list;
;;
Urgency: 50;;
end:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,710 @@
maintenance:
title: Track the Average and Total Daily Doses ;;
mlmname: STD_FUNC_DOSAGE_TRACKER;;
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: This MLM tracks the Average Daily Dose and the Total Daily Dose.
;;
explanation: This MLM calculates the Average Daily Dose and the Total Daily Dose
by using two approaches:
1. The CONVERSION FACTOR approach does the calculation by multiplying the single dose
by a conversion factor that is based on the order{{{SINGLE-QUOTE}}}s frequency, or if Prescription.
2. The SUMMED DOSES approach uses the estimated dose administration times to sort
the single doses into 24-hour intervals. Then each 24-hour interval is summed
to calculate the Average and Total doses.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
med_data_list := ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
//Declare MLMs that can be called
calc_freqmult_daily := MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_daily{{{SINGLE-QUOTE}}};
calc_freqmult_average:= MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_average{{{SINGLE-QUOTE}}};
func_dosage_trim := MLM {{{SINGLE-QUOTE}}}std_func_dosage_trim{{{SINGLE-QUOTE}}};
func_calc_method := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_CALC_METHOD{{{SINGLE-QUOTE}}};
//Declare the Dose_Tracker_Object
Dose_Tracker_Object := OBJECT [
Med_Data_GUID,
med_order_type,
med_name,
interval_begin_dtm,
interval_end_dtm,
num_doses_in_24hrs, // indicates how many number of doses should be in 24hr
num_doses, // indicates how many doses would be administered in 24hr
total_dose_low,
total_dose_high,
uom,
route,
start_date ];
//Declare the Sum_Tracker_Object
Sum_Tracker_Object := OBJECT
[interval_begin_dtm,
interval_end_dtm,
is_last_24hr_interval,
has_full_24hrs_doses,
med_order_type,
med_name,
route,
total_dose_low,
total_dose_high,
uom,
start_date ];
//Declare the Total_Tracker_Object
Total_Tracker_Object := OBJECT
[
sort_number,
interval_begin_dtm_list,
is_last_24hr_interval,
has_full_24hrs_doses,
med_order_type,
med_name,
route,
total_dose_low,
total_dose_high,
uom,
dose_calc_method_number,
total_calc_med_dose_low,
total_calc_med_dose_high,
calc_text,
retrieved_dose_range_data,
found_total_daily_dose,
missing_height,
missing_weight,
processed_missing_data_msg,
met_criteria_under_24_hours,
processed_for_printing,
dose_range_check_method,
outside_total_daily_dose,
suppress_alert,
alert_msg_for_total,
met_criteria_has_shift_frequency,
start_date ];
//Declare the Average_Tracker_Object
Average_Tracker_Object := OBJECT
[
sort_number,
interval_begin_dtm_list,
is_last_24hr_interval,
has_full_24hrs_doses,
med_order_type,
med_name,
route,
average_dose_low,
average_dose_high,
uom,
dose_calc_method_number,
average_calc_med_dose_low,
average_calc_med_dose_high,
calc_text,
retrieved_dose_range_data,
found_average_daily_dose,
processed_missing_data_msg,
met_criteria_under_24_hours,
processed_for_printing,
irregular_schedule_used,
user_scheduled_weekly_used,
dose_range_check_method,
outside_average_daily_dose,
suppress_alert,
alert_msg_for_average,
met_criteria_has_shift_frequency,
start_date ];
;;
evoke:
;;
logic:
// Initialize Variables
dose_tracker_list := ();
sum_tracker_list := ();
total_tracker_list := ();
average_tracker_list := ();
Calculation_Method := call func_calc_method with med_data_list;
if Calculation_Method = "CONVERSION"
then
for med_data in med_data_list do
// Significant_date is important in several calculations and cannot
// be NULL. Set it to be the first calculated admin time.
if med_data.order_med_significant_date is null
then
med_data.order_med_significant_date := first med_data.admin_dtm_list;
endif;
//-----------------------------
//Calculate Total Daily Dose
//-----------------------------
// Find the Total_Tracker_Object
// The Med Order Type, Medication Name, and UOM must match
// Route must match or both be NULL
found_total_tracker := total_tracker_list where
(total_tracker_list.med_order_type = med_data.med_order_type
and total_tracker_list.med_name = med_data.order_med_name
and (total_tracker_list.route = med_data.order_med_route
or ((total_tracker_list.route is NULL)
and (med_data.order_med_route is NULL)))
and total_tracker_list.uom = med_data.order_med_units);
//and total_tracker_list.start_date = med_data.order_med_significant_date );
if not exist found_total_tracker
then
//Calculate the Total Daily Dose for the Highs and Low Doses
//Create a new object
total_instance := new Total_Tracker_Object;
total_tracker_list := total_tracker_list, total_instance;
//Populate the data
total_instance.dose_range_check_method := "Conversion Factor";
total_instance.med_order_type := med_data.med_order_type;
total_instance.med_name := med_data.order_med_name;
total_instance.route := med_data.order_med_route;
total_instance.uom := med_data.order_med_units;
total_instance.dose_calc_method_number := med_data.calc_dose_method;
total_instance.calc_text := med_data.calc_text;
total_instance.start_date := med_data.order_med_significant_date;
if (med_data.is_order)
then
// Call an MLM to calculate the conversion factor for Total Daily Dose
conversion_factor_ave := call calc_freqmult_daily
with med_data.order_med_frequency,
med_data.freq_from_time,
med_data.freq_uom;
else
conversion_factor_ave := med_data.freq_multiplier;
endif;
// Calculate the Low and High Doses for Total Daily Dose
// by multiplying the doses with the conversion factor
// AND Store the Doses
temp_total_dose_low := med_data.order_med_dose_low * conversion_factor_ave;
temp_total_dose_high := med_data.order_med_dose_high * conversion_factor_ave;
// Trim the Excess Decimals
rounded_trim_numbers_list := call func_dosage_trim with
med_data.order_med_dose_low, // a single number
(temp_total_dose_high, temp_total_dose_low); // a list of numbers
// Store Doses
total_instance.total_dose_high := rounded_trim_numbers_list[1];
total_instance.total_dose_low := rounded_trim_numbers_list[2];
endif; //not exist found_total_tracker
//-----------------------------
//Calculate Average Daily Dose
//-----------------------------
// Find the Average_Tracker_Object
// The Med Order Type, Medication Name, and UOM must match
// Route must match or both be NULL
found_average_tracker := average_tracker_list where
(average_tracker_list.med_order_type = med_data.med_order_type
and average_tracker_list.med_name = med_data.order_med_name
and (average_tracker_list.route = med_data.order_med_route
or ((average_tracker_list.route is NULL)
and (med_data.order_med_route is NULL)))
and average_tracker_list.uom = med_data.order_med_units );
if not exist found_average_tracker
then
//Calculate an Average for the Highs and Low Doses
//Create a new object
average_instance := new Average_Tracker_Object;
average_tracker_list := average_tracker_list, average_instance;
//Populate the data
average_instance.dose_range_check_method := "Conversion Factor";
average_instance.med_order_type := med_data.med_order_type;
average_instance.med_name := med_data.order_med_name;
average_instance.route := med_data.order_med_route;
average_instance.uom := med_data.order_med_units;
average_instance.dose_calc_method_number := med_data.calc_dose_method;
average_instance.calc_text := med_data.calc_text;
average_instance.start_date := med_data.order_med_significant_date;
// Call an MLM to calculate the conversion factor for Average Daily Dose
conversion_factor_ave := call calc_freqmult_average
with med_data.order_med_frequency,
med_data.freq_from_time,
med_data.freq_uom;
// Calculate the Low and High Doses for Average Daily Dose
// by multiplying the doses with the conversion factor
// AND Store the Doses
temp_average_dose_low := med_data.order_med_dose_low * conversion_factor_ave;
temp_average_dose_high := med_data.order_med_dose_high * conversion_factor_ave;
// no rounding for average dose for proper daily dose checking
average_instance.average_dose_high := temp_average_dose_high;
average_instance.average_dose_low := temp_average_dose_low;
endif; //not exist found_average_tracker
enddo; //for med_data
//**************************************************************
// Use the SUMMED-DOSE Dosage-Range Checking (newer approach )
//**************************************************************
else
//-----------------------------------------
//Create and Populate Dose_Tracker_Objects
//-----------------------------------------
// Remove NULL from the Admin_Dtm_List before doing a MIN function
temp_admin_dtm_list := ();
for med_data in med_data_list do
if exist med_data.admin_dtm_list
then
temp_admin_dtm_list := temp_admin_dtm_list, med_data.admin_dtm_list;
endif;
enddo; //for med_data
//Get the Earliest Administration Date-Time for the Medication Order
order_begin_dtm := MIN temp_admin_dtm_list;
// Loop Through Each Med_Data Object
for EE in med_data_list do
// Significant_date is important in several calculations and cannot
// be NULL. Set it to be the first calculated admin time.
if EE.order_med_significant_date is null
then
EE.order_med_significant_date := first EE.admin_dtm_list;
endif;
// Only create Dose_Tracker_Objects if the medication has a dose.
// If a medication has a dose, then the order_med_dose_low must have a value.
// Medication orders such as IV-solutions and Master Complex Orders do not have doses.
// So their order_med_dose_low is NULL. However, their components do have doses.
if exist EE.order_med_dose_low
then
// Find the dose instance based on the med GUID and Name.
dose_instance := last (dose_tracker_list where
(dose_tracker_list.Med_Data_GUID = EE.med_data_guid
and dose_tracker_list.order_med_name = EE.order_med_name));
dMultiplier := call calc_freqmult_average
with EE.order_med_frequency,
EE.freq_from_time,
EE.freq_uom;
num_doses_in_24hrs := 1;
if dMultiplier is not null
then
num_doses_in_24hrs := int floor of dMultiplier;
endif;
// Use the Medication{{{SINGLE-QUOTE}}}s Administation Date to Put the Doses in the Correct Object.
for admin_date in EE.admin_dtm_list do
// If a instance doesn{{{SINGLE-QUOTE}}}t yet exist or the admin date is beyond
// the current instance{{{SINGLE-QUOTE}}}s end date then create a new one.
if not exists dose_instance OR
(admin_date >= dose_instance.interval_end_dtm)
then
// Create a new Dose_Tracker_Object
dose_instance := new Dose_Tracker_Object;
//Add to the List of objects
dose_tracker_list := dose_tracker_list, dose_instance;
//Populate the new Dose_Tracker_Object with basic information
dose_instance.Med_Data_GUID := EE.med_data_guid;
dose_instance.med_order_type := EE.med_order_type;
dose_instance.med_name := EE.order_med_name;
dose_instance.uom := EE.order_med_units;
dose_instance.route := EE.order_med_route;
dose_instance.total_dose_low := 0;
dose_instance.total_dose_high := 0;
dose_instance.num_doses_in_24hrs := num_doses_in_24hrs;
dose_instance.num_doses := 0;
dose_instance.start_date := EE.order_med_significant_date;
//Calculate the Begin and End Time Intervals
//And Set Them
length_of_time := admin_date - order_begin_dtm;
multiplier := truncate (length_of_time / 24 hours) ;
dose_instance.interval_begin_dtm := order_begin_dtm + (multiplier * 24 hours);
dose_instance.interval_end_dtm := dose_instance.interval_begin_dtm + 24 hours;
endif; //if exist found_dose_tracker
//Populate Dose_Tracker with Doses
if exist EE.order_med_dose_low
then //use the low dose for dose low,
//otherwise the dose is null and we do not add null to a number.
dose_instance.total_dose_low := dose_instance.total_dose_low +
(EE.order_med_dose_low as number) ;
endif;
if exist EE.order_med_dose_high
then //use the high dose for dose high
dose_instance.total_dose_high := dose_instance.total_dose_high +
(EE.order_med_dose_high as number);
elseif exist EE.order_med_dose_low
then //use the low dose for dose high
dose_instance.total_dose_high := dose_instance.total_dose_high +
(EE.order_med_dose_low as number);
endif; //if exist EE.order_med_dose_high
// count the number of doses in 24 hr interval based on admin times.
dose_instance.num_doses := dose_instance.num_doses + 1;
enddo; //for admin_date
endif; //if exist EE.order_med_dose_low
enddo; //for EE
//------------------------------------------------------------------------
// Sum the Dose for Each 24-Hour Interval Across OrderVariableComponents
//------------------------------------------------------------------------
// Different Routes and UOMs must be summed separately
// Loop Through Each Dose_Tracker_Object
// And determine which Sum_Tracker_Object to Use
for FF in dose_tracker_list do
// Use the Interval_Begin_Dtm to Put the Doses in the Correct Object.
// Find the Dose_Tracker_Object
// The Medication Name, Date Intervals, and UOM must be the same
// and the Routes must match or both be NULL.
found_sum_tracker := sum_tracker_list where
((sum_tracker_list.route = FF.route or
(sum_tracker_list.route is null) and (FF.route is null))
and sum_tracker_list.uom = FF.uom
and sum_tracker_list.med_name = FF.med_name
and sum_tracker_list.interval_begin_dtm = FF.interval_begin_dtm);
if exist found_sum_tracker
then
// Use the Existing Sum_Tracker_Object
sum_instance := last (found_sum_tracker);
else
//Otherwise Create a new Sum_Tracker_Object
sum_instance := new Sum_Tracker_Object;
//Add to the List of objects
sum_tracker_list := sum_tracker_list, sum_instance;
//Populate the new Sum_Tracker_Object with basic information
sum_instance.med_order_type := FF.med_order_type;
sum_instance.med_name := FF.med_name;
sum_instance.interval_begin_dtm := FF.interval_begin_dtm;
sum_instance.interval_end_dtm := FF.interval_end_dtm;
sum_instance.uom := FF.uom;
sum_instance.route := FF.route;
sum_instance.total_dose_low := 0;
sum_instance.total_dose_high := 0;
sum_instance.start_date := FF.start_date;
endif; //if exist found_sum_tracker
if FF.num_doses_in_24hrs = FF.num_doses
then
sum_instance.has_full_24hrs_doses := true;
else
sum_instance.has_full_24hrs_doses := false;
endif;
if FF = last (dose_tracker_list)
then
sum_instance.is_last_24hr_interval := true;
else
sum_instance.is_last_24hr_interval := false;
endif;
//Populate Sum_Tracker with Doses
sum_instance.total_dose_low := sum_instance.total_dose_low + FF.total_dose_low ;
sum_instance.total_dose_high := sum_instance.total_dose_high + FF.total_dose_high ;
enddo; //for FF
//------------------------------
// Calculate Total Daily Dose
//------------------------------
for GG in (1 seqto count sum_tracker_list) do
// Find the Total_Tracker_Object
// The Med Order Type, Medication Name, UOM, Dose Low, and Dose High must match
// Route must match or both be NULL
found_total_tracker := total_tracker_list where
(total_tracker_list.med_order_type = sum_tracker_list[GG].med_order_type
and total_tracker_list.med_name = sum_tracker_list[GG].med_name
and (total_tracker_list.route = sum_tracker_list[GG].route or
((total_tracker_list.route is NULL) and (sum_tracker_list[GG].route is NULL)))
and total_tracker_list.uom = sum_tracker_list[GG].uom
and total_tracker_list.total_dose_low = sum_tracker_list[GG].total_dose_low
and total_tracker_list.total_dose_high = sum_tracker_list[GG].total_dose_high);
if exist found_total_tracker
then
//Use existing object
total_instance := last found_total_tracker;
//Add DTM to the list
if exist total_instance.interval_begin_dtm_list
then
total_instance.interval_begin_dtm_list :=
total_instance.interval_begin_dtm_list,
sum_tracker_list[GG].interval_begin_dtm;
endif; //if exist total_instance.interval_begin_dtm_list
else
//Create a new object
total_instance := new Total_Tracker_Object;
//Add the total_instance to the list
total_tracker_list := total_tracker_list, total_instance;
//Populate Total_Tracker_Object
total_instance.dose_range_check_method := "Summed Doses";
total_instance.med_order_type := sum_tracker_list[GG].med_order_type;
total_instance.med_name := sum_tracker_list[GG].med_name;
total_instance.route := sum_tracker_list[GG].route;
total_instance.total_dose_low := sum_tracker_list[GG].total_dose_low;
total_instance.total_dose_high := sum_tracker_list[GG].total_dose_high;
total_instance.uom := sum_tracker_list[GG].uom;
total_instance.dose_calc_method_number :=
sum_tracker_list[GG].dose_calc_method_number;
total_instance.interval_begin_dtm_list :=
sum_tracker_list[GG].interval_begin_dtm;
total_instance.is_last_24hr_interval := sum_tracker_list[GG].is_last_24hr_interval;
total_instance.has_full_24hrs_doses := sum_tracker_list[GG].has_full_24hrs_doses;
total_instance.start_date := sum_tracker_list[GG].start_date;
endif; //if exist found_total_tracker
// Set the Calc Method and Calc_Text
temp_object := first (med_data_list where
(med_data_list.med_order_type = total_instance.med_order_type
and med_data_list.order_med_name = total_instance.med_name
and (med_data_list.order_med_route = total_instance.route
or ((med_data_list.order_med_route is NULL)
and (total_instance.route is NULL)))));
total_instance.dose_calc_method_number := temp_object.calc_dose_method;
total_instance.calc_text := temp_object.calc_text;
enddo; //for GG
//-----------------------------
//Calculate Average Daily Dose
//-----------------------------
for HH in (1 seqto count total_tracker_list) do
// Find the Average_Tracker_Object
// The Med Order Type, Medication Name, and UOM must match
// Route must match or both be NULL
found_average_tracker := average_tracker_list where
(average_tracker_list.med_order_type = total_tracker_list[HH].med_order_type
and average_tracker_list.med_name = total_tracker_list[HH].med_name
and (average_tracker_list.route = total_tracker_list[HH].route
or ((average_tracker_list.route is NULL)
and (total_tracker_list[HH].route is NULL)))
and average_tracker_list.uom = total_tracker_list[HH].uom );
//Find the Total_Tracker_Objects
// The Med Order Type, Medication Name, and UOM must match
// Route must match or both be NULL
found_total_tracker := total_tracker_list where
(total_tracker_list.med_order_type = total_tracker_list[HH].med_order_type
and total_tracker_list.med_name = total_tracker_list[HH].med_name
and (total_tracker_list.route = total_tracker_list[HH].route
or ((total_tracker_list.route is NULL)
and (total_tracker_list[HH].route is NULL)))
and total_tracker_list.uom = total_tracker_list[HH].uom );
if found_total_tracker[1].med_order_type = "Complex Order"
and not exist found_average_tracker
then
//Copy Total_Tracker data to the Average_Tracker
//Do NOT calculate an Average for the Highs and Low Doses
for JJ in (1 seqto count found_total_tracker) do
//Create a new object
average_instance := new Average_Tracker_Object;
average_tracker_list := average_tracker_list, average_instance;
//Populate the data
average_instance.dose_range_check_method := "Summed Doses";
average_instance.med_order_type := found_total_tracker[JJ].med_order_type;
average_instance.med_name := found_total_tracker[JJ].med_name;
average_instance.route := found_total_tracker[JJ].route;
average_instance.uom := found_total_tracker[JJ].uom;
average_instance.dose_calc_method_number :=
found_total_tracker[JJ].dose_calc_method_number;
average_instance.calc_text := found_total_tracker[JJ].calc_text;
average_instance.interval_begin_dtm_list :=
found_total_tracker[JJ].interval_begin_dtm_list;
average_instance.average_dose_low := found_total_tracker[JJ].total_dose_low;
average_instance.average_dose_high := found_total_tracker[JJ].total_dose_high;
average_instance.is_last_24hr_interval := found_total_tracker[JJ].is_last_24hr_interval;
average_instance.has_full_24hrs_doses := found_total_tracker[JJ].has_full_24hrs_doses;
average_instance.start_date := found_total_tracker[JJ].start_date;
enddo; //for JJ
elseif found_total_tracker[1].med_order_type is in ( "Regular", "IV-Additive")
and not exist found_average_tracker
then
//Calculate an Average for the Highs and Low Doses
//Create a new object
average_instance := new Average_Tracker_Object;
average_tracker_list := average_tracker_list, average_instance;
//Populate the data
average_instance.dose_range_check_method := "Summed Doses" ;
average_instance.med_order_type := last found_total_tracker.med_order_type;
average_instance.med_name := last found_total_tracker.med_name;
average_instance.route := last found_total_tracker.route;
average_instance.uom := last found_total_tracker.uom;
average_instance.dose_calc_method_number :=
last found_total_tracker.dose_calc_method_number;
average_instance.calc_text := last found_total_tracker.calc_text;
average_instance.start_date := last found_total_tracker.start_date;
//Calculate Average Daily for Low and High Doses
temp_low := 0;
temp_high := 0;
temp_min_dtm := null;
temp_max_dtm := null;
for KK in (1 seqto count found_total_tracker) do
temp_number_of_dates := count found_total_tracker[KK].interval_begin_dtm_list;
temp_low := temp_low
+ (found_total_tracker[KK].total_dose_low * temp_number_of_dates);
temp_high := temp_high
+ (found_total_tracker[KK].total_dose_high * temp_number_of_dates);
// Get the Min and Max DTM from the CURRENT Total Tracker
temp_min_dtm_in_tracker := min (found_total_tracker[KK].interval_begin_dtm_list);
temp_max_dtm_in_tracker := max (found_total_tracker[KK].interval_begin_dtm_list);
// Find the Minimum Dtm for the group of FOUND Total Trackers
if not exist temp_min_dtm
then temp_min_dtm := temp_min_dtm_in_tracker;
elseif exist temp_min_dtm
and temp_min_dtm_in_tracker < temp_min_dtm
then temp_min_dtm := temp_min_dtm_in_tracker;
endif;
// Find the Maximum Dtm for the group of FOUND Total Trackers
if not exist temp_max_dtm
then temp_max_dtm := temp_max_dtm_in_tracker;
elseif exist temp_max_dtm
and temp_max_dtm_in_tracker > temp_max_dtm
then temp_max_dtm := temp_max_dtm_in_tracker;
endif; //if not exist temp_max_dtm
enddo; //for KK
//Store the entire list of dates from the found_total_tracker, not just the last one
for LL in (1 seqto count found_total_tracker) do
if exist average_instance.interval_begin_dtm_list
then
average_instance.interval_begin_dtm_list :=
average_instance.interval_begin_dtm_list,
found_total_tracker[LL].interval_begin_dtm_list;
else
average_instance.interval_begin_dtm_list :=
found_total_tracker[LL].interval_begin_dtm_list;
endif; //if LL
enddo; //for LL
//Calculate the Total Number of Days the Patient receives Medications
// Since we are using the interval_begin_dtm_list
// which are the beginning of the 24-hour interval,
// we need to adjust the number of days by 24 hours
// since the patient can receive medication until
// the end of the 24-hour interval
num_days_rounded_up := Truncate ((temp_max_dtm - temp_min_dtm + 24 hours )/ 1 day);
//Calculate the Low and High Doses by dividing the doses with the number of days
//AND Store the Doses
temp_average_dose_low := temp_low / num_days_rounded_up;
temp_average_dose_high := temp_high / num_days_rounded_up;
// Find the Single Dose for the current Average_Tracker.
found_med_data := med_data_list where
(med_data_list.med_order_type = average_instance.med_order_type
and med_data_list.order_med_name = average_instance.med_name
and (med_data_list.order_med_route = average_instance.route
or ((med_data_list.order_med_route is NULL)
and (average_instance.route is NULL)))
and med_data_list.order_med_units = average_instance.uom );
// Store Doses - no rounding for average dose for proper daily dose checking
average_instance.average_dose_high := temp_average_dose_high;
average_instance.average_dose_low := temp_average_dose_low;
endif; //if found_total_tracker[1].med_order_type = "Complex Order"
enddo; //for HH
endif; //if med_data.med_order_type is in ("Regular", "IV-Additive")
total_tracker_count := count total_tracker_list;
total_tracker_list.sort_number := 1 seqto total_tracker_count;
average_tracker_count := count average_tracker_list;
average_tracker_list.sort_number := 1 seqto average_tracker_count;
//Always Conclude True;
Conclude True;
;;
action:
return total_tracker_list, average_tracker_list;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,127 @@
maintenance:
title: Trim Excess Decimals from Numbers;;
mlmname: STD_FUNC_DOSAGE_TRIM;;
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: Trims excess decimals from number(s) by rounding them to a specific
number of decimals, based on a template number.
;;
explanation: A list of numbers is rounded and trimmed to 1 decimal place more
than the template number with the most decimal places.
Example: the template number has 2 decimal places (e.g. 450.25),
then the list of numbers is rounded to 3 decimals (e.g. 20.333333, 50.7777777)
and becomes (20.333, 50.778).
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
(template_numbers_list, // A list of numbers that is used as a template for trimming decimals
trim_numbers_list // One or more numbers that need to be trimmed.
) := ARGUMENT;
standard_libs := mlm {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
using namespace "System";
// Set to true if logging is needed.
log_execution_info := false;
;;
evoke:
;;
logic:
if template_numbers_list is number
then
template_numbers_list := , template_numbers_list;
endif;
if all (template_numbers_list is number)
and all (trim_numbers_list is number)
then
// Initalize Variables
rounded_trim_numbers_list := ();
max_decimals := 0;
for temp_num in template_numbers_list do
// Convert number to Characters and extract them into a list
initial_string := "" || temp_num;
// Check for Scientific Notation
// and convert to all digits
if initial_string matches pattern "%E%"
then
initial_string := temp_num formatted with "%f";
endif; // if "E"
net_string := initial_string as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
decimal_index := call net_string.IndexOf with (".");
if (decimal_index >= 0)
then
number_of_decimals := LENGTH initial_string - (decimal_index + 1);
else
number_of_decimals := 0;
endif;
if (number_of_decimals > max_decimals)
then
max_decimals := number_of_decimals;
longest_num := temp_num;
endif;
enddo;
// Adjust by one decimal
max_decimals := max_decimals + 1;
// Create the string template for format the number
// Template example: "%.3f"
string_template := "%." || max_decimals ||"f";
// Create a list of numbers with the required number of decimals
for temp_num in trim_numbers_list do
// Check that a number is being formatted.
// Otherwise formatting something that is not a number
// will throw an execution error.
// Return a NULL if we do not have a number.
if temp_num is number
then rounded_num := (temp_num formatted with string_template) AS NUMBER ;
else rounded_num := null;
endif;
rounded_trim_numbers_list := rounded_trim_numbers_list, rounded_num;
enddo; //for temp_num
endif; //if template_number is number
Conclude True;
;;
action:
Return rounded_trim_numbers_list;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,105 @@
maintenance:
title: Trim Excess Decimals from Numbers;;
mlmname: STD_FUNC_DOSAGE_TRIM_ADJUSTED;;
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: Applies conversion factor to the list of numbers, and if the conversion factor
is small and introduces extra significant digits, it shifts the template number to
add extra significant digits
;;
explanation: A list of numbers is rounded and trimmed to 1 decimal place more
than the template number with the most decimal places and conversion factor.
Example: the template number has 2 decimal places (e.g. 450.25),
then the list of numbers is rounded to 3 decimals (e.g. 20.333333, 50.7777777)
and becomes (20.333, 50.778).
The conversion factor is applied to the list of numbers.
If the conversion factor introduces extra significant digit, it adds the significant digits
to the template number.
Example: the template number has 2 decimal places (e.g. 450.25), and the conversion factor is 0.1
then the list of numbers is rounded to 3 decimals (e.g. 2.0333333, 5.07777777)
and becomes (2.0333, 5.0778).
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
knowledge:
type: data-driven;;
data:
(template_numbers_list, // A list of numbers that a used as a template for trimming decimals (based on the one with the most decimals)
conversion_factor, // A number to convert the trim_numbers_list
trim_numbers_list // One or more numbers that need to be trimmed.
) := ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
func_dosage_trim := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_trim{{{SINGLE-QUOTE}}};
;;
evoke:
;;
logic:
if template_numbers_list is number
then
template_numbers_list := , template_numbers_list;
endif;
if all (template_numbers_list is number)
and conversion_factor is number
and all (trim_numbers_list is number)
then
divisor := 1;
// See how many factors of 10 we can find
// Every divisor of 10 shifts the number by one decimal place
// 0.1 => 1/0.1 = 10 => a factor of 10
// 0.05 => 1/0.05 = 20 => shifts the digits by a factor of 10
// 0.01 => 1/0.01 => 100 => shifts digits by a factor of 100
if (conversion_factor >0) and (conversion_factor < 1)
then
val := 1/conversion_factor;
while (val > 10)
do
divisor := divisor * 10;
val := val/10;
enddo;
endif;
// Adjust the significant digits of the template number based on the conversion factor
shifted_template_numbers_list := template_numbers_list / divisor;
converted_trim_numbers_list := trim_numbers_list * conversion_factor;
(rounded_trim_numbers_list) := call func_dosage_trim with (shifted_template_numbers_list, converted_trim_numbers_list);
endif; //if template_number is number
Conclude True;
;;
action:
Return rounded_trim_numbers_list;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,394 @@
maintenance:
title: Generate XML parameters to get dose range data;;
mlmname: STD_Func_Dosage_XML_Params;;
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: Generate XML input parameters for getting dose range data from
item-catalog or multum.
;;
explanation: This MLM assists the STD_Dosage MLM with dose-range checking.
It formats the input XML for the SCMGetItemCatDosageRangePr and
SCMMultumGrouperDosageRangePR.
;;
keywords: dosage range, multum, item catalog, order, prescription
;;
knowledge:
type: data-driven;;
data:
// Set to true if logging is needed.
log_execution_info := false;
(
// Common medication data
drc_grouper_id,
multum_dnum,
multum_mmdc,
order_med_route,
order_med_route_id,
is_generic_route,
order_med_significant_date,
order_med_units,
order_med_uom_id,
multum_freq_id,
med_order_type,
is_order,
// Patient data
patient_birthday_info_on_order,
has_valid_birthdate,
wt_kg,
BSA_number_rounded,
intl_patient_gender,
// Item Catalog only
for_item_catalog,
catalog_item_obj,
// Multum only
has_liver_disease_bit,
dialysis_type_str,
serum_creatinine,
// Flags and constants
alert_if_missing_flags,
patient_info,
core_uom_const
):= ARGUMENT;
Name_Value_Object := OBJECT [name, val];
// XML parameter
indent := " ";
indent1 := indent;
indent2 := indent || indent;
newline := "\n";
// Set the medication parameters
med_info_list := (
(new Name_Value_Object with "GrouperID", drc_grouper_id),
(new Name_Value_Object with "DNum", multum_dnum),
(new Name_Value_Object with "MMDC", multum_mmdc),
(new Name_Value_Object with "UOMID", order_med_uom_id),
(new Name_Value_Object with "RouteID", order_med_route_id),
(new Name_Value_Object with "FrequencyID", multum_freq_id)
);
if for_item_catalog and exists catalog_item_obj then
catalog_med_info_list := (
(new Name_Value_Object with "CatalogMasterItemGUID", catalog_item_obj.GUID),
(new Name_Value_Object with "UOM", order_med_units),
(new Name_Value_Object with "Route", order_med_route)
);
med_info_list := med_info_list, catalog_med_info_list;
endif;
med_params_xml :=
indent1 ||"<Medication " || newline;
for med_item in med_info_list
do
if exists med_item.val
then
med_params_xml := med_params_xml ||
indent2 || med_item.name || "={{{SINGLE-QUOTE}}}" || XMLEX(med_item.val) || "{{{SINGLE-QUOTE}}}" || newline;
endif;
enddo;
med_params_xml := med_params_xml ||
indent1 ||"/>" || newline;
// Patient Info
age_params_xml := "";
if has_valid_birthdate
then
age_unit_list := (
(new Name_Value_Object with core_uom_const.day_string, patient_birthday_info_on_order.age_day_value),
(new Name_Value_Object with core_uom_const.week_string, patient_birthday_info_on_order.age_week_value),
(new Name_Value_Object with core_uom_const.month_string, patient_birthday_info_on_order.age_month_value),
(new Name_Value_Object with core_uom_const.year_string, patient_birthday_info_on_order.age_year_value),
(new Name_Value_Object with core_uom_const.hour_string, patient_birthday_info_on_order.age_hour_value)
);
//[New born birth-time missing]: when new born < 4 days is missing birth time and >= 1 day, add AgeMin value to it
age_unit_min_list := ();
if patient_birthday_info_on_order.is_estimated_birthday = true and patient_birthday_info_on_order.age_day_value >= 1.0
then
age_unit_min_list := (
(new Name_Value_Object with core_uom_const.day_string, patient_birthday_info_on_order.age_day_min_value),
(new Name_Value_Object with core_uom_const.week_string, patient_birthday_info_on_order.age_week_min_value),
(new Name_Value_Object with core_uom_const.month_string, patient_birthday_info_on_order.age_month_min_value),
(new Name_Value_Object with core_uom_const.year_string, patient_birthday_info_on_order.age_year_min_value),
(new Name_Value_Object with core_uom_const.hour_string, patient_birthday_info_on_order.age_hour_min_value)
);
endif;
for unit_item_index in (1 seqto count age_unit_list)
do
// age_unit_list and the age_unit_min_list are in the same unit sequence
// day, week, month, year, hour
unit_item := age_unit_list[unit_item_index];
unit_min_item := age_unit_min_list[unit_item_index];
age_params_xml := age_params_xml ||
indent2 || "<Item type={{{SINGLE-QUOTE}}}Age{{{SINGLE-QUOTE}}} "
|| "unit={{{SINGLE-QUOTE}}}" || XMLEX(unit_item.name) || "{{{SINGLE-QUOTE}}} "
|| "val={{{SINGLE-QUOTE}}}" || XMLEX(unit_item.val formatted with "%.16f") || "{{{SINGLE-QUOTE}}} ";
if exists unit_min_item
then
//[New born birth-time missing]: item will be lik:
// <Item type={{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}Age{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}} unit={{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}day{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}} val={{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}2.4270833333333335{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}} min_val={{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}1.4277777777777778{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}} />
age_params_xml := age_params_xml || "min_val={{{SINGLE-QUOTE}}}" || XMLEX(unit_min_item.val formatted with "%.16f") || "{{{SINGLE-QUOTE}}} ";
endif;
age_params_xml := age_params_xml || "/>" || newline;
enddo;
endif;
bsa_params_xml := "";
if BSA_number_rounded is number and BSA_number_rounded > 0
then
bsa_params_xml :=
indent2 || "<Item type={{{SINGLE-QUOTE}}}BSA{{{SINGLE-QUOTE}}} unit={{{SINGLE-QUOTE}}}M2{{{SINGLE-QUOTE}}} val={{{SINGLE-QUOTE}}}" || XMLEX(BSA_number_rounded) || "{{{SINGLE-QUOTE}}} />" || newline;
endif;
weight_params_xml := "";
if wt_kg is number and wt_kg > 0
then
// Convert patient weight to grams
wt_gm:= wt_kg * 1000;
weight_lb_value := wt_gm/453.6; // pound
weight_ounce_value := wt_gm/28.35; // ounce
wt_unit_list:= (
(new Name_Value_Object with core_uom_const.gm_string, wt_gm),
(new Name_Value_Object with core_uom_const.ounce_string, weight_ounce_value),
(new Name_Value_Object with core_uom_const.lb_string, weight_lb_value),
(new Name_Value_Object with core_uom_const.kg_string, wt_kg)
);
for unit_item in wt_unit_list
do
weight_params_xml := weight_params_xml ||
indent2 || "<Item type={{{SINGLE-QUOTE}}}Weight{{{SINGLE-QUOTE}}} "
|| "unit={{{SINGLE-QUOTE}}}" || XMLEX(unit_item.name) || "{{{SINGLE-QUOTE}}} "
|| "val={{{SINGLE-QUOTE}}}" || XMLEX(unit_item.val) || "{{{SINGLE-QUOTE}}} "
|| "/>" || newline;
enddo;
endif;
gender_params_xml := "";
if exists intl_patient_gender
then
gender_params_xml :=
indent1 || "<Gender val={{{SINGLE-QUOTE}}}" || XMLEX(intl_patient_gender) || "{{{SINGLE-QUOTE}}}/>" || newline;
endif;
//[New born birth-time missing]: add MissingBabyBirthTime
birth_time_missing_xml := "";
if patient_birthday_info_on_order.is_estimated_birthday = true
then
if patient_birthday_info_on_order.age_day_value >= 1.0
then
missing_baby_birthTime_value := 1;
else
missing_baby_birthTime_value := 2;
endif;
birth_time_missing_xml :=
indent1 || "<MissingBabyBirthTime val={{{SINGLE-QUOTE}}}" || XMLEX(missing_baby_birthTime_value) || "{{{SINGLE-QUOTE}}}/>" || newline;
endif;
liver_params_xml := "";
dialysis_params_xml := "";
creatinine_params_xml := "";
if not for_item_catalog
then
if exists has_liver_disease_bit
then
liver_params_xml :=
indent2 || "<LiverDisease val={{{SINGLE-QUOTE}}}" || XMLEX(has_liver_disease_bit) || "{{{SINGLE-QUOTE}}}/>" || newline;
endif;
if exists dialysis_type_str
then
dialysis_params_xml :=
indent2 || "<DialysisType val={{{SINGLE-QUOTE}}}" || XMLEX(dialysis_type_str) || "{{{SINGLE-QUOTE}}}/>" || newline;
endif;
if exists serum_creatinine
then
creatinine_params_xml :=
indent2 || "<SerumCreatinine val={{{SINGLE-QUOTE}}}" || XMLEX(serum_creatinine) || "{{{SINGLE-QUOTE}}}/>" || newline;
endif;
endif;
patient_params_xml :=
indent1 ||"<Patient>" || newline ||
age_params_xml ||
bsa_params_xml ||
weight_params_xml ||
gender_params_xml ||
birth_time_missing_xml ||
liver_params_xml ||
dialysis_params_xml ||
creatinine_params_xml ||
indent1 ||"</Patient>" || newline;
get_dosage_for_missing_weight :=
( alert_if_missing_flags.patient_weight
and ( patient_info.Weight.is_missing or patient_info.Weight.not_current )
);
get_dosage_for_missing_BSA := get_dosage_for_missing_weight
or
( alert_if_missing_flags.patient_height
and ( patient_info.Height.is_missing or patient_info.Height.not_current )
);
is_gender_missing := Patient_info.Gender.is_missing or intl_patient_gender in ("U", "O");
get_dosage_for_missing_gender :=
( ( alert_if_missing_flags.patient_gender and is_gender_missing )
or ( alert_if_missing_flags.unmapped_gender and Patient_info.Gender.is_unmapped )
);
if (is_order)
then
missing_route := order_med_route is null;
missing_uom := order_med_units is null;
else
missing_route := order_med_route is null AND order_med_route_id is null;
missing_uom := order_med_units is null AND order_med_uom_id is null;
endif;
if (for_item_catalog)
then
// For item catalog, there is no "unmapped" concept
unmapped_route := false;
unmapped_uom := false;
else
unmapped_route := (not missing_route) and order_med_route_id is null;
unmapped_uom := (not missing_uom) and order_med_uom_id is null;
endif;
get_dosage_for_missing_route :=
( ( alert_if_missing_flags.route and missing_route )
or ( alert_if_missing_flags.unmapped_route and unmapped_route)
);
get_dosage_for_missing_uom :=
( ( alert_if_missing_flags.uom and missing_uom)
or ( alert_if_missing_flags.unmapped_uom and unmapped_uom )
);
get_dosage_for_missing_grouper :=
( alert_if_missing_flags.cannot_check_DNUM_Rx_to_Multum
and drc_grouper_id is null
and not is_order
and not for_item_catalog
);
// - Return other routes if the current route is unrecognized route
// and the cannot check unrecognized route flag is on
// - Return other routes if the current route is not an unrecognized route
// and the inapplicable route flag is on
get_dosage_for_route_match_not_found :=
( alert_if_missing_flags.cannot_check_generic_route
and is_generic_route
)
OR
( alert_if_missing_flags.inapplicable_route
and not is_generic_route
and not for_item_catalog
);
get_dosage_for_uom_conversion := alert_if_missing_flags.uom_conversion;
if for_item_catalog and not is_order
then
get_dosage_for_ic_dnum := alert_if_missing_flags.cannot_check_Rx_to_IC;
endif;
if not for_item_catalog and is_order
then
get_dosage_for_any_freq := (med_order_type = "Complex Order");
endif;
if for_item_catalog
then
get_dosage_for_missing_age := alert_if_missing_flags.patient_age and (not has_valid_birthdate);
endif;
missing_data_flags_list := (
(new Name_Value_Object with "ReturnDataForMissingWeight", get_dosage_for_missing_weight),
(new Name_Value_Object with "ReturnDataForMissingBSA", get_dosage_for_missing_BSA),
(new Name_Value_Object with "ReturnDataForMissingGender", get_dosage_for_missing_gender),
(new Name_Value_Object with "ReturnDataForMissingGrouperBasedOnDnum", get_dosage_for_missing_grouper),
(new Name_Value_Object with "ReturnDataForMissingRoute", get_dosage_for_missing_route),
(new Name_Value_Object with "ReturnDataForRouteMatchNotFound", get_dosage_for_route_match_not_found),
(new Name_Value_Object with "ReturnDataForMissingUOM", get_dosage_for_missing_uom),
(new Name_Value_Object with "ReturnDataForUomConversionIssue", get_dosage_for_uom_conversion),
(new Name_Value_Object with "ReturnDataByDnumWhenNoMatchFound", get_dosage_for_ic_dnum),
(new Name_Value_Object with "ReturnDailyDoseForAnyFreq", get_dosage_for_any_freq),
(new Name_Value_Object with "ReturnDataForMissingAge", get_dosage_for_missing_age)
);
missing_data_flag_name_val_xml := "";
for unit_item in missing_data_flags_list
do
if unit_item.val then bit_val := 1; else bit_val := 0; endif;
missing_data_flag_name_val_xml := missing_data_flag_name_val_xml ||
indent2 || unit_item.name || "={{{SINGLE-QUOTE}}}" || XMLEX(bit_val) || "{{{SINGLE-QUOTE}}}" || newline;
enddo;
missing_data_flags_xml :=
indent1 || "<MissingData " || newline ||
missing_data_flag_name_val_xml || newline ||
indent1 || "/>" || newline;
input_param_xml := "\n<ROOT>\n" ||
med_params_xml ||
patient_params_xml ||
missing_data_flags_xml ||
"</ROOT>" || newline;
debug_str_input_param_xml := SQL(input_param_xml);
;;
priority: 50
;;
evoke:
;;
logic:
/* Always conclude true to return variables to calling MLM */
CONCLUDE TRUE;
;;
action:
return (input_param_xml, missing_route, unmapped_route, missing_uom, unmapped_uom, uom_conversion_issue);
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,207 @@
maintenance:
title: Process Actions on Alerts for Drug Interactions;;
mlmname: STD_FUNC_DRUG_INTERACTION_ACTIONS;;
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: This MLM is used by the Drug Interaction checking MLMs to call another
MLM to create the AlertAction object and to populate them with data.
;;
explanation: This MLM will do the following:
1. Call the STD_Func_Create_Alert_Action_Object MLM to create an instance
of the AlertAction object.
2. Process the data that was sent to it and populate each AlertAction object.
3. Create a list of the objects and return it to the call program.
;;
keywords:
;;
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;
/********************************************************************************/
(aoa_evoking_drug_list, //Drugs that have interactions
evoking_combined_med_type_list, //Evoking Data Values for a Regular or IV additives
aoa_interaction_severity_list, //Interacting Severities
aoa_interacting_drug_list, //Drugs that interact with the evoking drugs
aoa_concomit_order_name_list, //All containing orders
aoa_concomit_order_guid_list, //All orders including additives
aoa_concomit_order_catalog_item_guid_list,
aoa_concomit_item_type_list, // Regular or IVAdditive
aoa_concomit_item_status_list, // Evoking, Unsubmitted, or Existing
aoa_concomit_is_suspended_list,
evoking_catalog_item_guid,
evoking_order_guid,
evoking_order_name)
:= Argument;
// Declare the MLM that can be called
func_create_alert_action_object := MLM {{{SINGLE-QUOTE}}}STD_Func_Create_Alert_Action_Object{{{SINGLE-QUOTE}}};
// Declare string constants
Additive_string := "Additive";
DC_Cancel_string := "DC-Cancel";
Delete_string := "Delete";
Evoking_string := "Current Order";
Existing_string := "Existing";
IVSolution_string := "IVSolution";
Modify_string := "Modify";
Regular_string := "Regular";
Suspend_string := "Suspend";
Unsubmitted_string := "Unsubmitted";
Status_Unsubmitted_string := "Unsubmitted Order";
Status_Unapprove_string := "Unapproved";
;;
evoke:
;;
logic:
//-----------------------------------------------------
// Process The Lists to Extract Data To Create Actions
//-----------------------------------------------------
// Initialize
alert_action_list := ();
// Loop through the list of interacting drugs
action_index_list := 1 seqto count (aoa_evoking_drug_list);
for AA in action_index_list do
// Get the drug-drug interaction pair and its severity
aoa_evoking_drug := aoa_evoking_drug_list[AA];
aoa_interacting_drug := aoa_interacting_drug_list[AA];
aoa_interaction_severity := aoa_interaction_severity_list[AA];
aoa_evoking_med_type := evoking_combined_med_type_list[AA];
//--------------------//
// Create the Actions //
//--------------------//
// Loop through the sublist of drugs //
sub_index_list := 1 seqto count aoa_concomit_order_guid_list;
for BB in sub_index_list do
aoa_order_guid := aoa_concomit_order_guid_list[BB];
aoa_catalog_item_guid := aoa_concomit_order_catalog_item_guid_list[BB];
aoa_med_type := aoa_concomit_item_type_list[BB];
aoa_status_type := aoa_concomit_item_status_list[BB];
aoa_is_suspended := aoa_concomit_is_suspended_list[BB];
aoa_action_item_name := aoa_concomit_order_name_list[BB];
// Only process EXISTING and UNSUBMITTED Orders, NOT EVOKING
if aoa_status_type <> Evoking_string
then
//---------------------------------------------------//
// Create the ShortMessage for the Actions on Alerts //
//---------------------------------------------------//
//Add the front part of the message.
If aoa_evoking_med_type = Regular_string
then
short_message := "The current order for "
|| aoa_evoking_drug ||" has a drug interaction with ";
elseif aoa_evoking_med_type = IVSolution_string
then
short_message := "The current order for "
|| aoa_evoking_drug ||" has a drug interaction with ";
elseif aoa_evoking_med_type = Additive_string
then
short_message := "The current order has an IV-additive, "
|| aoa_evoking_drug ||", that has a drug interaction with ";
endif; //aoa_evoking_med_type
//Add the middle part of the message.
if aoa_med_type = Regular_string
then short_message := short_message || aoa_interacting_drug ;
elseif aoa_med_type = IVSolution_string
then short_message := short_message || aoa_interacting_drug ;
elseif aoa_med_type = Additive_string
then short_message := short_message || "the IV-additive, "
|| aoa_interacting_drug ;
endif; //if aoa_med_type
//Add the back part of the message.
short_message := short_message
|| ". The severity is: "|| aoa_interaction_severity ||".";
//----------------------------------------------//
// Create the Alert Action Objects and Populate //
//----------------------------------------------//
// Create the Modify, Delete, DC-Cancel, and Suspend actions
// and Apply the following business rules
// 1. Any order any be modified.
// 2. Only Unsubmitted orders can be deleted
// 3. Only Existing orders can be dc-cancelled
// 4. Do not suspend an order, if the order is already suspended.
// Create the correct action_event_list for EXISTING and
// UNSUBMITTED orders
if (aoa_status_type = Status_Unsubmitted_string or aoa_status_type = Status_Unapprove_string)
then
aoa_action_item_status := Unsubmitted_string;
action_event_list := Delete_string, Modify_string;
else // existing
aoa_action_item_status := Existing_string;
//Do NOT suspend an order that is already suspended.
if aoa_is_suspended
then action_event_list := DC_Cancel_string, Modify_string;
else action_event_list := DC_Cancel_string, Modify_string,
Suspend_string;
endif; //if is_suspended
endif;
for aoa_action_event in action_event_list do
/* Create the Alert Action object and partially populate it */
instance := call func_create_alert_action_object
with "CV3Order", "CV3Order";
/* Finish populating the Alert Action object */
instance.EvokingEnterpriseItemID := (evoking_catalog_item_guid as string);
instance.EvokingObjectID := (evoking_order_guid as string);
instance.EvokingObjectName := evoking_order_name;
instance.ActionItemStatus := aoa_action_item_status;
instance.ActionEvent := aoa_action_event;
instance.ActionItemID := (aoa_order_guid as string);
instance.ActionItemName := aoa_action_item_name;
instance.ActionEnterpriseItemID := (aoa_catalog_item_guid as string);
instance.mlmname := "STD_Drug_Interaction";
instance.ShortMessage := short_message;
// Save the Alert Action objects to a List
alert_action_list := alert_action_list, instance;
enddo; //for aoa_action_event
endif; //if aoa_status_type
enddo; //for BB
enddo; //for AA
// Always Conclude True to Return objects
Conclude true;
;;
action:
return alert_action_list;
;;
end:

View File

@@ -0,0 +1,142 @@
maintenance:
title: Set the Actions for the Duplicate Order Alert;;
mlmname: STD_FUNC_DUP_ACTIONS;;
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: This MLM is used by the Duplicate Order checking MLMs to call another
MLM to create the AlertAction object and to populate them with data.
;;
explanation: This MLM will do the following:
1. Call the STD_Func_Create_Alert_Action_Object MLM to create an instance
of the AlertAction object.
2. Process the data that was sent to it and populate each AlertAction object.
3. Create a list of the objects and return it to the call program.
;;
keywords:
;;
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;
/********************************************************************************/
// Instantiate the variables associated with the Arguments
(evoking_object_guid, //GUID of the Evoking Object
matching_aoa_action_item_status_list, //List of STRINGs for the ActionItemStatus
matching_aoa_order_guid_list, //List of GUIDs for the ActionItemID
matching_aoa_order_name_list, //List of STRINGs for the ActionItemName
matching_aoa_master_guid_list, //List of GUIDs for ActionEnterpriseItemID
matching_aoa_short_message_list) //LIst of STRINGs for the ShortMessage
:= ARGUMENT;
// Declare the MLM that can be called by this MLM
func_create_alert_action_object := MLM {{{SINGLE-QUOTE}}}STD_Func_Create_Alert_Action_Object{{{SINGLE-QUOTE}}};
// Execute only when this MLM is called by the editor
if called_by_editor then
obj := read last
{ Order: THIS
WHERE GUID = evoking_object_guid };
EvokingObject := obj;
endif;
//---------------------------------------------
// Call the MLM to Create AlertAction Objects
//---------------------------------------------
// Get data from the Evoking Object
(evoking_catalog_item_guid,
evoking_object_name):= read last
{Order: OrderCatalogMasterItemGUID, Name
REFERENCING EvokingObject };
// Set Values for AlertAction data
evoking_object_table := "CV3Order";
action_item_table := "CV3Order";
mlm_name := "STD_DUPLICATE";
alert_action_object_list := ();
counter_list := 1 seqto (count matching_aoa_order_guid_list );
for JJ in counter_list do
// Process Through the Lists
// to Set Variables that will populate the AlertAction object
action_item_name := matching_aoa_order_name_list[JJ];
action_item_catalog_item_guid := matching_aoa_master_guid_list[JJ];
action_item_guid := matching_aoa_order_guid_list [JJ];
action_item_status := matching_aoa_action_item_status_list [JJ];
short_message := matching_aoa_short_message_list[JJ];
// Create the correct action_event_list for EXISTING and UNSUBMITTED orders
if action_item_status = "Existing"
then
//Do NOT suspend an order that is already suspended.
if is_suspended
then action_event_list := "DC-Cancel", "Modify";
else action_event_list := "DC-Cancel", "Modify", "Suspend";
endif; //if is_suspended
elseif action_item_status = "Unsubmitted"
then action_event_list := "Delete", "Modify";
endif;
for action_event in action_event_list do
// Create the AlertAction Object 2 Times
alert_action_obj:= call func_create_alert_action_object with
(evoking_object_table,
action_item_table) ;
// Set the Shared Values for a Single Instance of the AlertAction Object
alert_action_obj.EvokingEnterpriseItemID := evoking_catalog_item_guid;
alert_action_obj.EvokingObjectID := evoking_object_guid;
alert_action_obj.EvokingObjectName := evoking_object_name;
alert_action_obj.ActionEvent := action_event;
alert_action_obj.ActionItemStatus := action_item_status;
alert_action_obj.ActionItemID := action_item_guid;
alert_action_obj.ActionItemName := action_item_name;
alert_action_obj.ActionEnterpriseItemID := action_item_catalog_item_guid;
alert_action_obj.MLMName := mlm_name;
alert_action_obj.ShortMessage := short_message;
// Add AlertAction object to a list
alert_action_object_list := alert_action_object_list, alert_action_obj;
enddo; //for action_event
enddo; //for JJ
;;
evoke:
;;
logic:
conclude true;
;;
action:
return alert_action_object_list;
;;
end:

View File

@@ -0,0 +1,69 @@
maintenance:
title: Calculate Durations for Advanced Duplicate Order Checking MLM;;
mlmname: STD_FUNC_DUP_DURATION;;
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: Calculates the durations for the Advanced Duplicate-Order Checking MLM.
;;
explanation: Pass in a number and a string representation of time units, and
it will converted the information into an ARDEN Duration.
The expected spellings are:
"minutes", "hours", "days", "weeks", "months", and "hours".
;;
keywords: Duplicate Order; Duration; Calculation;
;;
knowledge:
type: data-driven;;
data:
(some_number,
time_unit) := ARGUMENT;
If time_unit = "minutes"
then answer:= some_number MINUTES;
elseif time_unit = "hours"
then answer:= some_number HOURS;
elseif time_unit = "days"
then answer:= some_number DAYS;
elseif time_unit = "weeks"
then answer:= some_number WEEKS;
elseif time_unit = "months"
then answer:= some_number MONTHS;
elseif time_unit = "years"
then answer:= some_number YEARS;
endif; /*if time_unit = */
;;
evoke:
;;
logic:
Conclude True;
;;
action:
Return (answer);
;;
end:

View File

@@ -0,0 +1,400 @@
maintenance:
title: Alert Messages for Advanced Duplicate Order Checking MLM;;
mlmname: STD_FUNC_DUP_MESSAGES;;
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: Selects the appropriate alert message for the Advanced Duplicate-Order
Checking MLM{{{SINGLE-QUOTE}}}s alerts and actions.
;;
explanation: The number of possible messages for the Advanced Duplicate-Order
Checking MLM is large. This MLM encapsulates the messages, so that all
changes to the messages can be done in one MLM.
;;
keywords: Duplicate Order; Alert; Message;
;;
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;
/********************************************************************************/
(order_name,
order_status_code,
order_without_specific_stop_date,
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,
matching_name_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_list,
matching_order_type_code_list,
matching_alternate_order_type_list,
matching_is_script_list,
community_resultedOrder_alert_text ):= ARGUMENT;
/* Gets the Full text description of the OrderStatusCode */
(status_code_list,
status_description_list):= read { "SELECT Code, Description FROM CV3OrderStatus WHERE Active = 1" };
;;
evoke:
;;
logic:
indent_string:= " ";
hyphen_string:= "-----";
// Substitutes the Status Description for the Status Code
order_status := first (status_description_list where (status_code_list = order_status_code ));
/*---------------------------------*/
/* Picks the correct alert message */
/*---------------------------------*/
//Initialize variables
long_alert_msg:= "";
short_message := "";
matching_short_message_list := ();
processing_list:= 1 seqto (count matching_name_list);
for k in processing_list do
// Gets duplicate order information
dup_order_found:= processing_list = k;
dup_order_name:= first (matching_name_list where dup_order_found);
dup_order_significant_date:= first (matching_significant_date_list where dup_order_found);
dup_order_entered_date := first (matching_entered_date_list where dup_order_found);
dup_order_requested_date := first(matching_requested_date_list where dup_order_found);
dup_order_stop_date:= first (matching_stop_date_list where dup_order_found);
dup_order_msg_type:= first (matching_msg_type_list where dup_order_found);
dup_order_msg_text:= first (matching_msg_text_list where dup_order_found);
dup_order_time_msg:= first (matching_time_msg_list where dup_order_found);
dup_order_class_msg:= first (matching_class_list where dup_order_found);
dup_order_summary:= first (matching_summary_list where dup_order_found);
dup_order_status_code:= first (matching_order_status_list where dup_order_found);
dup_order_type_code:= first (matching_order_type_code_list where dup_order_found);
dup_alternate_order_type := first(matching_alternate_order_type_list where dup_order_found);
dup_is_script := first(matching_is_script_list where dup_order_found);
// Format dates, removing milliseconds
if exist dup_order_significant_date then
dup_order_significant_date_formatted := dup_order_significant_date formatted with "%.4t";
else
dup_order_significant_date_formatted := "";
endif;
if exist dup_order_requested_date then
dup_order_requested_date_formatted := dup_order_requested_date formatted with "%.4t";
else
dup_order_requested_date_formatted := "";
endif;
if exist dup_order_entered_date then
dup_order_entered_date_formatted := dup_order_entered_date formatted with "%.4t";
else
dup_order_entered_date_formatted := "";
endif;
if exist dup_order_stop_date then
dup_order_stop_date_formatted := dup_order_stop_date formatted with "%.4t";
else
dup_order_stop_date_formatted := "";
endif;
// Eliminates NULLs from printing in the alert message
if dup_order_msg_text is null
then
dup_order_msg_text:= "";
endif;
if (dup_order_summary is not null AND dup_order_summary <> "")
then
dup_order_summary := hyphen_string || dup_order_summary;
else
dup_order_summary := "";
endif;
dup_order_status := "Unsubmitted";
if ( dup_order_status_code <> "Unsubmitted" )
then
// Substitutes the Status Description for the Status Code
dup_order_status := first (status_description_list where (status_code_list = dup_order_status_code ));
endif;
dup_date_prefix := "Start Date: ";
dup_date_str := dup_order_significant_date_formatted;
dup_status_suffix := "Order";
if (dup_alternate_order_type = 2)
then
if (dup_order_requested_date is NULL or dup_order_requested_date = "" or dup_order_requested_date = "null")
then
dup_date_prefix := "Entered Date: ";
endif;
if (dup_is_script)
then
dup_status_suffix := "Prescription";
else
dup_status_suffix := "Home Medication";
endif;
elseif (dup_alternate_order_type = 1)
then
dup_status_suffix := "";
elseif (dup_alternate_order_type = 3)
then
dup_order_name := dup_order_name || "{{+B}} (" || community_resultedOrder_alert_text || "){{-B}}";
endif;
// Creates the beginning of the long alert message
long_alert_msg:= long_alert_msg
|| dup_order_name || dup_order_summary || "\n"
|| dup_date_prefix || dup_date_str || "\n"
|| "Status: " || dup_order_status || " " || dup_status_suffix || "\n" ;
// Creates the rest of the long alert message
If dup_order_msg_type = exact_type
then
If dup_order_time_msg = exact_msg
then
short_message :=
"Warning duplicate order - " || dup_order_name
|| " has already been ordered for the same date and time. "
|| dup_order_msg_text
;
elseif dup_order_time_msg = performed_msg
then
if order_without_specific_stop_date
then
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " was performed " || dup_order_significant_date_formatted || ". "
|| dup_order_msg_text
;
else
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " was started " || dup_order_significant_date_formatted || ". "
|| dup_order_msg_text
;
endif; /* if order_without_specific_stop_date */
elseif dup_order_time_msg = scheduled_msg
then
if order_without_specific_stop_date
then
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " has already been scheduled on " || dup_order_significant_date_formatted
|| ". Consider cancelling one of the items. "
|| dup_order_msg_text
;
else
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " has already been scheduled to start on "
|| dup_order_significant_date_formatted
|| ". Consider cancelling one of the items. "
|| dup_order_msg_text
;
endif; /* if order_without_specific_stop_date */
else
short_message :=
"Error Message 1: Cannot find a message for an EXACT match."
;
endif; /* if dup_order_time_msg */
elseif dup_order_msg_type = subset_type
then
If dup_order_time_msg = exact_msg
then
short_message :=
"Warning duplicate order - Your current order for " || order_name
|| " includes the " || dup_order_name
|| " which has already been ordered for the same date and time. "
|| dup_order_msg_text
;
elseif dup_order_time_msg = performed_msg
then
short_message :=
"Warning - potential duplicate - Your current order for " || order_name
|| " includes the " || dup_order_name
|| " which was performed on " || dup_order_significant_date_formatted || ". "
|| dup_order_msg_text
;
elseif dup_order_time_msg = scheduled_msg
then
short_message :=
"Warning - potential duplicate - Your current order for " || order_name
|| " includes the " || dup_order_name
|| " which is already scheduled for " || dup_order_significant_date_formatted
|| ". Consider cancelling the " || dup_order_name || ". "
|| dup_order_msg_text
;
else
short_message :=
"Error Message 2: Cannot find a message for a SUBSET match."
;
endif; /* if dup_order_time_msg */
elseif dup_order_msg_type = superset_type
then
If dup_order_time_msg = exact_msg
then
short_message :=
"Warning duplicate order - Your current order for " || order_name
|| " is included in the " || dup_order_name
|| " which has already been ordered for the same date and time. "
|| dup_order_msg_text
;
elseif dup_order_time_msg = performed_msg
then
short_message :=
"Warning - potential duplicate - Your current order for " || order_name
|| " is included in the " || dup_order_name
|| " which has already been performed on "
|| dup_order_significant_date_formatted || ". "
|| dup_order_msg_text
;
elseif dup_order_time_msg = scheduled_msg
then
short_message :=
"Warning - potential duplicate - Your current order for " || order_name
|| " is included in the " || dup_order_name
|| " which is scheduled on " || dup_order_significant_date_formatted
|| ". Consider cancelling one of the items. "
|| dup_order_msg_text
;
else
short_message :=
"Error Message 3: Cannot find a message for a SUPERSET match."
;
endif; /* if dup_order_time_msg */
elseif dup_order_msg_type = partial_match_type
then
If dup_order_time_msg = exact_msg
then
short_message :=
"Warning - duplicate order - " || dup_order_name
|| " has already been ordered for the same date and time. Both "
|| order_name || " and " || dup_order_name
|| " have some items in common. "
|| dup_order_msg_text
;
elseif dup_order_time_msg = performed_msg
then
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " was already performed on " || dup_order_significant_date_formatted
|| ". Both " || order_name || " and " || dup_order_name
|| " have some items in common. "
|| dup_order_msg_text
;
elseif dup_order_time_msg = scheduled_msg
then
short_message :=
"Warning - potential duplicate - " || dup_order_name
|| " is already scheduled on " || dup_order_significant_date_formatted
|| ". Both " || order_name || " and " || dup_order_name
|| " have some items in common. "
|| dup_order_msg_text
;
else
short_message :=
"Error Message 4: Cannot find a message for a PARTIAL MATCH. "
;
endif; /* if dup_order_time_msg */
elseif dup_order_msg_type = same_order_type
then
//Avoid Printing NULL for dup_order_class_msg
if exist dup_order_class_msg
then print_dup_order_class_msg := ", " || dup_order_class_msg || ",";
else print_dup_order_class_msg := "";
endif;
short_message :=
"An order for " || dup_order_name
|| " is of the same type" || print_dup_order_class_msg
|| " as your current order for " || order_name || ". "
|| dup_order_msg_text
;
elseif dup_order_msg_type = conflict_type
then
short_message :=
"A scheduled order for " || dup_order_name
|| " conflicts with your current order for " || order_name
|| ". Either modify the stop date of your current order,"
|| " modify the date of the scheduled order, or cancel the future order. "
|| dup_order_msg_text
;
elseif dup_order_msg_type = possible_conflict_type
then
short_message :=
"An order for " || dup_order_name
|| " may conflict with your current order for " || order_name
|| ". Please review. "
|| dup_order_msg_text
;
elseif dup_order_msg_type = no_std_message_type
then
short_message :=
dup_order_msg_text
;
else
short_message :=
"Error Message 5: Undefined Message Type for the item ordered."
;
endif; /*if dup_order_msg_type */
//Add the Message to the lists
matching_short_message_list := matching_short_message_list, short_message;
long_alert_msg:= long_alert_msg ||short_message || "\n\n";
enddo; /* for k */
/* Always conclude true to return values to the calling program */
conclude true;
;;
action:
RETURN (order_status, long_alert_msg, matching_short_message_list );
;;
end:

File diff suppressed because it is too large Load Diff

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:

View File

@@ -0,0 +1,184 @@
maintenance:
title: Suppress Duplicate Order Checking Within an Order Set;;
mlmname: STD_FUNC_DUP_SUPPRESS_CHECKING;;
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: The purpose of this MLM is to determine which OrderSetGUID and OrderSubsetGUID
should be avoided so that the orders in the PARENT and/or CHILD Order Set
will NOT be retrieved. When an order is NOT retrieved, then duplicate order
checking is suppressed for that order.
;;
explanation:
RULE 1. If the IsDupCheckingSuppressed is TRUE in the PARENT ORDER SET
Then exclude ALL the orders in the CURRENT order SET
for both the PARENT & CHILD ORDER SETS.
Returns the Parent{{{SINGLE-QUOTE}}}s OrderSetGUID with a GUID,
but the Child{{{SINGLE-QUOTE}}}s OrderSubsetGUID is an empty list.
RULE 2. ELSE IF the IsDupCheckingSuppressed is FALSE or NULL in the PARENT ORDER SET
and the Order Set is NOT a Linked-Set (i.e. order set type <> 4)
and the IsDupCheckingSuppressed is TRUE in the CHILD ORDER SET
and EXCLUDE all the orders in the CURRENT order SET
for the CHILD ORDER SET ONLY.
Returns the Parent{{{SINGLE-QUOTE}}}s OrderSetGUID as an empty list,
and the Child{{{SINGLE-QUOTE}}}s OrderSubsetGUID has a GUID.
RULE 3. ELSE Do NOT EXCLUDE ANY Orders from Duplicate Order Checking.
Returns the Parent{{{SINGLE-QUOTE}}}s OrderSetGUID as an empty list
and the Child{{{SINGLE-QUOTE}}}s OrderSubsetGUID as an empty list.
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(order_name, //String--the name of the Evoking Order
order_guid ) //GUID--the GUID of the Evoking Order
:= ARGUMENT;
/***************Make Changes To Spelling And Flags In This Section***************/
/* Set to true if logging is needed.*/
log_execution_info := false;
/********************************************************************************/
/* This block executes only when this MLM is called by the editor */
if called_by_editor
then
// Set the EvokingObject to object that is used by the STD_Duplicate MLM
// so that the EvokingObjects are the same.
// This is NOT necessary to do during run-time because there is only
// one EvokingObject.
EvokingObject := read last
{ Order: THIS
WHERE Name = order_name
and GUID = order_guid
};
endif;
// Get Information from the Evoking Order
(o_order_name,
o_order_significant_dtm,
o_order_set_name,
o_order_set_type,
o_order_set_GUID,
o_order_subset_name,
o_order_subset_type,
o_order_subset_GUID,
o_order_set_obj,
o_order_subset_obj ) := read last
{Order: Name, SignificantDtm,
OrderSetName, OrderSetType, OrderSetGUID,
OrderSubsetName, OrderSubsetType, OrderSubsetGUID,
OrderSet,
OrderSubset
Referencing EvokingObject};
// Get Information from the Parent Order Set
if exist o_order_set_obj
then
(os_parent_order_set_name,
os_parent_start_dtm,
os_parent_GUID,
os_parent_order_catalog_set_obj ) := read last
{OrderSet: OrderSetName, StartDtm, GUID, OrderCatalogSet
Referencing o_order_set_obj };
(ocs_parent_name,
ocs_parent_GUID,
ocs_parent_type,
ocs_parent_is_dup_checking_suppressed,
ocs_parent_duplicate_policy_GUID ) := read last
{OrderCatalogSet: Name, GUID, Type,
IsDupCheckingSuppressed, DuplicatePolicyGUID
Referencing os_parent_order_catalog_set_obj };
endif; //if exist o_order_set_obj
// Get Information from the Child Order Set
if exist o_order_subset_obj
then
(os_child_order_set_name,
os_child_start_dtm,
os_child_GUID,
os_child_order_catalog_set_GUID,
os_child_order_catalog_set_obj ) := read last
{OrderSet: OrderSetName, StartDtm, GUID, OrderCatalogSetGUID, OrderCatalogSet
Referencing o_order_subset_obj };
(ocs_child_name,
ocs_child_GUID,
ocs_child_type,
ocs_child_is_dup_checking_suppressed,
ocs_child_duplicate_policy_GUID ) := read last
{OrderCatalogSet: Name, GUID, Type,
IsDupCheckingSuppressed, DuplicatePolicyGUID
Referencing os_child_order_catalog_set_obj };
endif; //if exist o_order_subset_obj
;;
evoke:
;;
logic:
//-----------------------------------
// RULE 1--Exclude ALL Orders in Set
//-----------------------------------
If ocs_parent_is_dup_checking_suppressed
then
avoid_parent_order_set_GUID := o_order_set_GUID;
avoid_child_order_set_GUID := ();
//------------------------------------------
//RULE 2--Exclude Orders in Child Order Set
//------------------------------------------
ElseIf
(NOT ocs_parent_is_dup_checking_suppressed
OR ocs_parent_is_dup_checking_suppressed is NULL)
AND o_order_set_type <> 4
AND ocs_child_is_dup_checking_suppressed
then
avoid_parent_order_set_GUID := ();
avoid_child_order_set_GUID := o_order_subset_GUID;
//----------------------------------
//RULE 3--Do NOT exclude ANY Orders
//----------------------------------
Else
avoid_parent_order_set_GUID := ();
avoid_child_order_set_GUID := ();
endif; // if ocs_parent_is_dup_checking_suppressed
//Alway Conclude True to Return an Answer
Conclude True;
;;
action:
RETURN
avoid_parent_order_set_GUID, //OrderSetGUID or an empty list
avoid_child_order_set_GUID; //OrderSubsetGUID or an empty list
;;
end:

View File

@@ -0,0 +1,110 @@
maintenance:
title: Community Data;;
mlmname: STD_FUNC_FILTER_VPO_GEN_DICTIONARY;;
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) 2014 - 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:
This functional MLM is called by other STD_Filter_VPO MLMs that generate
VPO filter criteria.
This MLM converts the field value list into two .Net dictionaries:
(1) Dictionary with field name as key, and exclude flag as value
(2) Dictionary with field name as key, and a list of field values to filter
;;
explanation:
The argument passed into the MLM is:
* field_value_list - list of FieldValueObjects defined as
NameValueObject := OBJECT [ field_name, include_flag, value_list ];
The data returned by the MLM are:
* exclusion_criteria_dictionary_object -
Collections.Generic.Dictionary< String, Boolean>
with field_name as key, and exclude_flag as value
* name_value_dictionary_object -
Collections.Generic.Dictionary< String, Collections.Generic.List<String> >
with field_name as key, and Collections.Generic.List<String> list containing
value_list as value
;;
keywords:
Fused Agent;
Community Data;
VPO filter;
dbMotion Data;
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using namespace "System";
using namespace "System.Exception";
using namespace "System.Windows.Forms";
// Arguments are passed in from the calling C++ program or MLM
( field_value_list
) := argument;
exclusion_criteria_dictionary_object := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.Dictionary< String, Boolean>{{{SINGLE-QUOTE}}};
name_value_dictionary_object := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.Dictionary< String, Collections.Generic.List<String> >{{{SINGLE-QUOTE}}};
// Only add the fields that have both include flag and the field value list specified
field_criteria_list := field_value_list as list; // this ensures single item is also a list
for field_criteria in field_criteria_list
do
if exists field_criteria.value_list AND count field_criteria.value_list > 0
then
field_name_obj := field_criteria.field_name as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
exclude_field_obj := (not field_criteria.include_flag) as {{{SINGLE-QUOTE}}}Boolean{{{SINGLE-QUOTE}}};
value_list_obj := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.List< String >{{{SINGLE-QUOTE}}};
field_values := field_criteria.value_list as list;
for value_item in field_values
do
void := call value_list_obj.Add with (value_item as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}});
enddo;
void := call exclusion_criteria_dictionary_object.Add with field_name_obj, exclude_field_obj;
void := call name_value_dictionary_object.Add with field_name_obj, value_list_obj;
endif;
enddo;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return (exclusion_criteria_dictionary_object, name_value_dictionary_object);
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,95 @@
maintenance:
title: Community Data;;
mlmname: STD_FUNC_FILTER_VPO_GEN_PROPERTY_DICTIONARY;;
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) 2014 - 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:
This functional MLM is called by other STD_Filter_VPO MLMs that generate
VPO filter criteria.
This MLM converts the field value list into a .Net dictionary with field
name as key, an boolean as value
;;
explanation:
The argument passed into the MLM is:
* field_value_list - list of FieldValueObjects defined as
PropertyValueObject := OBJECT [ field_name, value ];
The data returned by the MLM are:
* property_dictionary_object -
Collections.Generic.Dictionary< String, Boolean >
with field_name as key, and object as value
;;
keywords:
Fused Agent;
Community Data;
VPO filter;
dbMotion Data;
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Specify which .NET assemblies need to be loaded
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using namespace "System";
using namespace "System.Exception";
using namespace "System.Windows.Forms";
// Arguments are passed in from the calling C++ program or MLM
( field_value_list ) := argument;
property_dictionary_object := new net_object {{{SINGLE-QUOTE}}}Collections.Generic.Dictionary< String, Boolean>{{{SINGLE-QUOTE}}};
// Only add the fields that have both include flag and the field value list specified
field_property_list := field_value_list as list; // this ensures single item is also a list
for field_property in field_property_list
do
if exists field_property_list AND count field_property_list > 0
then
field_name_obj := field_property.field_name as {{{SINGLE-QUOTE}}}String{{{SINGLE-QUOTE}}};
field_value_obj := field_property.value as {{{SINGLE-QUOTE}}}Boolean{{{SINGLE-QUOTE}}};
void := call property_dictionary_object.Add with field_name_obj, field_value_obj;
endif;
enddo;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return property_dictionary_object;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,134 @@
maintenance:
title: Formats medications to be displayed in alert message;;
mlmname: STD_FUNC_FORMAT_MEDICATION;;
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: Formats medication text to return to calling MLM for use in alert messages.
;;
explanation: This MLM returns "msg_text" to the calling MLM. The variable "msg_text"
contains the order name, summary line, start date, stop date and status.
Each order is separated by a line.
Order items that were found to match, are printed in blue or if an
additive, an additional line indicates that the additive is contained in
the order above.
Example: D5W
KCL 30 mEq, 100ml hourly QD
starting on March 1, 2001, to March 17, 2001. STATUS:Active
KCL contained in IV order above. (this is printed in blue)
This MLM relys on calling MLM to send
- a list indicating if the item is an order or component
- a list of each item{{{SINGLE-QUOTE}}}s GUIDs
- a list of each item{{{SINGLE-QUOTE}}}s name
- a list of each order item{{{SINGLE-QUOTE}}}s summary lines
- a list of each order item{{{SINGLE-QUOTE}}}s request date
- a list of each order item{{{SINGLE-QUOTE}}}s stop date
- a list of each order item{{{SINGLE-QUOTE}}}s status code
- a list of which items matched
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(order_component_list, // List indicating if an order or component
guid_list, // List of each item{{{SINGLE-QUOTE}}}s GUIDs
order_name_list, // List of each item{{{SINGLE-QUOTE}}}s name
summary_line_list, // List of each order item{{{SINGLE-QUOTE}}}s summary lines
order_significant_date_list, // List of each order item{{{SINGLE-QUOTE}}}s request date
order_stop_date_list, // List of each order item{{{SINGLE-QUOTE}}}s stop date
order_status_desc_list, // List of each order item{{{SINGLE-QUOTE}}}s status code
match_med_found ) // List of which items matched
:= ARGUMENT;
;;
evoke:
;;
logic:
msg_text := "";
index_list := 1 seqto (count order_name_list);
for i in index_list do
// Process each item on the order item lists
previous_guid := guid;
order_or_component := last(first i from order_component_list);
guid := last(first i from guid_list);
order_name := last(first i from order_name_list);
summary_line := last(first i from summary_line_list);
order_start_date := last(first i from order_significant_date_list);
order_stop_date := last(first i from order_stop_date_list);
order_status_desc := last(first i from order_status_desc_list);
matching_med := last(first i from match_med_found);
// Formats each item name, summary line, startdate, and stopdate
if i > 1 then msg_text := msg_text || "\n"; endif;
if exist order_or_component then
// Check to see if item in list is an order or a component
if order_or_component = "order"
then
if exist order_name then
msg_text := msg_text ||"______________________________________"|| "\n";
If matching_med then
// Format differently for matches found on order name V.S. additive
msg_text := msg_text || "{{+B}}{{+c}}"|| order_name ||"{{-c}}{{-B}}";
else
msg_text := msg_text || "{{+B}}"|| order_name ||"{{-B}}" ;
endif; // Format order message
endif; // if exist order_name
if exist summary_line then msg_text := msg_text || " "
|| summary_line;
endif;
if exist order_start_date then
temp_start_date := order_start_date formatted with "%.2t";
msg_text := msg_text || "\n starting on "|| temp_start_date;
endif;
if exist order_stop_date then
temp_stop_date := order_stop_date formatted with "%.2t";
msg_text := msg_text|| " to "|| temp_stop_date;
endif;
if exist order_status_desc then
msg_text := msg_text|| "{{+B}}" || " Status: "|| order_status_desc || "{{-B}}";
endif;
else if exist order_name then
// Format additional line to indicate which additives matched
msg_text := msg_text || "{{+c}}"|| order_name
|| " contained in IV order above. {{-C}}"; endif;
endif;
endif;// Check to see if item in list is order or component
enddo;
conclude TRUE;
;;
action:
return msg_text ;
;;
end:

View File

@@ -0,0 +1,109 @@
maintenance:
title: Formats results to be displayed in alert message;;
mlmname: STD_FUNC_FORMAT_RESULT;;
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: Formats result text to return to calling MLM for use in alert messages.
;;
explanation: This MLM returns "msg_text" to the calling MLM. The variable "msg_text"
contains the result name, value, text, unit of measure, and the
performed date of all tests that were sent in to this MLM.
Example: Serum Potassium 3.5 mmol/L on March 15, 2001 10:15 am.
Serum Potassium 3.8 mmol/L on March 17, 2001 8:30 am.
This MLM relys on calling MLM to send
- a list of result names
- a list of result values
- a list of any text sent with values
- a list of unit of measures sent with values
- a list of date tests were performed
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(result_name_list, // List of result names
result_value_list, // List of result values
result_text_list, // List of any text sent with values
result_uom_list, // List of unit of measures sent with values
result_performed_date_list, // List of date tests were performed
result_community_source_list, // list of community source
include_community_source, // flag to indicate if source should be added to aler
community_results_alert_text // optional
):= ARGUMENT;
;;
evoke:
;;
logic:
msg_text := "";
index_list := 1 seqto (count result_name_list);
for I in index_list do
// Process each item on the lists
result_name := last (first I from result_name_list);
result_value := last (first I from result_value_list);
result_text := last (first I from result_text_list);
result_uom := last (first I from result_uom_list);
result_performed_date := last (first I from result_performed_date_list);
result_community_source := last (first I from result_community_source_list);
// Format each item for the message
if I > 1 then msg_text := msg_text || "\n"; endif;
if exist result_name then msg_text := msg_text || result_name; endif;
if exist result_value then msg_text := msg_text || " " || result_value; endif;
if exist result_text then msg_text := msg_text || " " || result_text; endif;
if exist result_uom then msg_text := msg_text || " " || result_uom; endif;
if exist result_performed_date then
msg_text := (msg_text, " on ", result_performed_date)
formatted with "%s%s%.4t";
endif;
if exist result_community_source then
if exist community_results_alert_text AND
community_results_alert_text <> "" then
community_source_suffix := "(" || community_results_alert_text;
if ( include_community_source ) then
community_source_suffix := community_source_suffix || " Source: " || result_community_source;
endif;
msg_text := msg_text || " {{+B}}" || community_source_suffix || "){{-B}}";
endif;
endif;
enddo;
conclude TRUE;
;;
action:
return msg_text ;
;;
end:

View File

@@ -0,0 +1,88 @@
maintenance:
title: Health Management Auto assignment MLM;;
mlmname: STD_FUNC_HM_AUTO_ASSIGNMENT;;
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: This is a standard function MLM that is used
to insert a queue entry for the Health Management
auto assignment functionality.
;;
explanation: This MLM is called with 3 parameters.
clientGUID - The client GUID for the current patient
userGUID - The user GUID for the current logged on user
updateDatabase - Should only be set to true if the MLM needs to
write data to the queue. Generally set to false when the
calling MLM is being run from the MLM editor.
The CDS Scheduled Service must be running and the MLM
SCH_HM_AUTO_ASSIGNMENT_EXECUTE must be loaded and in production.
;;
keywords: HealthManagement, AutoAssignment
;;
knowledge:
type: data-driven;;
data:
(clientGUID,
userGUID,
updateDatabase
):= ARGUMENT;
log_execution_info := false;
// Do not run if called by the editor
if ( updateDatabase ) then
if clientGUID is null or userGUID is null then
result := null;
else
// Insert into the Auto Assignment Queue
// Using the stored procedure
result := read last { "Execute SXAHMAutoAssignmentScheduleInsPr @clientGUID=" ||
SQL(clientGUID) || ", @userGUID=" || SQL(userGUID) };
endif;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return result;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,151 @@
maintenance:
title: Standard MLM to mark an HM Event as done;;
mlmname: STD_FUNC_HM_MARKASDONE;;
arden: version 2.5;;
version: 18.4;;
institution: AllScripts;;
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: Standard Function MLM containing the necessary logic to Mark a
Health Management immunization or wellness event as done.
;;
explanation: Do not make any changes to this MLM unless instructed to do so
by Allscripts.
This MLM accepts several parameters which it uses to set properties on
several .NET object which are then used to mark a Health Management
immunization or wellness event as done.
Parameter List:
ClientGUID
The Id for the current patient on which the trigger event is
occuring.
locationGUID
The location group Id where the health management item was marked
as done.
linkedItemId
An Id to an order or some other data type that is being processed
by the calling MLM. If it is linked to a scheduled event occurrence
the linked occurrence will be maked as done. If the Id is NULL or
is not linked then the code will determine if it needs to create a
new scheduled event occurrence.
linkedItemType
The type of the linked item. Only order (0) is supported at this time.
updateDatabase
A flag used to determine if the actual Mark as Done functionality
will be called. If set to false it will go through all the look
ups and will indicate what will happen.
recordOnlyIfEventActive
A flag that determines if the event being processed must be
currently assigned to the patient and what state it should be. If true
then the event must be assigned to the patient and it must be active.
If false the the event must be assigned but it doesn{{{SINGLE-QUOTE}}}t need to be active.
recordOnlyIfPatientAssignedEvent
A flag that determines if the event needs to be already assigned before
it can be marked as done. If true then the event must be assigned, the
code will then check the flag recordOnlyIfEventActive. If false then
the event will be added as long as it exists and is active in the catalog.
eventOccurrenceObj
immunizationObj
vaccineMedicationLotObj
consentDocumentObj
educationalMaterialsObj
The data objects used to create the new Health Management client
event occurrence and mark it as done. For a wellness and immunization
events the object eventOccurrenceObj is required. For immunization
the immunizationObj is also manditory. All other objects are
optional.
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
using "Eclipsys.Clinicals.Common";
using "Sunrise.Clinicals.HealthManagement";
using namespace "Sunrise.Clinicals.HealthManagement";
using namespace "Sunrise.Clinicals.HealthManagement.DataObjects";
// Parameters passed to MLM.
( clientGUID,
locationGroupGuid,
linkedItemId,
linkedItemType,
updateDatabase,
recordOnlyIfPatientAssignedEvent,
recordOnlyIfEventActive,
eventOccurrenceObj,
immunizationObj,
vaccineMedicationLotObj,
consentDocumentObj,
educationalMaterialsObj,
linkOrderToEventOccurrence
) := argument;
HMAction_MLM := MLM {{{SINGLE-QUOTE}}}STD_FUNC_HM_PERFORM_ACTION{{{SINGLE-QUOTE}}};
(mlmStatus, outputMessage) := call HMAction_MLM
with clientGUID,
locationGroupGuid,
linkedItemId,
0,
updateDatabase,
recordOnlyIfPatientAssignedEvent,
recordOnlyIfEventActive,
"MAD",
eventOccurrenceObj,
immunizationObj,
vaccineMedicationLotObj,
consentDocumentObj,
educationalMaterialsObj,
null, //notGivenReasonDef,
linkOrderToEventOccurrence;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return mlmStatus, outputMessage;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,87 @@
maintenance:
title: Standard MLM to mark an HM Event as not done;;
mlmname: STD_FUNC_HM_MARKASNOTDONE;;
arden: version 2.5;;
version: 18.4;;
institution: AllScripts;;
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: Standard Function MLM containing the necessary logic to Mark a
Health Management immunization or wellness event as not done.
;;
explanation:
;;
keywords:
;;
citations:
;;
knowledge:
type: data-driven;;
data:
// Parameters passed to MLM.
( clientGUID,
locationGroupGUID,
linkedItemId,
linkedItemType,
updateDatabase,
recordOnlyIfPatientAssignedEvent,
recordOnlyIfEventActive,
eventOccurrenceObj,
immunizationObj,
notGivenReasonObj,
exemptionDocumentObj,
linkOrderToEventOccurrence
) := argument;
HMAction_MLM := MLM {{{SINGLE-QUOTE}}}STD_FUNC_HM_PERFORM_ACTION{{{SINGLE-QUOTE}}};
(mlmStatus, outputMessage) := call HMAction_MLM
with clientGUID,
locationGroupGuid,
linkedItemId,
0,
updateDatabase,
recordOnlyIfPatientAssignedEvent,
recordOnlyIfEventActive,
"MAND",
eventOccurrenceObj,
immunizationObj,
null, //vaccineMedicationLotObj
exemptionDocumentObj,
null, //educationalMaterialsObj
notGivenReasonObj,
linkOrderToEventOccurrence;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return mlmStatus, outputMessage;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,486 @@
maintenance:
title: Standard MLM to mark an HM Event as done;;
mlmname: STD_FUNC_HM_PERFORM_ACTION;;
arden: version 2.5;;
version: 18.4;;
institution: AllScripts;;
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) 2016 - 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: Standard Function MLM containing the necessary logic to Mark a
Health Management immunization or wellness event as done.
;;
explanation: Do not make any changes to this MLM unless instructed to do so
by Allscripts.
This MLM accepts several parameters which it uses to set properties on
several .NET object which are then used to mark a Health Management
immunization or wellness event as done.
Parameter List:
ClientGUID
The Id for the current patient on which the trigger event is
occuring.
locationGUID
The location group Id where the health management item was marked
as done.
linkedItemId
An Id to an order or some other data type that is being processed
by the calling MLM. If it is linked to a scheduled event occurrence
the linked occurrence will be maked as done. If the Id is NULL or
is not linked then the code will determine if it needs to create a
new scheduled event occurrence.
linkedItemType
The type of the linked item. Only order (0) is supported at this time.
updateDatabase
A flag used to determine if the actual Mark as Done functionality
will be called. If set to false it will go through all the look
ups and will indicate what will happen.
recordOnlyIfEventActive
A flag that determines if the event being processed must be
currently assigned to the patient and what state it should be. If true
then the event must be assigned to the patient and it must be active.
If false the the event must be assigned but it doesn{{{SINGLE-QUOTE}}}t need to be active.
recordOnlyIfPatientAssignedEvent
A flag that determines if the event needs to be already assigned before
it can be marked as done. If true then the event must be assigned, the
code will then check the flag recordOnlyIfEventActive. If false then
the event will be added as long as it exists and is active in the catalog.
hmAction
The type of action performed (Only "MAD" and "MAND" are supported right now)
eventOccurrenceObj
immunizationObj
vaccineMedicationLotObj
consentDocumentObj
educationalMaterialsObj
The data objects used to create the new Health Management client
event occurrence and mark it as done. For a wellness and immunization
events the object eventOccurrenceObj is required. For immunization
the immunizationObj is also manditory. All other objects are
optional.
notGivenReasonObj
linkOrderToEventOccurrence
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
using "Eclipsys.Clinicals.Common";
using "Sunrise.Clinicals.HealthManagement";
using "Sunrise.Clinicals.HealthManagement.ServiceInterfaces";
using namespace "Sunrise.Clinicals.HealthManagement";
using namespace "Sunrise.Clinicals.HealthManagement.ServiceInterfaces";
using namespace "Sunrise.Clinicals.HealthManagement.DataObjects";
// Parameters passed to MLM.
( clientGUID,
locationGUID,
linkedItemId,
linkedItemType,
updateDatabase,
recordOnlyIfPatientAssignedEvent,
recordOnlyIfEventActive,
hmAction,
eventOccurrenceObj,
immunizationObj,
vaccineMedicationLotObj,
consentDocumentObj,
educationalMaterialsObj,
notGivenReasonObj,
linkOrderToEventOccurrence
) := argument;
log_execution_info := false;
outputMessage := null;
// Status levels
// 1 = No client event on schedule
// 2 = Success
// 3 = Failure
mlmStatus := 2;
// Validate parameters
if (eventOccurrenceObj is null OR eventOccurrenceObj.eventName is null OR
clientGUID is null OR
eventOccurrenceObj.actionProviderId is null )
then
outputMessage := "The MLM STD_FUNC_HM_PERFORM_ACTION was called with invalid parameters.\n";
mlmStatus := 3;
else
// Test for the existance of the event
if recordOnlyIfPatientAssignedEvent
then
// If true then check for an active schedule, otherwise the status
// doesn{{{SINGLE-QUOTE}}}t matter
if recordOnlyIfEventActive
then
activeClientEventTest := " AND ce.EventStatusType=0 ";
else
activeClientEventTest := " ";
endif;
// Find the matching Health Management Event from the mapped Ancillary Name.
(eventId,
eventType,
eventTypeDesc ) := read last { "select e.EventID,e.Type,e1.ReferenceString as [TypeDesc] " ||
" from SXAHMEvent e " ||
" inner join SXAHMClientEvent ce on e.EventID = ce.EventID " ||
" inner join CV3EnumReference e1 on e1.TableName = {{{SINGLE-QUOTE}}}SXAHMEvent{{{SINGLE-QUOTE}}} " ||
" and e1.ColumnName={{{SINGLE-QUOTE}}}Type{{{SINGLE-QUOTE}}} and e1.EnumValue=e.Type " ||
"where e.Active=1 AND e.Name = " || SQL(eventOccurrenceObj.eventName) ||
activeClientEventTest ||
" AND ce.ClientGUID = " || SQL(clientGUID) };
else
// Make sure there is an Event for the mapped name, doesn{{{SINGLE-QUOTE}}}t have to be on the patient{{{SINGLE-QUOTE}}}s
// schedule
(eventId,
eventType,
eventTypeDesc ) := read last { "select e.EventID,e.Type,e1.ReferenceString as [TypeDesc] " ||
" from SXAHMEvent e " ||
" inner join CV3EnumReference e1 on e1.TableName = {{{SINGLE-QUOTE}}}SXAHMEvent{{{SINGLE-QUOTE}}} " ||
" and e1.ColumnName={{{SINGLE-QUOTE}}}Type{{{SINGLE-QUOTE}}} and e1.EnumValue=e.Type " ||
"where e.Active=1 AND e.Name = " || SQL(eventOccurrenceObj.eventName) };
endif;
// If found, get the necessary data from the other parameter objects
// and then call the occurrence mark as done logic
if eventId is not null
then
try
placeOrder := false;
//Get Pending occurrence ID for current eventID
(eventOccurrenceId, linkId) := read last { "SELECT seo.ScheduledEventOccurrenceID, oli.LinkedItemID FROM SXAHMScheduledEventOccurrence seo " ||
" LEFT OUTER JOIN SXAHMOccurrenceLinkedItemXRef oli ON ( oli.ScheduledEventOccurrenceID = seo.ScheduledEventOccurrenceID AND oli.LinkedItemType =" || linkedItemType || ") " ||
" WHERE seo.OccurrenceStatusType=0 " ||
" AND seo.EventID=" || SQL(eventId) ||
" AND seo.ClientGUID=" || SQL(clientGUID) };
// Get the location facility time zone, from the location guid
(locationTZNowDateTime) := read last { "DECLARE @EnterpriseNow DateTime " ||
" SELECT @EnterpriseNow = CurDate FROM dbo.SXADBGetEnterpriseNowTblFn(); " ||
" SELECT top 1 tz.LocalDate as locationTZNowDateTime " ||
" FROM CV3Location locn " ||
" left join CV3LocnFacility lf on ( iif( locn.IsFacility = 1 , locn.Guid, locn.FacilityGUID ) = lf.FacilityGUID ) " ||
" CROSS APPLY dbo.SXADBConvertEnterpriseToLocalTblFn(lf.TimeZone, @EnterpriseNow) tz " ||
" WHERE locn.GUID = " || SQL(locationGUID) };
eventOccurrenceMgr := new net_object {{{SINGLE-QUOTE}}}EventOccurrenceManager{{{SINGLE-QUOTE}}};
if ( eventOccurrenceId is not null ) then
eventOccurrence := call eventOccurrenceMgr.GetEventOccurrence with eventOccurrenceId as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}},
locationTZNowDateTime as {{{SINGLE-QUOTE}}}System.Nullable<System.DateTime>{{{SINGLE-QUOTE}}};
else
eventOccurrence := call {{{SINGLE-QUOTE}}}EventOccurrenceBObj{{{SINGLE-QUOTE}}}.CreateEventOccurrence with eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}};
eventOccurrence.ClientPrimaryKey := (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}};
endif;
if linkOrderToEventOccurrence and linkId is null and linkedItemId is not null then
placeOrder := true;
endif;
continueProcess := true;
if hmAction = "MAD" then
strAction := "Done";
elseif(hmAction = "MAND") then
strAction := "not Done";
endif;
// If the Mapped Event is an immunization then look for immumization and medication
// lot information.
if eventTypeDesc = "Immunization" then
//Find if Vaccine exist.
if immunizationObj.VaccineName is not null OR
immunizationObj.CVXCode is not null then
(vaccineId,
vaccineName,
vaccineCVXCode ) := read last { "SELECT vci.VaccineCatalogItemID, Name, CVXCode FROM SXAHMEventVaccineXRef vxref " ||
" INNER JOIN SXAHMVaccineCatalogItem vci ON (vci.VaccineCatalogItemID = vxref.VaccineID) " ||
" WHERE vxref.EventID =" || SQL(eventId) || " AND vci.Active = 1 AND (vci.Name =" || SQL(immunizationObj.VaccineName) || " OR vci.CVXCode =" || SQL(immunizationObj.CVXCode) || " ) " };
endif;
if(vaccineId is null) then
if immunizationObj.VaccineName is not null
then
vaccineInfo := "Vaccine name: " || immunizationObj.VaccineName ;
endif;
if immunizationObj.CVXCode is not null
then
vaccineInfo := vaccineInfo || "\nCVX Code: " || immunizationObj.CVXCode;
endif;
if vaccineInfo is null
then
vaccineInfo := "No vaccine data has been assigned to the order";
else
vaccineInfo := vaccineInfo || "\n is not configured for this event";
endif;
outputMessage := "Cannot mark the immunization event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} as " || strAction || ".\n";
outputMessage := outputMessage || vaccineInfo;
mlmStatus := 3;
continueProcess := false;
endif;
endif;
if(continueProcess) then
//Place Order first
if(placeOrder AND updateDatabase) then
//If created a new occurrence, we need to save it first
if(eventOccurrence.PrimaryKey = 0)then
x := call eventOccurrence.Insert;
endif;
occLinkedItemData := new net_object {{{SINGLE-QUOTE}}}OccurrenceLinkedItemXRefData{{{SINGLE-QUOTE}}};
occLinkedItemData.ScheduledEventOccurrenceId := eventOccurrence.PrimaryKey as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}};
occLinkedItemData.LinkedItemId := (linkedItemId as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}};
occLinkedItemData.LinkedItemType := linkedItemType as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}};
occLinkedItemData.ParentOccurrenceID := eventOccurrence.ParentOccurrencePrimaryKey as {{{SINGLE-QUOTE}}}System.Nullable<System.Int64>{{{SINGLE-QUOTE}}};
occLinkedItem := new net_object {{{SINGLE-QUOTE}}}OccurrenceLinkedItemXRefBObj{{{SINGLE-QUOTE}}} with (occLinkedItemData);
x := call eventOccurrence.PlaceOrder with occLinkedItem, true;
// Need to reload event occurrence, otherwise we have a update issue (MSRowVersion is different)
eventOccurrence := call eventOccurrenceMgr.FindPendingEventOccurrenceForClientByEvent with (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}, eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}},
null as {{{SINGLE-QUOTE}}}System.Nullable<System.DateTime>{{{SINGLE-QUOTE}}};
endif; //PlaceOrder
// The objects eventOccurrence, consentDocument and educationMaterials are
// used by both Wellness events and Immunization events.
// Set the Action date and provider information
yearAction := (extract year of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}};
monthAction := (extract month of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}};
dayAction := (extract day of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}};
hourAction := extract hour of eventOccurrenceObj.actionDate;
minAction := extract minute of eventOccurrenceObj.actionDate;
timeString := hourAction formatted with "%02d" || ":" || minAction formatted with "%02d";
partialDate := new net_object {{{SINGLE-QUOTE}}}Eclipsys.Clinicals.Common.PartialDate{{{SINGLE-QUOTE}}} with (yearAction, monthAction, dayAction, timeString);
eventOccurrence.ActionDateTime := partialDate;
eventOccurrence.ActionProviderName := eventOccurrenceObj.actionProviderDisplayName;
eventOccurrence.ActionProviderPrimaryKey := (eventOccurrenceObj.actionProviderId as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}};
eventOccurrence.Comment := eventOccurrenceObj.Comment;
eventOccurrence.SiteGivenCode := eventOccurrenceObj.SiteGivenCode;
eventOccurrence.RouteCode := eventOccurrenceObj.RouteCode;
eventOccurrence.IsPartialDose := eventOccurrenceObj.IsPartialDose;
// set the action user on the history to be the user from the state object. This is the user
// who triggered the MLM
userGUID := read last {StateInfo: UserGUID };
if ( userGUID is not null )
then
eventOccurrence.NewOccurrenceActionStatusHistory.ActionUserPrimaryKey := (userGUID as number) as {{{SINGLE-QUOTE}}}System.Nullable<System.Int64>{{{SINGLE-QUOTE}}};
endif;
if ( consentDocumentObj is not null )
then
consentDocument := new net_object {{{SINGLE-QUOTE}}}ConsentDocumentBObj{{{SINGLE-QUOTE}}};
consentDocument.ConsentTypeCode := consentDocumentObj.TypeCode;
consentDocument.ConsentDate := consentDocumentObj.ConsentDate as Time;
//consentDocument.ConsentTypeTime := consentDocumentObj.ConsentTime; // Timespan -- not supported
consentDocument.ConsentBy := consentDocumentObj.ConsentBy;
consentDocument.RelationshipCode := consentDocumentObj.RelationShipCode;
consentDocument.DocumentType := consentDocumentObj.DocumentType as {{{SINGLE-QUOTE}}}ConsentDocumentType{{{SINGLE-QUOTE}}};
x := call eventOccurrence.ConsentDocuments.Add with consentDocument;
endif;
if ( educationalMaterialsObj is not null )
then
educationalMaterials := new net_object {{{SINGLE-QUOTE}}}EducationMaterialBObj{{{SINGLE-QUOTE}}};
educationalMaterials.EducationalMaterialTypeCode := educationalMaterialsObj.TypeCode;
educationalMaterials.IsVis := educationalMaterialsObj.IsVis;
educationalMaterials.PublishedDate := educationalMaterialsObj.PublishedDate as Time;
educationalMaterials.PresentedDate := educationalMaterialsObj.PresentedDate as Time;
x := call eventOccurrence.EducationMaterials.Add with educationalMaterials;
endif;
if( notGivenReasonObj is not null) then
reasonType := eventTypeDesc || " " || notGivenReasonObj.ReasonType;
reasonCode := notGivenReasonObj.ReasonCode;
reason := notGivenReasonObj.Reason;
//If ReasonCode is populated, get the Reason, Otherwise get the ReasonCode.
if(reasonCode is not NULL) then
reason := read last { "SELECT cr.Reason FROM CV3CodedReason cr WHERE Type = " || SQL(reasonType) || " AND Code = " || SQL(reasonCode) };
else
reasonCode := read last { "SELECT cr.Code FROM CV3CodedReason cr WHERE Type = " || SQL(reasonType) || " AND Reason = " || SQL(notGivenReasonObj.Reason) };
endif;
codedReason := new net_object {{{SINGLE-QUOTE}}}Sunrise.Clinicals.HealthManagement.ServiceInterfaces.CodedReason{{{SINGLE-QUOTE}}};
codedReason.Code := reasonCode;
codedReason.Reason := reason;
actionReason := new net_object {{{SINGLE-QUOTE}}}ActionReason{{{SINGLE-QUOTE}}} with (codedReason);
eventOccurrence.NewOccurrenceActionStatusHistory.ActionCodedReasonType := reasonType;
x := call eventOccurrence.NewOccurrenceActionStatusHistory.ActionReasons.Add with actionReason;
eventOccurrence.NewOccurrenceActionStatusHistory.ActionMoreDetail := notGivenReasonObj.MoreDetails;
endif;
// If the Mapped Event is an immunization then look for immumization and medication
// lot information.
if (vaccineId is not null)
then
immunizationEventOccurrence := eventOccurrence as {{{SINGLE-QUOTE}}}ImmunizationEventOccurrenceBObj{{{SINGLE-QUOTE}}};
vaccineDose := (vaccineMedicationLotObj.LotDoseAmount as number) as {{{SINGLE-QUOTE}}}System.Nullable<System.Decimal>{{{SINGLE-QUOTE}}};
vaccineUom := vaccineMedicationLotObj.LotDoseUom;
immunizationEventOccurrence.VaccinePrimaryKey := vaccineId;
immunizationEventOccurrence.DoseAmount := vaccineDose;
immunizationEventOccurrence.DoseUom := vaccineUom;
immunizationEventOccurrence.VaccineProductCode := immunizationObj.VaccineProductCode;
immunizationEventOccurrence.VaccineBrandName := immunizationObj.VaccineBrandName;
immunizationEventOccurrence.VaccineEligibilityCode := immunizationObj.VaccineEligibilityCode;
// One or the other, not both.
if ( immunizationObj.VaccineManufacturerMVXCode is not null )
then
immunizationEventOccurrence.VaccineManufacturerMvxCode := immunizationObj.VaccineManufacturerMVXCode;
else
immunizationEventOccurrence.VaccineManufacturer := immunizationObj.VaccineManufacturer;
endif;
// Set Lot information
if (VaccineMedicationLotObj is not null)
then
vaccineMedicationLotData := new net_object {{{SINGLE-QUOTE}}}VaccineMedicationLotDataBObj{{{SINGLE-QUOTE}}};
vaccineMedicationLotData.LotNumber := VaccineMedicationLotObj.LotNumber;
vaccineMedicationLotData.LotSourceCode := VaccineMedicationLotObj.LotSourceCode;
vaccineMedicationLotData.LotExpirationDate := VaccineMedicationLotObj.LotExpirationDate as Time;
vaccineMedicationLotData.LotDoseAmount := vaccineDose;
vaccineMedicationLotData.LotDoseUom := vaccineUom;
vaccineMedicationLotData.RemovedFromStorage := VaccineMedicationLotObj.RemovedFromStorageDate as Time;
vaccineMedicationLotData.LotWasteAmount := (VaccineMedicationLotObj.LotWasteAmount as Number) as {{{SINGLE-QUOTE}}}System.Nullable<System.Decimal>{{{SINGLE-QUOTE}}};
vaccineMedicationLotData.LotWasteUom := VaccineMedicationLotObj.LotWasteUom;
x := call immunizationEventOccurrence.VaccineMedicationLots.Add with vaccineMedicationLotData;
endif;
outputMessage := "Marked the vaccine type event occurrence {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName ||
"{{{SINGLE-QUOTE}}} as " || strAction || " using vaccine {{{SINGLE-QUOTE}}}" || vaccineName || "{{{SINGLE-QUOTE}}} CVXCode=(" || vaccineCVXCode || ").";
else
outputMessage := "Marked the wellness event occurrence {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} as " || strAction || ".";
endif; //vaccineId is not null
if mlmStatus = 2 AND updateDatabase then
locationId := (locationGUID as Number) as {{{SINGLE-QUOTE}}}System.Nullable<System.Int64>{{{SINGLE-QUOTE}}};
// Mark it as done via the manager
eventOccurrenceMgr := new net_object {{{SINGLE-QUOTE}}}EventOccurrenceManager{{{SINGLE-QUOTE}}};
if hmAction = "MAD" then
x := call eventOccurrenceMgr.MarkEventOccurrenceDone with eventOccurrence, locationId;
elseif(hmAction = "MAND") then
x := call eventOccurrenceMgr.MarkEventOccurrenceNotDone with eventOccurrence, locationId;
endif; //hmAction = {{{SINGLE-QUOTE}}}MAD{{{SINGLE-QUOTE}}}
// Re-evaluate based on possible new conditions
clientEventMgr := new net_object {{{SINGLE-QUOTE}}}ClientEventManager{{{SINGLE-QUOTE}}};
dataChanged := call clientEventMgr.ReEvaluateClientEventOccurrence
with (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}},
eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}},
null as {{{SINGLE-QUOTE}}}System.Nullable<System.DateTime>{{{SINGLE-QUOTE}}};
endif;
endif; //continueProcess
endtry;
catch exception ex
mlmStatus := 3;
outputMessage := "An attempt to Mark as " || strAction || " the Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName ||
"{{{SINGLE-QUOTE}}} has failed. \nThe reason for the failure is as follows:\n" || ex.Message;
endcatch;
else
// Not an error condititon, just that the evoking object doesn{{{SINGLE-QUOTE}}}t have a matching
// Health Management scheduled Client Event.
mlmStatus := 1;
if recordOnlyIfPatientAssignedEvent
then
outputMessage := "The Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName ||
"{{{SINGLE-QUOTE}}} does not exist in the catalog or is not active on the patient{{{SINGLE-QUOTE}}}s chart.\n" ||
"No action has been taken.";
else
outputMessage := "The Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName ||
"{{{SINGLE-QUOTE}}} does not exist in the catalog.\n" ||
"No action has been taken.";
endif;
endif;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return mlmStatus, outputMessage;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,279 @@
maintenance:
title: Function MLM used to insert a row into the reportable info message queue ;;
mlmname: STD_FUNC_INSERT_REPORTABLE_SURVEILLANCE;;
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: This is a standard function MLM that is used by all other
reportable result/Bio-surveillance MLMs. It takes the parameter
values passed in, validates them and then creates a SQL call to
insert a row into the SXAReportableInfoMsgQueue table.
This MLM will return the Xml document generated is successful and
NULL if there was nothing to be written.
;;
explanation:
3 parameters are passed to this procedure:
Message Queue Type - This specifies what type of message is being processed.
Valid values are 0,"ReportableResults" or
1,"Biosurveillance" or 2,"Case Notification" or 3,"SendLabResults".
If invalid or set to NULL it will be defaulted to "ReportableResults".
Reportable Object List - The objects that need to be reported. This can
either be a single ReportableType object or a list
of these objects.
Write To Database - A boolean flag, if true an entry will be written to the
database. Generally a value of false is passed when
testing this MLM from the editor.
The reportable Object list will contain objects defined by this structure:
ReportableType := OBJECT
[
ParentKey, // Document, Order or Visit GUID (Single)
ChildKeys, // Observation, Result or HealthIssue GUID (Single, list or NULL)
ObjectType, // "result", "observation", "healthissue", "visit", "subject", "notification", "messageprofileid"
Reason
];
This object must be defined in the calling MLM and populated based on the
business rules of that MLM.
ParentKey - This is the GUID for an Order or Document that is the parent
for the childKeys. An order will have Result children while
a Document will have Observation children.
ChildKeys - This property contains either Result or Observation GUIDs
depending on the type of the ParentKey. It can contain
either a single GUID or list of GUIDs. If a list the GUIDs
are all assumed to be of the same type.
If NULL, the code will assume that all result items are to
be included. A tag in the outgoing message is set so that
it is not necessary to actually retrieve all the GUIDs.
ObjectType - If the Parent object is a Document then this value must be
"observation". If the parent object is an Order then this
value must be "result".
Reason - This is a coded value that can be included into the parent element.
For reportable results this will be the diagnostic code:
<Code>^<Description>^<Code Type>
413.9^Angina^ICD9
For Bio Surveillance messages the reason code is only required for
the visit object and is the HL7 message type.
;;
keywords: Biosurveillance
;;
knowledge:
type: data-driven;;
data:
( MsgQueueType,
ReportableObjectList, // Single item or list
writeToDatabase
) := ARGUMENT;
log_execution_info := false;
// Set default values
parentKeyType := "Order";
childKeyType := "Result";
parentKeyAttrib := "Results";
xmlDoc := null;
returnStatus := false;
errorMessage := "";
fatal_error := false;
if (writeToDatabase is NULL) then
writeToDatabase := true;
endif;
// Sanity check on MsgQueueType, defaults to ReportableResult
// If all else fails
if ( MsgQueueType is not NULL ) then
if ( MsgQueueType is not number ) then
if ( MsgQueueType = "BioSurveillance" ) then MsgQueueType := 1;
elseif ( MsgQueueType = "ReportableResult" ) then MsgQueueType := 0;
elseif ( MsgQueueType = "CaseNotification" ) then MsgQueueType := 2;
elseif ( MsgQueueType = "SendLabResults" ) then MsgQueueType := 3;
else MsgQueueType := 0;
endif;
endif;
else
MsgQueueType := 0;
endif;
if ( MsgQueueType is 2 ) then
error_message := "Invalid MsgQueueType value - CaseNotification no longer supported";
fatal_error := true;
endif;
if not fatal_error then
userID := read last { UserInfo: IDCode };
// If not a list, turn it into one.
if (not ReportableObjectList is list) then
ReportableObjectList := ,ReportableObjectList;
endif;
// Make sure there is at least one reportable
// object.
if exists ReportableObjectList
then
// Build Xml
xmlDoc := "";
for obj in ReportableObjectList do
if ( obj.ParentKey is not NULL ) then
if ( obj.ObjectType = "result") then
parentKeyType := "Order";
parentKeyAttrib := "Results";
childKeyType := "Result";
elseif ( obj.ObjectType = "observation") then
parentKeyType := "Document";
parentKeyAttrib := "ObsItems";
childKeyType := "ObsItem";
elseif (obj.ObjectType = "healthissue") then
parentKeyType := "HealthIssue";
parentKeyAttrib := "Diagnosis";
childKeyType := "DG1";
elseif (obj.ObjectType = "procedure") then
parentKeyType := "HealthIssue";
parentKeyAttrib := "Diagnosis";
childKeyType := "PR1";
elseif (obj.ObjectType = "visit") then
parentKeyType := "Visit";
parentKeyAttrib := null;
childKeyType := null;
elseif (obj.ObjectType = "subject") then
parentKeyType := "Subject";
parentKeyAttrib := null;
childKeyType := null;
elseif (obj.ObjectType = "notification") then
parentKeyType := "Notification";
parentKeyAttrib := null;
childKeyType := null;
elseif (obj.ObjectType = "messageprofileid") then
parentKeyType := "MessageProfileId";
parentKeyAttrib := null;
childKeyType := null;
elseif (obj.ObjectType = "resultstatus") then
parentKeyType := "ResultStatus";
parentKeyAttrib := null;
childKeyType := null;
else
parentKeyType := obj.ObjectType;
parentKeyAttrib := null;
childKeyType := null;
endif;
xmlDoc := xmlDoc || "<" || parentKeyType || " Key={{{SINGLE-QUOTE}}}" || obj.ParentKey || "{{{SINGLE-QUOTE}}}";
if ( obj.Reason is Not NULL ) then
if ( obj.ObjectType = "visit") then
xmlDoc := xmlDoc || " Event={{{SINGLE-QUOTE}}}" || xml(obj.Reason) ||"{{{SINGLE-QUOTE}}} ";
elseif ( obj.ObjectType in( "subject", "notification", "resultstatus" ) ) then
xmlDoc := xmlDoc || " Type={{{SINGLE-QUOTE}}}" || xml(obj.Reason) ||"{{{SINGLE-QUOTE}}} ";
elseif ( obj.ObjectType = "messageprofileid" ) then
xmlDoc := xmlDoc || " ID={{{SINGLE-QUOTE}}}" || xml(obj.Reason) ||"{{{SINGLE-QUOTE}}} ";
elseif( obj.ObjectType in("result", "observation", "healthissue") ) then
xmlDoc := xmlDoc || " Reason={{{SINGLE-QUOTE}}}" || xml(obj.Reason) ||"{{{SINGLE-QUOTE}}} ";
else
xmlDoc := xmlDoc || " Value={{{SINGLE-QUOTE}}}" || xml(obj.Reason) ||"{{{SINGLE-QUOTE}}} ";
endif;
endif;
// Visit, Subject, Notification, and MessageProfileId nodes do not have any children
if ( parentKeyAttrib is not null ) then
if ( obj.ChildKeys is NULL ) then
xmlDoc := xmlDoc || " " || parentKeyAttrib || "={{{SINGLE-QUOTE}}}All{{{SINGLE-QUOTE}}} >";
else
xmlDoc := xmlDoc || " " || parentKeyAttrib || "={{{SINGLE-QUOTE}}}Selected{{{SINGLE-QUOTE}}} >";
if ( obj.ChildKeys is NOT list) then
obj.ChildKeys := ,obj.ChildKeys; // If not a list make a list
endif;
for child in obj.ChildKeys do
if ( child <> "" AND child is not null ) then
if ( (child as number) is number) then
keyAttribute := "Key";
else
keyAttribute := "Type";
endif;
xmlDoc := xmlDoc || "<" || childKeyType || " " ||
keyAttribute ||"={{{SINGLE-QUOTE}}}" || child || "{{{SINGLE-QUOTE}}} />";
endif;
enddo;
endif;
else
xmlDoc := xmlDoc || ">";
endif;
xmlDoc := xmlDoc || "</" || parentKeyType || ">";
endif;
enddo;
if ( xmlDoc <> "" ) then
xmlDoc := "<Root>" || xmlDoc || "</Root>";
// Build SQL Insert logic
if ( writeToDatabase ) then
result := read last
{ "execute SXAReportableInfoMsgQueueInsPr " ||
" @ReportableInfoXml = " || SQL(xmlDoc) ||
", @MsgQueueType = " || SQL(MsgQueueType) ||
", @CreatedBy = " || SQL(userID) };
endif;
returnStatus := true;
endif;
endif;
endif;
;;
priority: 50
;;
evoke:
;;
logic:
conclude returnStatus;
;;
action:
if ( xmlDoc = "" ) then xmlDoc := null; endif;
if fatal_error then
return error_message;
else
return xmlDoc;
endif;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,238 @@
maintenance:
title: Retrieve Multum References;;
mlmname: STD_FUNC_MULTUM_REFERENCES;;
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: This MLM is used to retrieve references from the MULTUM database and format
then based on the Vancouver journal standard.
;;
explanation:
This MLM retrieves from the Multum database all the references that are linked to the parameters
that are passed in. The parameters used are dependent on the reference type that is being accessed.
render_style - Support which text formatting codes are used when creating the reference string.
RTF - Use RTF code for any formatting that is needed.
None - Only use CR, no other formatting is used. Calling MLM is assumed to do any formatting.
if NULL or blank then the default will be RTF.
reference_type - The type of reference to retrieve from the multum database. The following types
will be supported. "ddi", "drgint", "allrgy"
reference_title - A title that will be added to the top of the list of references created by a call to
this MLM. Can be empty which indicates that no title is to be included.
drug_number1 - A multum drug number, only used when the reference_type is "drgint".
drug_number2 - A multum drug number, only used when the reference_type is "drgint".
conflict_textId - A conflict Id from the multum database, only used when the reference_type is "ddi".
Three values are returned by this MLM.
outputString - This is the formatted references as a single string. If there are no references found
this string will be null.
revision_date - The date the Multum database was last updated.
refCounter - The actual number of references returned from the multum database. If there are no references
found this counter will be 0.
;;
keywords: references, Multum
;;
citations:
;;
knowledge:
type: data-driven;;
data:
(render_style,
reference_type,
reference_title,
drug_number1,
drug_number2,
conflict_textId,
allergenID,
functionId ):= ARGUMENT;
// Defaults
default_render_style := "rtf";
supported_render_styles := ("rtf", "none");
// ---------------------------------------------------------------------------------
// Do not change any code below
if render_style is null or render_style = "" or render_style not in supported_render_styles
then
render_style := default_render_style;
endif;
sqlCommand := "@type=" || SQL(reference_type);
referenceType := OBJECT [ id, author, title, journal_abbrevation, year_complete, volumn_issue, pages ];
// Determine which SQL parameters are needed to retrieve the data
if reference_type = "ddi" AND conflict_textId is not null
then
sqlCommand := sqlCommand || ", @conflictId=" || SQL(conflict_textId);
elseif reference_type = "drgint" AND drug_number1 is not null AND drug_number2 is not null
then
sqlCommand := sqlCommand || ", @drugId_1=" || SQL(drug_number1) ||
", @drugId_2=" || SQL(drug_number2);
elseif reference_type = "allrgy" AND allergenID is not null
then
sqlCommand := sqlCommand || ", @allergenID=" || SQL(allergenID);
elseif reference_type = "preglact" AND drug_number1 is not null
then
sqlCommand := sqlCommand || ", @drugId_1=" || SQL(drug_number1) || ", @functionId=" || SQL(functionId);
else // Invalid reference type
sqlCommand := null;
endif;
// Retrieve the data from the Multum database
if sqlCommand is not NULL
then
reference_list := read as referenceType { "exec SXACDSMultumReferenceSelPr " || sqlCommand };
//debug_sql := "exec SXACDSMultumReferenceSelPr " || sqlCommand;
// Get the last revision date of the Multum database, strip out time portion
revision_date := read last { "select change_date from SXAMTdatabase_infoSYN" };
revision_date := revision_date formatted with "%.2t";
endif;
;;
priority: 50
;;
evoke:
;;
logic:
refCounter := 0;
titleString := null;
outputString := null;
if not exists reference_list
then
conclude true;
endif;
// ---------------------------------------------------------
// Vancouver format style
// ---------------------------------------------------------
if reference_title is not null and length(reference_title) > 0
then
if render_style = "rtf"
then
titleString := "{{+B}}{{+g}}" || reference_title || "{{-g}}{{-B}}\n";
elseif render_style = "none"
then
titleString := reference_title || "\n";
endif;
endif;
// Build up a single reference for each row returned from Multum
for reference in reference_list do
singleReference := "";
refCounter := refCounter + 1;
if refCounter = 1 and titleString is not null then
outputString := titleString;
endif;
// Cleanup the data first
if reference.journal_abbrevation = "O" then reference.journal_abbrevation := null; endif;
if reference.year_complete = "0" then reference.year_complete := null; endif;
if reference.volumn_issue = "0" then reference.volumn_issue := null; endif;
if reference.pages = "0" then reference.pages := null; endif;
if reference.Author is not null and length(reference.Author) > 0
then
singleReference := reference.Author || ". ";
endif;
// Title is never null in the Multum database
singleReference := singleReference || reference.title || " ";
if reference.journal_abbrevation is not null and length(reference.journal_abbrevation) > 0
then
singleReference := singleReference || reference.journal_abbrevation || " ";
endif;
if reference.year_complete is not null and length(reference.year_complete) > 0
then
singleReference := singleReference || reference.year_complete || "; ";
endif;
if reference.volumn_issue is not null and length(reference.volumn_issue) > 0
then
singleReference := singleReference || reference.volumn_issue || ": ";
endif;
if reference.pages is not null and length(reference.pages) > 0
then
singleReference := singleReference || reference.pages || ". ";
endif;
if render_style is in ("rtf", "none")
then
singleReference := singleReference || "\n\n"; // double spacing between references
endif;
// Build up the final reference string
if outputString is null
then
outputString := refCounter || ". " ||singleReference;
else
outputString := outputString || refCounter || ". " || singleReference;
endif;
enddo;
if outputString is not null
then
if render_style is in ("rtf", "none")
then
outputString := outputString || "\n";
endif;
endif;
conclude true;
;;
action:
return outputString, revision_date, refCounter;
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,179 @@
maintenance:
title: Alert Messages for Duplicate Order Set Checking MLM;;
mlmname: STD_FUNC_ORDER_SET_DUP_MESSAGES;;
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: Selects the appropriate alert message for the Duplicate Order Set
Checking MLM{{{SINGLE-QUOTE}}}s alerts.
;;
explanation: The number of possible messages for the Duplicate Order Set
Checking MLM can be large. This MLM encapsulates the messages, so that all
changes to the messages can be done in one MLM.
;;
keywords: Duplicate Order Set; Alert; Message;
;;
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;
/********************************************************************************/
(order_set_name,
exact_msg,
performed_msg,
scheduled_msg,
exact_type,
subset_type,
superset_type,
same_set_type,
partial_match_type,
no_std_message_type,
matching_name_list,
matching_start_date_list,
matching_msg_type_list,
matching_msg_text_list,
matching_time_msg_list,
matching_order_set_status_list ):= ARGUMENT;
;;
evoke:
;;
logic:
indent_string:= " ";
hyphen_string:= "-----";
/*---------------------------------*/
/* Picks the correct alert message */
/*---------------------------------*/
//Initialize variables
long_alert_msg:= "";
short_message := "";
matching_short_message_list := ();
processing_list:= 1 seqto (count matching_name_list);
for k in processing_list do
/* Gets duplicate order_set information */
dup_order_set_found:= processing_list = k;
dup_order_set_name:= first (matching_name_list where dup_order_set_found);
dup_order_set_start_date:= first (matching_start_date_list
where dup_order_set_found);
dup_order_set_msg_type:= first (matching_msg_type_list where dup_order_set_found);
dup_order_set_msg_text:= first (matching_msg_text_list where dup_order_set_found);
dup_order_set_time_msg:= first (matching_time_msg_list where dup_order_set_found);
dup_order_set_type_code:= first (matching_order_set_type_code_list where dup_order_set_found);
/* Format date, removing milliseconds */
if exist dup_order_set_start_date then
dup_order_set_start_date_formatted := dup_order_set_start_date formatted with "%.4t";
endif;
/* Eliminates NULLs from printing in the alert message */
if dup_order_set_msg_text is null
then dup_order_set_msg_text:= "";
endif; /* if dup_order_set_msg_text is null */
/* Creates the beginning of the long alert message */
long_alert_msg:= long_alert_msg
|| dup_order_set_name || "\n"
|| "Date: " || dup_order_set_start_date_formatted || "\n" ;
/* Creates the rest of the long alert message */
If dup_order_set_msg_type = exact_type
then
short_message :=
"Warning potential duplicate - a " || dup_order_set_name
|| " has already been ordered on "
|| dup_order_set_start_date_formatted || ". "
|| dup_order_set_msg_text
;
elseif dup_order_set_msg_type = subset_type
then
short_message :=
"Warning - potential duplicate - a " || dup_order_set_name
|| " has already been ordered on "
|| dup_order_set_start_date_formatted
|| ". All the items of a " || order_set_name
|| " are included in a " || dup_order_set_name || ". "
|| dup_order_set_msg_text
;
elseif dup_order_set_msg_type = superset_type
then
short_message :=
"Warning - potential duplicate - a " || dup_order_set_name
|| " which includes a " || order_set_name
|| " has already been ordered on "
|| dup_order_set_start_date_formatted || ". "
|| dup_order_set_msg_text
;
elseif dup_order_set_msg_type = partial_match_type
then
short_message :=
"Warning - potential duplicate - a " || dup_order_set_name
|| " which included most of the items in a " || order_set_name
|| " has already been ordered on "
|| dup_order_set_start_date_formatted || ". "
|| dup_order_set_msg_text
;
elseif dup_order_set_msg_type = same_set_type
then
short_message :=
"An order set for " || dup_order_set_name
|| " which is of the same type"
|| " as your order set for " || order_set_name
|| " has already been ordered on "
|| dup_order_set_start_date_formatted
|| ". "
|| dup_order_set_msg_text
;
elseif dup_order_set_msg_type = no_std_message_type
then
short_message :=
dup_order_set_msg_text
;
else
short_message :=
"Error Message: Undefined Message Type for the order set."
;
endif; /*if dup_order_set_msg_type */
//Add the Message to the lists
matching_short_message_list := matching_short_message_list, short_message;
long_alert_msg:= long_alert_msg ||short_message || "\n\n";
enddo; /* for k */
/* Always conclude true to return values to the calling program */
conclude true;
;;
action:
RETURN ( long_alert_msg, matching_short_message_list );
;;
end:

View File

@@ -0,0 +1,173 @@
maintenance:
title: Order Retrievals for Duplicate Order Set Checking;;
mlmname: STD_FUNC_ORDER_SET_DUP_RETRIEVE;;
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: Retrieves the UNSUBMITTED and DATABASE order sets according to the rules
stated in std_duplicate_order_set.mlm. Returns order information to the
std_func_order_set_dup_rules.mlm.
;;
explanation: See the explanation in std_duplicate_order_set.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;
/********************************************************************************/
/* Arguments that are passed by the calling MLM */
(client_guid,
chart_guid,
client_visit_guid,
order_set_guid,
order_set_name,
order_set_scope,
past_time,
future_time ):= ARGUMENT;
/* ScopeLevel from the duplicate policy */
/* 1 = This Visit, 2 = This Chart, 3 = All Charts */
ScopeLevel := 0;
If exist client_guid
then
/* Sets variable values to retrieve order sets from the database */
If order_set_scope = "This Chart"
then
ScopeLevel := 2;
elseif order_set_scope = "This Visit"
then
ScopeLevel := 1;
else
ScopeLevel := 3;
endif; /* order_set_scope */
/*----------------------------------*/
/* Gets the UNSUBMITTED ORDER SETS */
/*----------------------------------*/
(unsub_order_set_name_list,
unsub_order_set_guid_list,
unsub_start_date_list,
unsub_order_set_type_code_list,
unsub_master_GUID_list,
unsub_this_list ):= read
{Unsubmitted OrderSet:
OrderSetName, GUID, StartDtm,
OrderSetType, OrderCatalogSetGUID, THIS
WHERE StartDtm >= past_time
AND StartDtm <= future_time
AND ParentOrderSetGUID IS NULL
AND GUID <> order_set_guid
};
/*------------------------------*/
/* Gets the DATABASE ORDER SETS */
/*------------------------------*/
(db_order_set_name_list,
db_order_set_guid_list,
db_start_date_list,
db_order_set_type_code_list,
db_master_GUID_list ):= read
{ "EXEC SCMDuplicateOrderSetCheckingPR "
|| SQLEX(order_set_guid) || " ,"
|| SQLEX(client_guid) || " ,"
|| SQLEX(chart_guid) || " ,"
|| SQLEX(client_visit_guid) || " ,"
|| SQLEX(past_time) || " ,"
|| SQLEX(future_time)|| " ,"
|| SQLEX(ScopeLevel)
, PrimaryTime = StartDtm};
endif; /* If exist client_guid */
;;
evoke:
;;
logic:
If NOT exist db_order_set_name_list
AND NOT exist unsub_order_set_name_list
then conclude false;
endif;
/*-----------------------*/
/* Initializes Variables */
/*-----------------------*/
order_set_name_list:= ();
order_set_guid_list:= ();
start_date_list:= ();
order_set_type_code_list:= ();
master_GUID_list:= ();
/*-----------------------------------------------------------------*/
/* Combines information on "unsubmitted" and "database" order sets */
/*-----------------------------------------------------------------*/
/*--------------------------------*/
/* Process UNSUBMITTED order sets */
/*--------------------------------*/
If exist unsub_master_guid_list
then
/* Add the UNSUBMITTED order sets onto the lists for processing */
order_set_name_list:= order_set_name_list, unsub_order_set_name_list ;
order_set_guid_list:= order_set_guid_list, unsub_order_set_guid_list ;
start_date_list:= start_date_list, unsub_start_date_list ;
order_set_type_code_list:= order_set_type_code_list, unsub_order_set_type_code_list ;
master_GUID_list:= master_GUID_list, unsub_master_GUID_list ;
endif; /* if (exist unsub_master_guid_list) */
/*-----------------------------*/
/* Process DATABASE order sets */
/*-----------------------------*/
If exist db_master_guid_list
then
/* Add the order_sets retrieved from the database onto the lists for processing */
order_set_name_list:= order_set_name_list, db_order_set_name_list ;
order_set_guid_list:= order_set_guid_list, db_order_set_guid_list ;
start_date_list:= start_date_list, db_start_date_list ;
order_set_type_code_list:= order_set_type_code_list, db_order_set_type_code_list ;
master_GUID_list:= master_GUID_list, db_master_GUID_list ;
endif; /* if (exist db_master_guid_list)or... */
/*--------------------------------------------------------*/
/* Conclude True to Return Information to the Calling MLM */
/*--------------------------------------------------------*/
conclude true;
;;
action:
Return ( order_set_name_list,
order_set_guid_list,
start_date_list,
order_set_type_code_list,
master_GUID_list
);
;;
end:

View File

@@ -0,0 +1,328 @@
maintenance:
title: Rules for Duplicate Order Set Checking;;
mlmname: STD_FUNC_ORDER_SET_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_order_set.mlm.
Returns information on the duplicate orders to std_duplicate_order_set.mlm.
;;
explanation: See the explanation in std_duplicate_order_set.mlm
;;
keywords: Duplicate Order Set;
;;
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;
/********************************************************************************/
/* Do Not Changes these Internal MLM Variables */
exact_msg:= "exact";
performed_msg:= "performed";
scheduled_msg:= "scheduled";
exact_type:= "exact";
subset_type:= "subset";
superset_type:= "superset";
same_set_type:= "same set type";
partial_match_type:= "partial match";
no_std_message_type:= "no std message";
/*==============================================================================*/
(order_set_name,
order_set_guid,
order_set_catalog_guid,
chart_guid,
client_visit_guid,
order_set_start_date,
patient_loc_group):= ARGUMENT;
/* Declares MLMs which can be called */
calc_duration:= MLM {{{SINGLE-QUOTE}}}std_func_dup_duration{{{SINGLE-QUOTE}}};
get_order_sets:= MLM {{{SINGLE-QUOTE}}}std_func_order_set_dup_retrieve{{{SINGLE-QUOTE}}};
/* Gets the Client GUID */
client_guid := read last {ClientInfo: GUID};
/* Gets the evoking order set{{{SINGLE-QUOTE}}}s Catalog information */
(catalog_name,
duplicate_policy_guid ):= read last
{"SELECT Name, DuplicatePolicyGUID "
|| " FROM CV3OrderCatalogSet "
|| " WHERE GUID = " || SQL(order_set_catalog_guid)
|| " AND Active = 1 "};
/* Continue if "check for duplicates" is marked in the Item-Catalog */
If exist duplicate_policy_guid
then
/* Gets evoking order set{{{SINGLE-QUOTE}}}s duplicate policy information */
(order_set_loc_group_guid_list,
order_set_scope_list,
order_set_performed_time_list,
order_set_performed_unit_list,
order_set_exact_time_list,
order_set_exact_unit_list,
order_set_scheduled_time_list,
order_set_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_set_scope_list
then
If any (patient_loc_group = order_set_loc_group_guid_list)
then
loc_group_found := patient_loc_group = order_set_loc_group_guid_list;
else
loc_group_found := order_set_loc_group_guid_list is null;
endif;
loc_is_excluded := last (loc_is_excluded_list where loc_group_found);
endif; /* if exist order_set_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_set_loc_grp:= last (order_set_loc_group_guid_list where loc_group_found);
order_set_scope:= last (order_set_scope_list where loc_group_found);
order_set_performed_time:= last (order_set_performed_time_list where loc_group_found);
order_set_performed_unit:= last (order_set_performed_unit_list where loc_group_found);
order_set_exact_time:= last (order_set_exact_time_list where loc_group_found);
order_set_exact_unit:= last (order_set_exact_unit_list where loc_group_found);
order_set_scheduled_time:= last (order_set_scheduled_time_list where loc_group_found);
order_set_scheduled_unit:= last (order_set_scheduled_unit_list where loc_group_found);
/*-------------------------------------*/
/* Converts EXACT TIME into Arden Time */
/*-------------------------------------*/
If order_set_exact_time > 0 and order_set_exact_unit is string
then
exact_duration:= call calc_duration with
(order_set_exact_time, order_set_exact_unit);
If order_set_exact_unit = "days"
then exact_low_time:= (day floor of order_set_start_date)
- exact_duration ;
exact_high_time:= (day floor of order_set_start_date)
+ exact_duration + (1 day) - (1 second);
else exact_low_time:= order_set_start_date - exact_duration;
exact_high_time:= order_set_start_date + exact_duration;
endif; /* if order_set_exact_unit = */
else
exact_low_time:= order_set_start_date;
exact_high_time:= order_set_start_date;
endif; /* if order_set_exact_time > 0 ...*/
/*-----------------------------------------*/
/* Converts PERFORMED TIME into Arden Time */
/*-----------------------------------------*/
If order_set_performed_time > 0 and order_set_performed_unit is string
then
performed_duration:= call calc_duration with
(order_set_performed_time, order_set_performed_unit);
If order_set_performed_unit = "days"
then past_time:= (day floor of order_set_start_date)
- performed_duration;
else past_time:= order_set_start_date - performed_duration;
endif; /* if order_set_performed_unit = */
else
past_time:= exact_low_time;
endif; /* if order_set_performed_time > 0 ...*/
/*-----------------------------------------*/
/* Converts SCHEDULED TIME into Arden Time */
/*-----------------------------------------*/
If order_set_scheduled_time > 0 and order_set_scheduled_unit is string
then
scheduled_duration:= call calc_duration with
(order_set_scheduled_time, order_set_scheduled_unit);
If order_set_scheduled_unit = "days"
then future_time:= (day floor of order_set_start_date)
+ scheduled_duration + (1 day) - (1 second);
else future_time:= order_set_start_date + scheduled_duration;
endif; /* if order_set_scheduled_unit = */
else
future_time:= exact_high_time;
endif; /* if order_set_scheduled_time > 0 ...*/
/* Gets the evoking order set{{{SINGLE-QUOTE}}}s list of duplicate sets */
/* in the Order Set Catalog */
(cat_dup_item_name_list,
cat_dup_item_guid_list,
cat_message_type_list,
cat_message_list) := read
{"SELECT DuplicateSetName, DuplicateSetGUID, "
|| " MessageType, MessageText "
|| " FROM CV3CatalogSetDuplicate "
|| " WHERE OrderCatalogSetGUID = " || SQL(order_set_catalog_guid)
|| " AND Active = 1 "};
/*--------------------------------------------------------------------------*/
/* Retrieve the order sets from the DATABASE and the UNSUBMITTED order sets */
/*--------------------------------------------------------------------------*/
(order_set_name_list,
order_set_guid_list,
start_date_list,
order_set_type_code_list,
master_GUID_list ):= call get_order_sets with
(client_guid,
chart_guid,
client_visit_guid,
order_set_guid,
order_set_name,
order_set_scope,
past_time,
future_time );
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_set_guid_list:= ();
matching_start_date_list:= ();
matching_msg_type_list:= ();
matching_msg_text_list:= ();
matching_time_msg_list:= ();
matching_order_set_type_code_list:= ();
dup_item_guid_list:= cat_dup_item_guid_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 (order_set_catalog_guid is not in dup_item_guid_list)
and (order_set_catalog_guid is in master_guid_list)
then
dup_item_guid_list:= order_set_catalog_guid, dup_item_guid_list;
message_type_list:= exact_type, message_type_list;
message_list:= null, message_list;
endif; /* if order_set_catalog_guid is not in... */
/*------------------------------------------------*/
/* Finds all possible duplicates among the ITEMS */
/*------------------------------------------------*/
If any(dup_item_guid_list is in master_guid_list)
then
for item_master_guid in dup_item_guid_list do
master_guid_found:= item_master_guid = master_guid_list;
temp_guid:= master_guid_list where master_guid_found;
temp_name:= order_set_name_list where master_guid_found;
temp_order_set_guid:= order_set_guid_list where master_guid_found;
temp_start_date:= start_date_list where master_guid_found;
temp_type_code:= order_set_type_code_list where master_guid_found;
matching_guid_list:= matching_guid_list, temp_guid;
matching_name_list:= matching_name_list, temp_name;
matching_order_set_guid_list:= matching_order_set_guid_list, temp_order_set_guid;
matching_start_date_list:= matching_start_date_list, temp_start_date;
matching_order_set_type_code_list:= matching_order_set_type_code_list, temp_type_code;
/* Find associated message type and message text */
For K in temp_guid do
item_guid_found:= dup_item_guid_list = K;
temp_msg_type:= first(message_type_list where item_guid_found);
temp_msg_text:= first(message_list where item_guid_found);
matching_msg_type_list:= matching_msg_type_list, temp_msg_type;
matching_msg_text_list:= matching_msg_text_list, temp_msg_text;
/* Set the time messages */
order_set_time:= time of K;
relative_date:= now;
If order_set_time >= exact_low_time AND order_set_time <= exact_high_time
then correct_msg:= exact_msg;
elseif order_set_time < relative_date
then correct_msg:= performed_msg;
elseif order_set_time > relative_date
then correct_msg:= scheduled_msg;
else correct_msg:= null;
endif; /* if order_set_time */
matching_time_msg_list:= matching_time_msg_list, correct_msg;
enddo; /* for K */
enddo; /* for item_master_guid...*/
endif; /* if any(dup_item_guid_list...*/
/*--------------------------------------------------*/
/* 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_set_type,
partial_match_type,
no_std_message_type,
matching_name_list,
matching_order_set_guid_list,
matching_start_date_list,
matching_msg_type_list,
matching_msg_text_list,
matching_time_msg_list,
matching_order_set_type_code_list );
;;
end:

View File

@@ -0,0 +1,162 @@
maintenance:
title: Results retrieved for matching result name within a given interval;;
mlmname: STD_FUNC_RETRIEVE_MATCHING_RESULTS;;
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: Retrieves a list of valid numeric results to return to the calling MLM.
Note, values such as "specimen hemolyzed", ">500", or "2+" are not
considered valid numeric results.
;;
explanation: This MLM processes information received to return matching results
from the database or the current result returned via HL7.
The retrieval is performed based on a SQL query or a pointer to the object.
If a pointer is sent in from the calling MLM, an object query for the
current result is performed. If a pointer is not sent, then a SQL query is
performed based on the chart guid, visit guid, present time and past interval.
This information is sent by the calling MLM in the following parameters:
- client guid used for SQL search
- chart guid used for SQL search,
- visit guid used for SQL search
- start range for SQL search
- end range for SQL search
- result name string used for SQL query OR pointer used for Object
- result scope whether all charts, this visit or this chart
This MLM returns lists of result information that contain:
- the result guid,
- chart guid for that result,
- visit guid for that result,
- the result name,
- the performed date and time for the result,
- any text for the result,
- the unit of measure for the result,
- the result value as a string,
- the most recent result found in the database as a number,
- the current result as just received via HL7 as a number;
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(client_guid, // Client guid used for SQL search
chart_guid, // Chart guid used for SQL search,
client_visit_guid, // Visit guid used for SQL search
present_time, // End range for SQL search, could be the last PerformedDtm
past_time, // Start range for SQL search, could be the first PerformedDtm
result_info, // String used for SQL query (result item name) or pointer used for Object
result_scope, // Indicator to check all visits, this visit, or this chart.
include_community // Indicator to include community results. Only applicable to "All" scope
)
:= ARGUMENT;
if exists include_community then
local_include_community := include_community;
else
local_include_community := FALSE;
endif;
if result_info is string
then
// Get result data from database using SQL
(result_guid,
result_name,
result_dtm,
result_str,
result_uom,
result_value_str,
result_community_source) := read
{ "Execute CV3ResultsForCDSMatchingFnSelPr "
|| " @ClientGUID = " || SQL(client_guid)
|| ", @ChartGUID = " || SQL(chart_guid)
|| ", @ClientvisitGUID = " || SQL(client_visit_guid)
|| ", @Scope= " || sql(result_scope)
|| ", @PerformedDtmFrom = " || sql(past_time)
|| ", @ItemName = " || sql(result_info) ||", @IncludeCmty = " || sql(local_include_community),
PrimaryTime = PerformedDtm};
// Convert result values in string to number
converted_results := result_value_str as number;
// Set found index to positions where valid numeric result is found
found_valid_result := converted_results is number;
// Set lists to inlcude data for only valid numeric results
result_guid := result_guid where found_valid_result;
result_name := result_name where found_valid_result;
result_dtm := result_dtm where found_valid_result;
result_str := result_str where found_valid_result;
result_uom := result_uom where found_valid_result;
result_value_str := result_value_str where found_valid_result;
result_community_source := result_community_source where found_valid_result;
// Set most recent result;
recent_last_result := last(result_value_str) as number;
elseif exist result_info
then
// Get result information from the object
(result_guid,
result_chart_guid,
result_visit_guid,
result_name,
result_dtm,
result_str,
result_uom,
result_value_str) := read last
{Observation: GUID, ChartGUID, ClientVisitGUID, Itemname,
PerformedDtm, Text, UnitOfMeasure, Value
REFERENCING result_info};
// Convert current result value in string to number
current_result := result_value_str as number;
endif;
;;
evoke:
;;
logic:
if exist result_info
then conclude TRUE;
else conclude FALSE;
endif;
;;
action:
return
result_guid,
result_chart_guid,
result_visit_guid,
result_name,
result_dtm,
result_str,
result_uom,
result_value_str,
recent_last_result,
current_result,
result_community_source;
;;
end:

View File

@@ -0,0 +1,752 @@
maintenance:
title: Active medications retrieved with class type and value matching result;;
mlmname: STD_FUNC_RETRIEVE_MEDICATIONS;;
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: Retrieves a list of medications to return to the calling MLM.
;;
explanation: This MLM processes information received to return matching medications
from the database or the current result returned via HL7.
The retrieval is performed based on a SQL query or a pointer to the object.
If a pointer is sent in from the calling MLM, an object query for the
current order is performed.
If a pointer is not sent, then a SQL query is performed based on the chart
guid, visit guid, and a list of medications or a list of class types and
values. All active orders that match are returned.
If a pointer is sent, the order pointed to is compared to a list of medications
or class types and values. If the order matches the information is returned.
This information is received from the calling MLM in the following parameters:
- a STRING indicating SQL query
OR
- pointer to Evoking Object
AND
- a list of medications to match
OR
- a list of class types and values to match
AND
- a client guid
AND
- a chart guid to match
OR
- a visit guid to match
This MLM returns lists of medication order information that contain:
- an indicator for whether this is an order or component,
- the chart guid of the order,
- the client guid of the order,
- the visit guid of the order,
- the high dosage for the order,
- the low dosage for the order,
- the date and time the order was entered,
- the form of the medication, ie, {{{SINGLE-QUOTE}}}Tablet{{{SINGLE-QUOTE}}}
- the frequency for the order,
- the order guid,
- a flag for whether the order is conditional,
- a flag for whether the order is held,
- a flag for whether the order is prn,
- a flag for whether the order is suspended,
- the order name,
- the order catalog master item guid,
- the order priority,
- the order route,
- the order status code,
- the order status description as defined by the site,
- the order status level number,
- the requested date and time of the order,
- the significant date and time(requested, scheduled, or performed,
- the stop date and time of the order,
- the order summary line as defined by the site,
- the associated system order priority,
- the unit of measure for the order,
- a flag indicating whether this order is a match;
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
(med_info, // STRING indicating SQL query or pointer to Evoking Object
medications_list, // Only return information on medications in this list
// If Null, returns all active medications for scope/class
class_type, // Class type list used to validate against via SQL query
// If Null, returns all active medications for scope/med list)
class_value, // Class value used to validate against via SQL query
// If Null returns all active medications for scope/med list)
client_guid, // Chart Guid used to filter db query
chart_guid, // Chart Guid used to filter db query if medication_scope = Chart
client_visit_guid, // Visit Guid used to filter db query if medication_scope = Visit
medication_scope) // Indicator to check all visits, this visit, or this chart.
:= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
/* Set this flag to true to include historical session type orders
when checking the current order */
include_historical_session_type_orders := FALSE;
/* Set this flag to false to exclude discharge session type orders
when checking the current order */
include_discharge_session_type_orders := TRUE;
/* Set this flag to false to exclude standard session type orders
when checking the current order */
include_in_house_session_type_orders := TRUE;
/* Set this flag to false to exclude outpatient rx type orders
when checking the current order */
include_outpatient_rx_session_type_orders := TRUE;
/* Set this flag to false to exclude outpatient hx type orders
when checking the current order */
include_outpatient_hx_session_type_orders := FALSE;
/* Declare MLMs that can be called */
func_session_type_filter := MLM {{{SINGLE-QUOTE}}}STD_FUNC_SESSION_TYPE_FILTER{{{SINGLE-QUOTE}}};
if med_info is string then
// Set scope for SQL search
if medication_scope = "All" then
scope_info := " WHERE O.ClientGUID = " || SQL(client_guid);
elseif medication_scope = "Chart" then
scope_info := " WHERE O.ClientGUID = " || SQL(client_guid) ||
" AND O.ChartGUID = " || SQL(chart_guid);
else
scope_info := " WHERE O.ClientGUID = " || SQL(client_guid) ||
" AND O.ChartGUID = " || SQL(chart_guid) ||
" AND O.ClientVisitGUID = " || SQL(client_visit_guid);
endif; // Set scope for SQL search
if exist medications_list
then
// Set the med list into a string so it can be used in the
// "Where" statement below to return current ORDERS
sql_medications_list_string := "";
counter:= 0;
for temp_med in medications_list do
counter:= counter + 1;
If counter = 1
then
sql_medications_list_string := "(" || SQL(temp_med) || ")";
else
sql_medications_list_string := sql_medications_list_string || ", (" || SQL(temp_med) || ")";
endif;
enddo;
order_med_list_filter:= " AND Exists (select 1 from @Tmp T where CV3OrderComponent.Name = T.Name OR CV3Order.Name = T.Name) ";
component_med_list_filter:= " AND Exists (select 1 from @Tmp T where CV3OrderComponent.Name = T.Name) ";
elseif exist class_type and exist class_value
then
if exist class_value then
// Set the med list into a string so it can be used in the
// "Where" statement below to return current ORDERS
sql_class_value_string := "";
counter := 0;
for temp_value in class_value do
counter := counter + 1;
If counter = 1
then
sql_class_value_string := SQL(temp_value);
else
sql_class_value_string := sql_class_value_string || ", " || SQL(temp_value);
endif;
enddo;
// Set up the SQL query for the order items and their components
// that match the classes and values
order_med_list_filter:= " AND CV3CatalogClassTypeValue.Value IN ("
|| sql_class_value_string || " )"
|| " AND CV3CatalogClassTypeValue.ClassTypeGUID = "
|| "(SELECT guid from CV3ClassType where Code ="
|| SQL(class_type)||")";
component_med_list_filter:= " AND CV3CatalogClassTypeValue.Value IN ("
|| sql_class_value_string || " )"
|| " AND CV3CatalogClassTypeValue.ClassTypeGUID = "
|| "(SELECT guid from CV3ClassType where Code = "
|| SQL(class_type)||")" ;
endif;
endif;
if (sql_medications_list_string is null) OR (sql_medications_list_string = "") then
sql_insert_values_string := " ";
else
sql_insert_values_string := " INSERT INTO @Tmp VALUES " || sql_medications_list_string;
endif;
sql_query1 := "DECLARE @Tmp TABLE (Name varchar(200) primary key) "
|| sql_insert_values_string
|| " SELECT an_order_or_component = {{{SINGLE-QUOTE}}}order{{{SINGLE-QUOTE}}}, O.ChartGUID, "
|| " O.ClientGUID, O.ClientVisitGUID, "
|| " CombinedDoseHigh = DosageHigh, CombinedDose = DosageLow, Entered, "
|| " CombinedForm = FormCode, FrequencyCode, O.GUID, IsConditional, "
|| " IsHeld, IsPRN, IsSuspended, CombinedName = O.Name, "
|| " CombinedOCMItemGUID = O.OrderCatalogMasterItemGUID, "
|| " OrderPriorityCode, CombinedRoute = OrderRouteCode, "
|| " OrderStatusCode, CV3OrderStatus.Description, OrderStatusLevelNum, "
|| " RequestedDtm, SignificantDtm, StopDtm, CombinedSummary = SummaryLine,"
|| " SystemOrderPriorityCode, CombinedUOM = CV3MedicationExtension.UOM "
|| " FROM CV3AllOrdersVw as O " || " JOIN CV3MedicationExtension "
|| " ON O.GUID = CV3MedicationExtension.GUID "
|| " LEFT OUTER JOIN CV3OrderComponent "
|| " ON (O.ClientGUID = CV3OrderComponent.ClientGUID "
|| " AND O.GUID = CV3OrderComponent.OrderGUID) "
|| " LEFT OUTER JOIN CV3OrderAddnlInfo AS OAI "
|| " ON ( O.ClientGUID = OAI.ClientGUID AND O.GUID = OAI.GUID ) "
|| " JOIN CV3CatalogClassTypeValue "
|| " ON (O.OrderCatalogMasterItemGUID = CV3CatalogClassTypeValue.CatalogMasterGUID "
|| " OR CV3OrderComponent.OrderCatalogMasterItemGUID = CV3CatalogClassTypeValue.CatalogMasterGUID) "
|| " JOIN CV3OrderStatus "
|| " ON O.OrderStatusCode = CV3OrderStatus.Code"
|| scope_info
|| " AND O.TypeCode = {{{SINGLE-QUOTE}}}Medication{{{SINGLE-QUOTE}}} "
|| " AND OrderStatusLevelNum <= 50 "
|| order_med_list_filter;
sql_query2 := " UNION "
|| " SELECT an_order_or_component = {{{SINGLE-QUOTE}}}component{{{SINGLE-QUOTE}}}, O.ChartGUID, "
|| " O.ClientGUID, O.ClientVisitGUID, "
|| " CombinedDoseHigh = NULL, CombinedDose = CV3OrderComponent.Dosage,"
|| " Entered, CombinedForm = NULL, FrequencyCode, O.GUID, "
|| " IsConditional, IsHeld, IsPRN, IsSuspended, "
|| " CombinedName = CV3OrderComponent.Name,"
|| " CombinedOCMItemGUID = CV3OrderComponent.OrderCatalogMasterItemGUID, "
|| " OrderPriorityCode, CombinedRoute = NULL, OrderStatusCode, "
|| " CV3OrderStatus.Description, OrderStatusLevelNum, RequestedDtm, "
|| " SignificantDtm, StopDtm = NULL, CombinedSummary = NULL,"
|| " SystemOrderPriorityCode, CombinedUOM = CV3OrderComponent.UOM "
|| " FROM CV3AllOrdersVw as O " || " JOIN CV3OrderComponent "
|| " ON (O.ClientGUID = CV3OrderComponent.ClientGUID "
|| " AND O.GUID = CV3OrderComponent.OrderGUID ) "
|| " LEFT OUTER JOIN CV3OrderAddnlInfo AS OAI "
|| " ON ( O.ClientGUID = OAI.ClientGUID AND O.GUID = OAI.GUID ) "
|| " JOIN CV3CatalogClassTypeValue "
|| " ON CV3OrderComponent.OrderCatalogMasterItemGUID = CV3CatalogClassTypeValue.CatalogMasterGUID "
|| " JOIN CV3OrderStatus "
|| " ON O.OrderStatusCode = CV3OrderStatus.Code "
|| scope_info
|| " AND O.TypeCode = {{{SINGLE-QUOTE}}}Medication{{{SINGLE-QUOTE}}} "
|| " AND OrderStatusLevelNum <= 50 "
|| " AND (CV3OrderComponent.Type = 0 "
|| " OR CV3OrderComponent.Type = 3) "
|| component_med_list_filter;
if (not include_in_house_session_type_orders)
then
sql_query1 := sql_query1 || " AND (O.AlternateOrderType <> 0 OR O.IsForDischarge = 1) ";
sql_query2 := sql_query2 || " AND (O.AlternateOrderType <> 0 OR O.IsForDischarge = 1) ";
endif;
if (not include_historical_session_type_orders)
then
sql_query1 := sql_query1 || " AND O.AlternateOrderType <> 1 ";
sql_query2 := sql_query2 || " AND O.AlternateOrderType <> 1 ";
endif;
if (not include_discharge_session_type_orders)
then
sql_query1 := sql_query1 || " AND O.IsForDischarge = 0 ";
sql_query2 := sql_query2 || " AND O.IsForDischarge = 0 ";
endif;
if (not include_outpatient_rx_session_type_orders)
then
sql_query1 := sql_query1 || " AND NOT(O.AlternateOrderType = 2 AND OAI.IsScript = 1) ";
sql_query2 := sql_query2 || " AND NOT(O.AlternateOrderType = 2 AND OAI.IsScript = 1) ";
endif;
if (not include_outpatient_hx_session_type_orders)
then
sql_query1 := sql_query1 || " AND NOT(O.AlternateOrderType = 2 AND OAI.IsScript = 0) ";
sql_query2 := sql_query2 || " AND NOT(O.AlternateOrderType = 2 AND OAI.IsScript = 0) ";
endif;
// Get medication orders(including additives) from DB using SQL query
(an_order_or_component,
chart_guid,
client_guid,
client_visit_guid,
dosage_high,
dosage_low,
entereddtm,
form_code,
frequency_code,
guid,
is_conditional,
is_held,
is_prn,
is_suspend,
name,
order_catalog_master_item_guid,
order_priority_code,
order_route_code,
order_status_code,
order_status_desc,
order_status_level_num,
request_dtm,
significant_dtm,
stop_dtm,
summary_line,
system_order_priority_code,
uom) := read { " " || sql_query1 || sql_query2 || " order by SignificantDtm, O.GUID, an_order_or_component desc, CombinedName" };
//,PrimaryTime = SignificantDtm };
//end - Get medication orders(including additives) from DB using SQL query
// Initialize variables
match_med_found := ();
item_class_value := ();
// For each item indicate whether the item or component is the match.
// Mark matches found for medication lists
if exist medications_list then
list_index := 1 seqto (count name);
for A in list_index do
temp_name := last(first A from name);
if temp_name is in (medications_list) then
match_med_found := match_med_found, TRUE;
else
match_med_found := match_med_found, FALSE;
endif;
enddo;
// Mark matches found for class types
elseif exists class_type then
list_index := 1 seqto (count name);
for A in list_index do
// Get the Master GUID for this component item
temp_ocmi_guid := last(first A from order_catalog_master_item_guid);
temp_name := last(first A from name);
// Get the real class type and value for each item returned on lists
(the_name,
the_type,
the_value)
:= read
{" SELECT Name, Code, Value "
|| " FROM CV3OrderCatalogMasterItem LEFT OUTER JOIN CV3CatalogClassTypeValue "
|| " ON CV3OrderCatalogMasterItem.GUID = CV3CatalogClassTypeValue.CatalogMasterGUID "
|| " JOIN CV3ClassType "
|| " ON CV3ClassType.GUID = CV3CatalogClassTypeValue.ClassTypeGUID "
|| " WHERE CV3OrderCatalogMasterItem.GUID = "
|| SQL(temp_ocmi_guid )
|| " AND CV3ClassType.Code = "
|| SQL(class_type)};
if last(the_value) is in class_value
then
// Mark the match as found and add value to list
match_med_found := match_med_found, TRUE;
item_class_value := item_class_value, the_value;
else
// Mark the match as not found and set value to NULL
match_med_found := match_med_found, FALSE;
item_class_value := item_class_value, NULL;
endif;
enddo;
endif;
elseif exist med_info
then
//Get medication orders from object if the item name
// or the component name(additive) is in med filter list
//Initialize variables
chart_guid := ();
client_guid :=();
client_visit_guid := ();
dosage_high := ();
dosage_low := ();
entereddtm := ();
form_code := ();
frequency_code := ();
guid := ();
is_conditional := ();
is_held := ();
is_prn := ();
is_suspend := ();
name := ();
order_catalog_master_item_guid := ();
order_component := ();
order_route_code := ();
order_status_code := ();
order_status_desc := ();
order_status_level_num := ();
significant_dtm := ();
stop_dtm := ();
summary_line := ();
uom := ();
match_med_found := ();
item_class_value := ();
// Get main order data from Evoking Object
(temp_chart_guid,
temp_client_guid,
temp_client_visit_guid,
temp_dosage_high,
temp_dosage_low,
temp_entereddtm,
temp_form_code,
temp_frequency_code,
temp_guid,
temp_is_conditional,
temp_is_held,
temp_is_prn,
temp_is_suspended,
temp_order_name,
temp_order_catalog_master_item_guid,
temp_order_priority_code,
temp_order_component,
temp_order_route_code,
temp_order_status_code,
temp_order_status_level_num,
temp_request_dtm,
temp_significant_dtm,
temp_stop_dtm,
temp_summary_line,
temp_order_sys_priority,
temp_uom ) := read last
{Order: ChartGUID, ClientGUID, ClientVisitGUID,
DosageHigh, DosageLow, Entered, FormCode, FrequencyCode, GUID,
IsConditional, IsHeld, IsPRN, IsSuspended,
Name, OrderCatalogMasterItemGUID, OrderPriorityCode, OrderComponent,
OrderRouteCode, OrderStatusCode, OrderStatusLevelNum, RequestedDtm,
SignificantDtm, StopDtm, SummaryLine, SystemOrderPriorityCode, UOM
REFERENCING med_info };
// put the order definitions found into their place in the lists
an_order_or_component := "order";
chart_guid := temp_chart_guid;
client_guid := temp_client_guid;
client_visit_guid := temp_client_visit_guid;
dosage_high := temp_dosage_high;
dosage_low := temp_dosage_low;
entereddtm := temp_entereddtm;
form_code := temp_form_code;
frequency_code := temp_frequency_code;
guid := temp_guid;
is_conditional := temp_is_conditional;
is_held := temp_is_held;
is_prn := temp_is_prn;
is_suspend := temp_is_suspended;
name := temp_order_name;
order_catalog_master_item_guid := temp_order_catalog_master_item_guid;
order_priority_code := temp_order_priority_code;
order_route_code := temp_order_route_code;
order_status_code := temp_order_status_code;
order_status_desc := read
{"SELECT Description FROM CV3OrderStatus "
||"WHERE Code = "||SQL(temp_order_status_code)};
order_status_level_num := temp_order_status_level_num;
request_dtm := temp_request_dtm;
significant_dtm := temp_significant_dtm;
stop_dtm := temp_stop_dtm;
summary_line := temp_summary_line;
system_order_priority_code := temp_order_sys_priority;
uom := temp_uom;
// Check to see if medication list or class type is used
If exists medications_list then
// If order name in list, then set flag.
if name is in medications_list
then
match_med_found := (TRUE);
else
match_med_found := (FALSE);
endif;
else
if exists class_type then
(the_type,
the_value)
:= read
{" SELECT Code, Value "
||" FROM CV3OrderCatalogMasterItem JOIN CV3CatalogClassTypeValue "
||" ON CV3OrderCatalogMasterItem.GUID = CV3CatalogClassTypeValue.CatalogMasterGUID "
||" JOIN CV3ClassType "
||" ON CV3ClassType.GUID = CV3CatalogClassTypeValue.ClassTypeGUID "
||" WHERE CV3OrderCatalogMasterItem.GUID = "
||SQL(temp_order_catalog_master_item_guid)};
// If there is class assigned to the item, check to see if it is a match
if exists the_type then
class_index := 1 seqto (count the_type);
for I in class_index do
temp_med_class_type := last(first I from the_type);
temp_med_class_value := last(first I from the_value);
if temp_med_class_type = class_type then
if (temp_med_class_value is in class_value)
then
match_med_found := (TRUE);
item_class_value := (temp_med_class_value);
else
match_med_found := (FALSE);
item_class_value := (NULL);
endif;
endif;
// Mark as found if class and value match
enddo;
else
// If there is no class assigned to the item, set match to FALSE
match_med_found := (FALSE);
endif;
else
match_med_found := (FALSE);
item_class_value := (NULL);
endif;
endif;
// Retrieve medication IV Additive data if OrderComponent objects exist
if exist temp_order_component
then
// Get the additive names from order component object
(iv_dosage_list,
iv_dosage_to_list,
iv_name_list,
iv_order_catalog_master_item_guid_list,
iv_uom_list,
component_type) := read
{OrderComponent: Dosage, DosageTo, Name,
OrderCatalogMasterItemGUID, Uom, Type
REFERENCING temp_order_component
where (Dosage AS Number) > 0 };
index_iv := 1 seqto (count iv_name_list);
// Get additive list for those that match medications list
if exist medications_list then
for A in index_iv do
temp_iv_name := last(first A from iv_name_list);
if temp_iv_name is in medications_list then
// Synch the field lists of components to the order
an_order_or_component := an_order_or_component,"component";
chart_guid := chart_guid, temp_chart_guid;
client_guid := client_guid, temp_client_guid;
client_visit_guid := client_visit_guid, temp_client_visit_guid;
dosage_high := dosage_high, last(first A from iv_dosage_to_list);
dosage_low := dosage_low, last(first A from iv_dosage_list);
entereddtm := entereddtm, NULL;
form_code := form_code, NULL;
frequency_code := frequency_code, NULL;
guid := guid, temp_guid;
is_conditional := is_conditional, NULL;
is_held := is_held, NULL;
is_prn := is_prn, temp_is_prn;
is_suspend := is_suspend, NULL;
name := name, temp_iv_name;
order_catalog_master_item_guid := order_catalog_master_item_guid,
last(first A from iv_order_catalog_master_item_guid_list);
order_priority_code := order_priority_code, NULL;
order_route_code := order_route_code, NULL;
order_status_code := order_status_code, NULL;
order_status_desc := order_status_desc, NULL;
order_status_level_num := order_status_level_num, NULL;
request_dtm := request_dtm, NULL;
significant_dtm := significant_dtm, temp_significant_dtm;
stop_dtm := stop_dtm, temp_stop_dtm;
summary_line := summary_line, NULL;
system_order_priority_code := system_order_priority_code, NULL;
uom := uom, last(first A from iv_uom_list);
// If order name in list, then set flag.
if name is in medications_list then
match_med_found := match_med_found, TRUE;
else
match_med_found := match_med_found, FALSE;
endif;
endif; // If med in list
enddo; // Get additive list for those that match medications list
elseif exists class_type then
// Get additive list for those that match class type and value
for A in index_iv do
// Get the Master GUID for this component item
temp_ocmi_guid := last(first A from iv_order_catalog_master_item_guid_list);
// Get the class type and value for this components master item
(the_name,
the_type,
the_value)
:= read
{" SELECT Name, Code, Value "
||" FROM CV3OrderCatalogMasterItem JOIN CV3CatalogClassTypeValue "
||" ON CV3OrderCatalogMasterItem.GUID = CV3CatalogClassTypeValue.CatalogMasterGUID "
||" JOIN CV3ClassType "
||" ON CV3ClassType.GUID = CV3CatalogClassTypeValue.ClassTypeGUID "
||" WHERE CV3OrderCatalogMasterItem.GUID = "
||SQL(temp_ocmi_guid)};
class_index := 1 seqto (count the_type);
// Check each class type and value for each item.
for I in class_index do
temp_med_class_type := last(first I from the_type);
temp_med_class_value := last(first I from the_value);
if temp_med_class_type = class_type then
if temp_med_class_value is in class_value then
// Add and synch the field lists of components to the order
match_med_found := match_med_found, TRUE;
item_class_value := item_class_value, temp_med_class_value;
an_order_or_component := an_order_or_component,"component";
chart_guid := chart_guid, temp_chart_guid;
client_guid := client_guid, temp_client_guid;
client_visit_guid := client_visit_guid, temp_client_visit_guid;
dosage_high := dosage_high, last(first A from iv_dosage_to_list);
dosage_low := dosage_low, last(first A from iv_dosage_list);
entereddtm := entereddtm, NULL;
form_code := form_code, NULL;
frequency_code := frequency_code, NULL;
guid := guid, temp_guid;
is_conditional := is_conditional, NULL;
is_held := is_held, NULL;
is_prn := is_prn, temp_is_prn;
is_suspend := is_suspend, NULL;
name := name, last(first A from iv_name_list);
order_catalog_master_item_guid := order_catalog_master_item_guid,
temp_ocmi_guid;
order_priority_code := order_priority_code, NULL;
order_route_code := order_route_code, NULL;
order_status_code := order_status_code, NULL;
order_status_desc := order_status_desc, NULL;
order_status_level_num := order_status_level_num, NULL;
request_dtm := request_dtm, NULL;
significant_dtm := significant_dtm, temp_significant_dtm;
stop_dtm := stop_dtm, temp_stop_dtm;
summary_line := summary_line, NULL;
system_order_priority_code := system_order_priority_code, NULL;
uom := uom, last(first A from iv_uom_list);
endif;
endif;
enddo; // Check each class type and value for each item.
enddo; // Get additive list for those that match class type and value
else
// Get the entire list of additives
for A in index_iv do
temp_component_type := last(first A from component_type);
// // Type of 0 or 3 are IV additives
if temp_component_type is in (0,3) then
chart_guid := chart_guid, temp_chart_guid;
client_visit_guid := client_visit_guid, temp_client_visit_guid;
dosage_high := dosage_high, last(first A from iv_dosage_to_list);
dosage_low := dosage_low, last(first A from iv_dosage_list);
frequency_code := frequency_code, NULL;
guid := guid, temp_guid;
is_conditional := is_conditional, NULL;
is_prn := is_prn, temp_is_prn;
name := name, last(first A from iv_name_list);
order_catalog_master_item_guid := order_catalog_master_item_guid,
last(first A from iv_order_catalog_master_item_guid_list);
order_component := temp_order_component;
order_route_code := order_route_code, NULL;
order_status_code := order_status_code, NULL;
order_status_desc := order_status_desc, NULL;
order_status_level_num := order_status_level_num, NULL;
significant_dtm := significant_dtm, temp_significant_dtm;
stop_dtm := stop_dtm, temp_stop_dtm;
summary_line := summary_line, NULL;
uom := uom, last(first A from iv_uom_list);
endif; // Type of 0 or 3 are IV additives
enddo; // Get the entire list of additives
endif; // Exist medicaitons list else class type else all additives.
endif; //exist temp_order_component
//end - Get medication orders from object if the item name
// or the component name(additive) is in med filter list
endif;
;;
evoke:
;;
logic:
if exist med_info
then conclude TRUE;
else conclude FALSE;
endif;
;;
action:
return
an_order_or_component,
chart_guid,
client_guid,
client_visit_guid,
dosage_high,
dosage_low,
entereddtm,
form_code,
frequency_code,
guid,
is_conditional,
is_held,
is_prn,
is_suspend,
name,
order_catalog_master_item_guid,
order_priority_code,
order_route_code,
order_status_code,
order_status_desc,
order_status_level_num,
request_dtm,
significant_dtm,
stop_dtm,
summary_line,
system_order_priority_code,
uom,
match_med_found,
item_class_value;
;;
end:

View File

@@ -0,0 +1,350 @@
maintenance:
title: Get Filter Query And Bit Flags Based on Session Types ;;
mlmname: STD_FUNC_SESSION_TYPE_FILTER;;
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: Returns the order table name, SQL filter query and session type bit
flags depending on the session types lists or include flags AND whether
the current order is of in house, historical or discharge session type.
;;
explanation: Sites are allowed to configure whether they want to check the
current order entered (may be of Standard, Discharge, or
Historical session type) against existing or unsubmitted orders of
Standard, Discharge, or Historical session types of any combination.
Depending on the passed in arguments, the order table name and filter
query will be set to filter the existing database orders accordingly.
The session type bit flags will be set to filter the unsubmitted
orders accordingly.
The following is a description of the arguments passed in:
at_in_house_session_list - existing/unsubmitted orders belonging to
this list of session types will be checked
against the current inhouse order
at_historical_session_list - existing/unsubmitted orders belonging to
this list of session types will be checked
against the current historical order
at_discharge_session_list - existing/unsubmitted orders belonging to
this list of session types will be checked
against the current discharge order
at_outpatient_session_list -
at_prescription_session_list - existing/unsubmitted prescriptions
belonging to this list of session types
will be checked against the current prescriptions
at_prescription_historical_session_list - existing/unsubmitted prescriptions
belonging to this list of session types
will be checked against the current
historical prescriptions
use_community_medication - if community medication is found in the list,
this flag indicates whether to use community medication
if corresponding list is null (use_lists is false),
this flag indicates checking against
community medication
order_is_for_discharge - indicates whether current order
is entered in discharge session or
in house session
order_alternate_order_type - indicates whether current order
is entered in historical session or
not
prescription_type - indicates the session type of the current prescription
;;
keywords:
Session Type
;;
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;
/********************************************************************************/
(at_in_house_session_list, /* list of session types for current
inhouse order */
at_historical_session_list, /* list of session types for current
historical order */
at_discharge_session_list, /* list of session types for current
discharge order */
at_outpatient_session_list, /* list of session types for current
outpatient order */
at_prescription_session_list, /* list of session types for current
prescriptions */
at_prescription_historical_session_list, /* list of session types for current
historical prescriptions */
use_community_medication, /* indicates whether to use
community medication, if community
medication session is found in the list.
If corresponding list is null,
this flag specifies whether to check
against community medication or not
*/
order_is_for_discharge, /* indicates whether current order
is entered in discharge session */
order_alternate_type, /* indicates current order type */
prescription_type) /* indicates the session type of
the current prescription */
:= ARGUMENT;
/* Constant strings to denote the different session types */
discharge_order_session_str := "Discharge";
in_house_order_session_str := "Inhouse";
historical_session_str := "Historical";
outpatient_rx_session_str := "Outpatient Rx";
outpatient_hx_session_str := "Outpatient Hx";
in_house_rx_session_str := "Prescriptions";
historical_rx_session_str := "Historical Prescriptions";
community_med_session_str := "Community Medication";
// Initialize the default values for the session type inclusion flag
// in case the list corresponding to the current order/historical order/prescription is null
include_in_house_session_type_orders := false;
include_historical_session_type_orders := false;
include_discharge_session_type_orders := false;
include_outpatient_rx_session_type_orders := false;
include_outpatient_hx_session_type_orders := false;
// Initialize the default values for the session type inclusion flag
// in case the list corresponding to the current order/historical order is null
// Please note the flags do not affect the result if the current medication is a prescription
include_prescriptions := false;
include_historical_prescriptions := false;
include_community_medication := false;
// Enum values for Rx, Hx, Community Medication defined
enum_rx_type_Rx := 1;
enum_rx_type_Hx := 3;
enum_rx_type_Community_Med := 5;
/* Flags to include the orders belonging to the respective session
types during duplicate checking. Flags are set based on the site
configured list variables in STD_DUPLICATE namely
at_discharge_session_list, at_in_house_session_list, or
at_historical_session_list.
*/
session_type_list_count := 0;
valid_input_list := (discharge_order_session_str, in_house_order_session_str, historical_session_str,
outpatient_rx_session_str, outpatient_hx_session_str, in_house_rx_session_str, historical_rx_session_str, community_med_session_str);
at_in_house_session_list := at_in_house_session_list WHERE it is in valid_input_list;
at_historical_session_list := at_historical_session_list WHERE it is in valid_input_list;
at_discharge_session_list := at_discharge_session_list WHERE it is in valid_input_list;
at_outpatient_session_list := at_outpatient_session_list WHERE it is in valid_input_list;
at_prescription_session_list := at_prescription_session_list WHERE it is in valid_input_list;
at_prescription_historical_session_list := at_prescription_historical_session_list WHERE it is in valid_input_list;
// Use the configured session types list for in-house session
session_type_list := at_in_house_session_list;
if (count(session_type_list) = 0) then
session_type_list := (in_house_order_session_str);
endif;
// Use the configured session types list for discharge session
if (order_is_for_discharge is not null) AND (order_is_for_discharge) then
session_type_list := at_discharge_session_list;
if (count(session_type_list) = 0) then
session_type_list := (discharge_order_session_str);
endif;
endif;
// Use the configured session types list for historical session
if (order_alternate_type is not null) AND (order_alternate_type = 1) then
session_type_list := at_historical_session_list;
if (count(session_type_list) = 0) then
session_type_list := (historical_session_str);
endif;
endif;
// Use the configured session types list for outpatient session
if (order_alternate_type is not null) AND (order_alternate_type = 2) then
session_type_list := at_outpatient_session_list;
if (count(session_type_list) = 0) then
session_type_list := (outpatient_rx_session_str, outpatient_hx_session_str);
endif;
endif;
if (prescription_type is not null) then
if (prescription_type = enum_rx_type_Rx) then
session_type_list := at_prescription_session_list;
elseif (prescription_type = enum_rx_type_Hx) then
session_type_list := at_prescription_historical_session_list;
endif;
// If the session type list is empty, set it to the default value
if (count(session_type_list) = 0) then
session_type_list := (in_house_rx_session_str, historical_rx_session_str);
if (use_community_medication) then
session_type_list := session_type_list, community_med_session_str;
endif;
endif;
endif;
// Include the existing discharge session orders
if discharge_order_session_str in session_type_list then
include_discharge_session_type_orders := true;
endif;
// Include the existing in-house session orders
if in_house_order_session_str in session_type_list then
include_in_house_session_type_orders := true;
endif;
// Include the existing historical session orders
if historical_session_str in session_type_list then
include_historical_session_type_orders := true;
endif;
// Include the existing outpatient rx session orders
if outpatient_rx_session_str in session_type_list then
include_outpatient_rx_session_type_orders := true;
endif;
// Include the existing outpatient hx session orders
if outpatient_hx_session_str in session_type_list then
include_outpatient_hx_session_type_orders := true;
endif;
// Include the existing in-house session prescriptions
if in_house_rx_session_str in session_type_list then
include_prescriptions := true;
endif;
// Include the existing historical session prescriptions
if historical_rx_session_str in session_type_list then
include_historical_prescriptions := true;
endif;
if community_med_session_str in session_type_list
and use_community_medication
then
include_community_medication := true;
else
include_community_medication := false;
endif;
if (session_type_list is null)
then
session_type_list_count := 0;
else
session_type_list_count := count(session_type_list);
endif;
filter_orders_sql_query := "";
order_table_name := "CV3AllOrdersVw";
session_flag := OBJECT [name, value];
session_inhouse_flag := new session_flag with in_house_order_session_str, include_in_house_session_type_orders;
session_historical_flag := new session_flag with historical_session_str, include_historical_session_type_orders;
session_discharge_flag := new session_flag with discharge_order_session_str, include_discharge_session_type_orders;
session_outpatient_rx_flag := new session_flag with outpatient_rx_session_str, include_outpatient_rx_session_type_orders;
session_outpatient_hx_flag := new session_flag with outpatient_hx_session_str, include_outpatient_hx_session_type_orders;
session_type_flags := (session_inhouse_flag, session_historical_flag, session_discharge_flag, session_outpatient_rx_flag, session_outpatient_hx_flag);
//discharge_flag := first(session_type_flags.value where session_type_flags.name = "Outpatient Rx");
if ( not include_in_house_session_type_orders ) then
filter_orders_sql_query := filter_orders_sql_query || " AND O.AlternateOrderType <> 0 ";
endif;
if ( not include_historical_session_type_orders ) then
filter_orders_sql_query := filter_orders_sql_query || " AND O.AlternateOrderType <> 1 ";
endif;
if ( not include_discharge_session_type_orders ) then
filter_orders_sql_query := filter_orders_sql_query || " AND O.IsForDischarge = 0 ";
endif;
if ( include_outpatient_rx_session_type_orders ) then
if ( include_outpatient_hx_session_type_orders ) then
;
else
filter_orders_sql_query := filter_orders_sql_query || " AND O.AlternateOrderType = 2 AND OAI.IsScript <> 0 ";
endif;
else
if ( include_outpatient_hx_session_type_orders ) then
filter_orders_sql_query := filter_orders_sql_query || " AND O.AlternateOrderType = 2 AND OAI.IsScript <> 1 ";
else
filter_orders_sql_query := filter_orders_sql_query || " AND O.AlternateOrderType <> 2 ";
endif;
endif;
filter_prescriptions_query := "";
rx_types_list := ();
if (include_prescriptions) then
rx_types_list := rx_types_list, enum_rx_type_Rx;
endif;
if (include_historical_prescriptions) then
rx_types_list := rx_types_list, enum_rx_type_Hx;
endif;
if (include_community_medication) then
rx_types_list := rx_types_list, enum_rx_type_Community_Med;
endif;
rx_types_count := count(rx_types_list);
index_list := 1 seqto rx_types_count;
for AA in index_list do
if (AA = 1) then
enum_rx_type_str := rx_types_list[AA];
else
enum_rx_type_str := enum_rx_type_str || ", " ||
rx_types_list[AA];
endif;
enddo;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
return( order_table_name,
filter_orders_sql_query,
session_type_flags,
enum_rx_type_str,
rx_types_list,
include_in_house_session_type_orders,
include_historical_session_type_orders,
include_discharge_session_type_orders,
include_outpatient_rx_session_type_orders,
include_outpatient_hx_session_type_orders,
include_community_medication );
;;
Urgency: 50;;
end:

View File

@@ -0,0 +1,208 @@
maintenance:
title: Calculate Durations for Tasks;;
mlmname: STD_FUNC_TASK_DURATION;;
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: Calculates the durations based on the standard times and
on a percentage of a frequency.
;;
explanation: Pass in a number and a string representation of time units, and
it will converted the information into an ARDEN Duration.
The expected spellings are:
"minutes", "hours", "days", "weeks", "months", "hours", and "task %".
In addition, the facility must map its Dictionary Codes to the Core UOM in the
Units of Measure Dictionary. To calculate the DURATION from "task %",
the MLM converts the facility-defined units of measure to the
system-defined values in the Unit of Measure Dictionary called CoreUOM.
The expected CoreUOM are:
"s", "min", "hr", "day", "week", "month", "year"
;;
keywords: Duration; Calculation;
;;
knowledge:
type: data-driven;;
data:
(some_number,
time_unit,
frequency_unit) := ARGUMENT;
/* System-defined units of measures in the Unit of Measure Dictionary*/
/* called CoreUOM. */
day_string:= "day";
hour_string:= "hr";
minute_string:= "min";
month_string:= "month";
second_string:= "s";
week_string:= "week";
year_string:= "year";
/*-------------------------------------------*/
/* Convert standard TIME units to a duration */
/*-------------------------------------------*/
If time_unit is in ("minutes", "hours", "days", "weeks", "months", "years")
then
if time_unit = "minutes"
then answer:= some_number MINUTES;
elseif time_unit = "hours"
then answer:= some_number HOURS;
elseif time_unit = "days"
then answer:= some_number DAYS;
elseif time_unit = "weeks"
then answer:= some_number WEEKS;
elseif time_unit = "months"
then answer:= some_number MONTHS;
elseif time_unit = "years"
then answer:= some_number YEARS;
endif; /* if time_unit */
endif; /* If time_unit is in */
/*---------------------------*/
/* Get FREQUENCY information */
/*---------------------------*/
if time_unit = "Task %"
and exist frequency_unit
then
/* Gets the Frequency information from the Enterprise data */
(frequency_code,
frequency_type,
time_from_value,
time_to_value,
time_uom,
time_core_uom):= read last
{"SELECT f.Code, f.DefinitionType, f.TimeFromValue, f.TimeToValue,"
|| " f.TimeUom, u.CoreUOM "
|| " FROM CV3Frequency AS f JOIN CV3UnitOfMeasure AS u"
|| " ON f.TimeUom = u.Code "
|| " WHERE f.Code = " || SQL (frequency_unit) };
/* Handle frequency templates <qxh> and <qxm> by parsing the frequency string */
/* If changes are made to this code, also change them in SYS_CALC_FREQMULT_DAILY */
/* This is a temporary workaround for frequency templates */
If NOT Exist frequency_type
then
/* Declare C functions to parse the frequency string */
func_get_token := interface {char* msvcrt:strtok(char*, char*)};
func_get_str := interface {char* msvcrt:strstr(char*, char*)};
/* Declare characters used for delimiting the string */
/* Delimiters are Case Sensitive */
q_delim:= "Q";
h_delim:= "H";
m_delim:= "M";
/* Determine if the letter in at the back of the string is H or M */
get_H:= call func_get_str with (frequency_unit, h_delim);
get_M:= call func_get_str with (frequency_unit, m_delim);
/* Remove the front Q, so xH or xM is left */
trim_Q:= call func_get_token with (frequency_unit, q_delim);
/* Set the time_core_uom */
/* Remove the H or the M, leaving a string representation of a number */
if exist get_H
then
time_core_uom := hour_string;
freq_num_str := call func_get_token with (trim_Q, h_delim);
elseif exist get_M
then time_core_uom := minute_string;
freq_num_str := call func_get_token with (trim_Q, m_delim);
endif; /* if exist get_H */
/* Convert string to number */
time_from_value := freq_num_str as number;
endif; /* If NOT Exist frequency_type */
endif; /*if time_unit = "Task %"*/
;;
evoke:
;;
logic:
/*---------------------------------*/
/* Convert FREQUENCY to a duration */
/*---------------------------------*/
if exist time_core_uom
and time_unit = "Task %"
then
if time_core_uom = day_string then
if frequency_type = 1 /* y times per day */
then frequency_duration:= (1/ time_from_value) * 1 day ;
else frequency_duration:= time_from_value * 1 day;
endif;
elseif time_core_uom = hour_string then
if frequency_type = 1 /* y times per hour */
then frequency_duration:= (1/ time_from_value) * 1 hour ;
else frequency_duration:= time_from_value * 1 hour ;
endif;
elseif time_core_uom = minute_string then
if frequency_type = 1 /* y times per minute*/
then frequency_duration:= (1/ time_from_value) * 1 minute ;
else frequency_duration:= time_from_value * 1 minute ;
endif;
elseif time_core_uom = second_string then
if frequency_type = 1 /* y times per second */
then frequency_duration:= (1/time_from_value) * 1 second ;
else frequency_duration:= time_from_value * 1 second ;
endif;
elseif time_core_uom = week_string then
if frequency_type = 1 /* y times per week */
then frequency_duration:= (1/time_from_value) * 1 week ;
else frequency_duration:= time_from_value * 1 week ;
endif;
elseif time_core_uom = month_string then
if frequency_type = 1 /* y times per month */
then frequency_duration:= (1/time_from_value) * 1 month;
else frequency_duration:= time_from_value * 1 month;
endif;
elseif time_core_uom = year_string then
if frequency_type = 1 /* y times per year */
then frequency_duration:= (1/time_from_value) * 1 year ;
else frequency_duration:= time_from_value * 1 year ;
endif;
endif; /* if time_core_uom */
/* Calculate Task % answer */
answer := frequency_duration * (SOME_NUMBER/100);
endif; /* if exist time_core_uom */
/************************/
/* Always conclude true */
/************************/
Conclude True;
;;
action:
Return answer;
;;
end:

View File

@@ -0,0 +1,334 @@
maintenance:
title: Alert Messages for Duplicate Task Checking MLM;;
mlmname: STD_FUNC_TASK_MESSAGES;;
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: Selects the appropriate alert message for the Duplicate-Task
Checking MLM.
;;
explanation: This MLM encapsulates the messages, so that all
changes to the messages can be done in one MLM.
;;
keywords: Duplicate Task; Alert; Message;
;;
knowledge:
type: data-driven;;
data:
(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_list ):= ARGUMENT;
;;
evoke:
;;
logic:
/* Intialize variables */
indent_string:= " ";
/*---------------------------------*/
/* Picks the correct alert message */
/*---------------------------------*/
long_alert_msg:= "";
processing_list:= 1 seqto (count matching_task_name_list);
for k in processing_list do
/* Gets duplicate task information */
dup_task_found:= processing_list = k;
dup_task_name:= first (matching_task_name_list where dup_task_found);
dup_task_significant_date:= first (matching_significant_date_list
where dup_task_found);
dup_task_msg_type:= first (matching_msg_type_list where dup_task_found);
dup_task_msg_text:= first (matching_msg_text_list where dup_task_found);
dup_task_time_msg:= first (matching_time_msg_list where dup_task_found);
dup_task_class_msg:= first (matching_class_list where dup_task_found);
dup_task_latest_scheduled_dtm:= first (matching_latest_scheduled_dtm_list
where dup_task_found);
dup_order_name:= first (matching_order_name_list where dup_task_found);
dup_order_type_code:= first (matching_order_type_code_list
where dup_task_found);
dup_task_performed_to_dtm:= first (matching_performed_to_dtm_list
where dup_task_found);
dup_task_process_type:= first (matching_process_type_list where dup_task_found);
dup_task_schedule_type_code:= first (matching_schedule_type_code_list
where dup_task_found);
dup_task_status_code:= first (matching_task_status_list where dup_task_found);
/*--------------------------------------*/
/* Sets Variables for the Alert Message */
/*--------------------------------------*/
/* Set Code 10 */
if dup_task_status_code = "performed"
then db10_task_schedule_type := "Already performed";
else
if dup_task_schedule_type_code = "scheduled"
then db10_task_schedule_type := "Scheduled";
elseif dup_task_schedule_type_code = "unscheduled"
then db10_task_schedule_type := "Unscheduled";
elseif dup_task_schedule_type_code = "PRN"
then db10_task_schedule_type := "Pending PRN";
elseif dup_task_schedule_type_code = "continuous"
then db10_task_schedule_type := "Pending continuous";
elseif dup_task_schedule_type_code = "ToSchedule"
and dup_task_process_type = 4
then db10_task_schedule_type :=
"To be scheduled starting when first done";
else db10_task_schedule_type := dup_task_schedule_type_code;
endif; /* if dup_task_schedule_type_code */
endif; /* if dup_task_status_code */
/* Set Code 11 */
if dup_task_status_code = "performed"
then
if exist dup_task_performed_to_dtm
then db11_date_label := "Date from: ";
else db11_date_label := "Date: ";
endif; /* if exist dup_task_performed_to_dtm */
elseif dup_task_status_code <> "performed"
then
if dup_task_schedule_type_code = "scheduled"
then db11_date_label := "Date: ";
else db11_date_label := "Earliest Date: ";
endif; /* if dup_task_schedule_type_code */
endif; /* if dup_task_status_code */
/* Set Codes 13 and 14 */
if dup_task_status_code = "performed"
and exist dup_task_performed_to_dtm
then
db13_to_label := " to: ";
db14_end_date := dup_task_performed_to_dtm formatted with "%.4t";
elseif dup_task_status_code <> "performed"
and exist dup_task_latest_scheduled_dtm
then
db13_to_label := " to latest date: ";
db14_end_date := dup_task_latest_scheduled_dtm formatted with "%.4t";
else
db13_to_label := "";
db14_end_date := "";
endif; /*
if dup_task_status_code */
/* Set task string */
if is_primary_task
then
task_string := "task";
else
task_string := "follow-up task";
endif;
/* Set Code A */
if (is_primary_task AND
order_type_code = "Medication")
then
a_type_of_order := "medication administration";
else
a_type_of_order := task_string;
endif; /* if order_type_code */
/* Set Code B */
if dup_task_schedule_type_code = "scheduled"
then b_verb := "scheduled";
else b_verb := "created";
endif; /* if dup_task_schedule_type_code */
/* Set Code D */
if dup_task_schedule_type_code = "unscheduled"
then d_task_schedule_type := "unscheduled";
elseif dup_task_schedule_type_code = "PRN"
then d_task_schedule_type := "PRN";
elseif dup_task_schedule_type_code = "continuous"
then d_task_schedule_type := "continuous";
else d_task_schedule_type := "" ;
endif; /* if dup_task_schedule_type_code */
/* Set up {{{SINGLE-QUOTE}}}another{{{SINGLE-QUOTE}}} varible text */
if d_task_schedule_type = ""
then another := "another";
else another := "another ";
endif;
/* Set Code C */
if dup_task_msg_type = same_item_type
then
if order_type_code = "Medication"
then
c_msg_type_text := another || d_task_schedule_type
|| " dose of the same medication";
else
c_msg_type_text := another || d_task_schedule_type
|| " " || task_string || " of the same";
endif;
elseif dup_task_msg_type = same_therapeutic_class_type
then
c_msg_type_text := another || d_task_schedule_type
|| " administration of a medication in the same therapeutic class";
elseif dup_task_msg_type = similar_task_type
then
c_msg_type_text := another || d_task_schedule_type
|| " " || task_string ||" of a similar type";
elseif dup_task_msg_type = conflict_type
then
c_msg_type_text := another || d_task_schedule_type
|| " conflicting " || task_string ;
elseif dup_task_msg_type = possible_conflict_type
then
c_msg_type_text := another || d_task_schedule_type
|| " possibly conflicting " || task_string;
endif; /* if dup_task_msg_type */
/* Set Code E */
if dup_task_status_code = "performed"
then e_occurrence_status := "had already been done";
elseif dup_task_status_code <> "performed"
then
if dup_task_schedule_type_code = "scheduled"
then e_occurrence_status := "was scheduled";
elseif dup_task_schedule_type_code = "ToSchedule"
and dup_task_process_type = 4 /* When 1ST GIVEN */
then e_occurrence_status :=
"was to be scheduled starting when first done";
else e_occurrence_status := "was pending";
endif; /* if dup_task_schedule_type_code */
endif; /* if dup_task_status_code */
/* Set Codes F and H */
if (is_primary_task
and dup_order_type_code = "Medication"
and order_type_code = "Medication")
then
f_too_close := "two doses might be given too close together";
h_was_done := "dose of " || dup_order_name ||" was given";
else
// two tasks(follow-up tasks) might be performed too close together
f_too_close := "two "|| task_string || "s might be performed too close together";
h_was_done := "time " || dup_order_name ||" was done";
endif;
/* Set Code G */
if (is_primary_task AND dup_order_type_code = "Medication")
then
g_doing_something := "giving this dose";
else
g_doing_something := "performing this " || task_string ;
endif; /* if is_primary_task AND dup_order_type_code */
/* Eliminates NULLs from printing in the alert message */
if dup_task_msg_text is null
then
dup_task_msg_text:= "";
print_cr := "";
else
print_cr := "\n\n" ;
endif; /* if dup_task_msg_text is null */
/*-------------------------------------------------*/
/* Creates the BEGINNING of the Long Alert Message */
/*-------------------------------------------------*/
if exist dup_task_significant_date then
formatted_dup_task_significant_date
:= dup_task_significant_date formatted with "%.4t";
endif; //check for task significant date
long_alert_msg:= long_alert_msg
|| indent_string || "{{+B}}{{+C}}"|| dup_task_name
||"{{-C}}{{-B}}"|| "\n"
|| indent_string || "( " || db10_task_schedule_type || " )\n"
|| indent_string || db11_date_label
|| formatted_dup_task_significant_date
|| db13_to_label || db14_end_date || "\n";
/*--------------------------------------------*/
/* Creates the REST of the Long Alert Message */
/*--------------------------------------------*/
if dup_task_msg_type = no_std_message_type
then
long_alert_msg:= long_alert_msg
|| dup_task_msg_text
|| "\n\n";
elseif dup_task_msg_type is in (same_item_type, same_therapeutic_class_type,
similar_task_type , conflict_type , possible_conflict_type )
then
long_alert_msg:= long_alert_msg
||"At the time this " || a_type_of_order
|| " was " || b_verb ||", " || c_msg_type_text || ","
|| " which is listed immediately above, "
|| e_occurrence_status || "."
|| " There is the potential that " || f_too_close ||"."
|| " Before " || g_doing_something
|| ", you should confirm that enough time has elapsed"
|| " since the last " || h_was_done || ". "
|| print_cr || dup_task_msg_text
|| "\n\n";
else
long_alert_msg:= long_alert_msg
|| "Error Message: Undefined Message Type for the item ordered."
|| "\n\n";
endif; /*if dup_task_msg_type */
enddo; /* for k */
/* Always conclude true to return the alert message to the calling program */
conclude true;
;;
action:
RETURN long_alert_msg;
;;
end:

View File

@@ -0,0 +1,328 @@
maintenance:
title: Task Retrievals for Duplicate Task Checking;;
mlmname: STD_FUNC_TASK_RETRIEVAL;;
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: Retrieves OrderTaskOccurrences according to the rules stated in
std_duplicate_task.mlm. Returns information to the calling MLM.
;;
explanation: See the explanation in std_duplicate.mlm
;;
keywords: Duplicate Task;
;;
knowledge:
type: data-driven;;
data:
/* Arguments that are passed by the calling MLM */
(client_guid,
chart_guid,
client_visit_guid,
task_occurrence_guid,
task_name,
task_scope,
is_primary_task,
originating_order_guid,
past_time,
future_time,
tasks_to_be_canceled_string,
schedule_type_code,
order_task_guid ):= ARGUMENT;
/* Set to true if logging is needed.*/
log_execution_info := false;
If exist client_guid
then
/*------------------------------------------------------------------*/
/* Set Variables to Retrieve OrderTaskOccurrences from the Database */
/*------------------------------------------------------------------*/
/* Set the OrderTaskOccurrence{{{SINGLE-QUOTE}}}s scope by using the patient{{{SINGLE-QUOTE}}}s GUIDs */
If task_scope = "This Chart"
then
ID_equals_patient_GUID := "o.ClientGUID = " || SQL(client_guid)
|| " AND t.ChartGUID = " || SQL(chart_guid);
elseif task_scope = "This Visit"
then
ID_equals_patient_GUID := "o.ClientGUID = " || SQL(client_guid)
|| " AND t.ChartGUID = " || SQL(chart_guid)
|| " AND ord.ClientVisitGUID = " || SQL(client_visit_guid);
else
ID_equals_patient_GUID := "o.ClientGUID = " || SQL(client_guid);
endif; /* task_scope */
/* Set the OrderTaskOccurrences that are in memory to be canceled */
If exist tasks_to_be_canceled_string
then
ignore_these_task_occurrences := SQL(task_occurrence_guid) || ","
|| tasks_to_be_canceled_string;
else
ignore_these_task_occurrences := SQL(task_occurrence_guid);
endif; /* tasks_to_be_canceled_string */
/* When there is a CONTINUOUS order task (CV3OrderTask.ScheduleTypeCode) */
/* Exclude the OrderTaskOccurrences that have the same OrderTaskGUID */
If schedule_type_code = "Continuous"
then
AND_exclude_order_task_guid := " AND o.OrderTaskGUID <> "
|| SQL(order_task_guid);
else
AND_exclude_order_task_guid := "";
endif; /* If schedule_type_code */
// Select same kind of task (primary or follow-up)
if is_primary_task
then
AND_match_task_sequence_number := " AND t.TaskSeqNum = 0";
AND_exclude_follow_up_task_from_same_order := "";
else
AND_match_task_sequence_number := " AND t.TaskSeqNum <> 0";
AND_exclude_follow_up_task_from_same_order := " AND t.OrderGUID <> "
|| SQL(originating_order_guid);
endif;
/*---------------------------------------*/
/* Get the DATABASE OrderTaskOccurrences */
/*---------------------------------------*/
(db_order_name_list,
db_order_type_code_list,
db_significant_date_list,
db_scheduled_dtm_list,
db_earliest_scheduled_dtm_list,
db_latest_scheduled_dtm_list,
db_performed_from_dtm_list,
db_performed_to_dtm_list,
db_cds_occurrence_type_list,
db_order_guid_list,
db_order_task_guid_list,
db_task_name_list,
db_task_status_code_list,
db_process_type_list,
db_schedule_type_code_list,
db_master_GUID_list,
db_level_number_list ) := read
{ "SELECT ord.Name, ord.TypeCode, "
||" tzSignificant.TimeValue as SignificantDtmOffset,"
||" tzScheduled.TimeValue as ScheduledDtmOffset,"
||" tzEarliest.TimeValue as EarliestScheduledDtmOffset,"
||" tzLatest.TimeValue as LatestScheduledDtmOffset,"
||" tzPerformedFrom.TimeValue as PerformedFromDtmOffset,"
||" tzPerformedTo.TimeValue as PerformedToDtmOffset,"
||" o.CDSOccurrenceType,"
||" o.OrderGUID, o.OrderTaskGUID, o.TaskName, o.TaskStatusCode,"
||" t.ProcessType, t.ScheduleTypeCode, t.OrderCatalogMasterItemGUID,"
||" ts.LevelNumber "
||" FROM CV3OrderTask as t "
||" JOIN CV3Order as ord"
||" ON t.OrderGUID = ord.GUID AND t.ChartGUID = ord.ChartGUID AND t.ClientGUID = ord.ClientGUID "
||" JOIN CV3OrderTaskOccurrence as o "
||" ON o.OrderTaskGUID = t.GUID AND o.OrderGUID = t.OrderGUID AND o.ClientGUID = t.ClientGUID "
||" JOIN CV3TaskStatus as ts "
||" ON o.TaskStatusCode = ts.Code "
||" JOIN CV3ClientVisit as cv "
||" ON ord.ClientVisitGUID = cv.GUID AND ord.ClientGUID = cv.ClientGUID "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.ScheduledDtm) tzScheduled "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.SignificantDtm) tzSignificant "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.EarliestScheduledDtm) tzEarliest "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.LatestScheduledDtm) tzLatest "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.PerformedFromDtm) tzPerformedFrom "
||" CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, o.PerformedToDtm) tzPerformedTo "
||" WHERE t.ClientGUID = " || SQL (client_guid)
||" AND " || ID_equals_patient_GUID
||" AND o.CDSOccurrenceType >= 0 "
||" AND ts.LevelNumber In (50,60) "
||" AND o.TaskStatusCode <> {{{SINGLE-QUOTE}}}Not Performed{{{SINGLE-QUOTE}}} "
||" AND o.IsSuspended = 0 "
||" AND o.GUID NOT IN (" || ignore_these_task_occurrences || ")"
|| AND_exclude_order_task_guid
|| AND_match_task_sequence_number
|| AND_exclude_follow_up_task_from_same_order
||" AND t.ScheduleTypeCode In "
||" ({{{SINGLE-QUOTE}}}Continuous{{{SINGLE-QUOTE}}},{{{SINGLE-QUOTE}}}ToSchedule{{{SINGLE-QUOTE}}},{{{SINGLE-QUOTE}}}Scheduled{{{SINGLE-QUOTE}}},{{{SINGLE-QUOTE}}}Unscheduled{{{SINGLE-QUOTE}}},{{{SINGLE-QUOTE}}}PRN{{{SINGLE-QUOTE}}})"
||" AND ((ts.LevelNumber = 60 "
||" AND (o.SignificantDtm between " || SQL(past_time)
|| " and " || SQL(future_time)|| "))"
||" OR "
||" (ts.LevelNumber = 50 "
||" AND ( (o.ScheduledDtm between " || SQL(past_time)
|| " and " || SQL(future_time)|| ")"
||" OR (o.EarliestScheduledDtm between " || SQL(past_time)
|| " and " || SQL(future_time)|| ")"
||" OR (o.LatestScheduledDtm between " || SQL(past_time)
|| " and " || SQL(future_time)|| ")"
||" OR ((o.EarliestScheduledDtm <= " || SQL(future_time)
||") and (o.LatestScheduledDtm is null))"
||" OR ((o.EarliestScheduledDtm <= " || SQL(past_time)
|| ") and (o.LatestScheduledDtm >= "
|| SQL(future_time)|| "))"
||" )))"
,PrimaryTime = SignificantDtmOffset };
endif; /* If exist client_guid */
/*-----------------------------------------------------*/
/* Get the Unsubmitted OrderTaskOccurrences from CACHE */
/*-----------------------------------------------------*/
/* Initialize Variables */
unsub_master_GUID_list := ();
unsub_order_name_list := ();
unsub_order_type_code_list := ();
unsub_process_type_list := ();
unsub_schedule_type_code_list := ();
unsub_significant_date_list := ();
unsub_latest_scheduled_dtm_list := ();
unsub_performed_to_dtm_list := ();
unsub_task_name_list := ();
unsub_task_status_code_list := ();
unsub_task_guid_list := ();
/* Only get the cached data if the schedule_type_code <> "Continuous" */
If is_primary_task AND ( schedule_type_code <> "Continuous" )
then
(unsub_latest_scheduled_dtm_list,
unsub_performed_to_dtm_list,
unsub_task_name_list,
unsub_task_status_code_list,
unsub_task_guid_list,
unsub_significant_date_list ) := read
{Unsubmitted OrderTaskOccurrence: LatestScheduledDtm,
PerformedToDtm, TaskName, TaskStatusCode,
guid, significantdtm
WHERE CDSOccurrenceType >= 0
AND TaskStatusCode IS IN ("Pending", "OverDue", "Rescheduled", "Performed" )
AND GUID <> task_occurrence_guid
AND IsSuspended = FALSE
AND (
SignificantDtm IS WITHIN past_time to future_time
OR ScheduledDtm IS WITHIN past_time to future_time
OR EarliestScheduledDtm IS WITHIN past_time to future_time
OR LatestScheduledDtm IS WITHIN past_time to future_time
OR (EarliestScheduledDtm <= future_time and LatestScheduledDtm is null)
OR (EarliestScheduledDtm <= past_time and LatestScheduledDtm >= future_time)
)};
/* OrderTaskOccurrence Object */
(order_obj,
order_task_obj):= read last
{OrderTaskOccurrence: Order, OrderTask
REFERENCING EvokingObject };
/* OrderTask object */
(unsub_master_GUID,
unsub_process_type,
unsub_schedule_type_code) := read last
{OrderTask: OrderCatalogMasterItemGUID, ProcessType, ScheduleTypeCode
REFERENCING order_task_obj };
/* Order object */
(unsub_order_name,
unsub_order_type_code,
unsub_significant_date ) := read last
{Order: Name, TypeCode, SignificantDtm
REFERENCING order_obj };
/* Create equal sized lists */
index_list := 1 seqto count(unsub_task_name_list);
for J in index_list do
unsub_master_GUID_list := unsub_master_GUID_list,
unsub_master_GUID;
unsub_order_name_list := unsub_order_name_list,
unsub_order_name;
unsub_order_type_code_list := unsub_order_type_code_list,
unsub_order_type_code;
unsub_process_type_list := unsub_process_type_list,
unsub_process_type;
unsub_schedule_type_code_list := unsub_schedule_type_code_list,
unsub_schedule_type_code;
enddo;
endif; /* If schedule_type_code <> "Continuous" */
/*---------------------------------------------*/
/* Append Unsubmitted and Database Information */
/*---------------------------------------------*/
if is_primary_task
AND (exist DB_TASK_NAME_LIST or exist UNSUB_TASK_NAME_LIST)
then
latest_scheduled_dtm_list := unsub_latest_scheduled_dtm_list,
db_latest_scheduled_dtm_list;
master_GUID_list := unsub_master_GUID_list,
db_master_GUID_list;
order_name_list := unsub_order_name_list,
db_order_name_list;
order_type_code_list := unsub_order_type_code_list,
db_order_type_code_list;
performed_to_dtm_list := unsub_performed_to_dtm_list,
db_performed_to_dtm_list;
process_type_list := unsub_process_type_list,
db_process_type_list;
schedule_type_code_list := unsub_schedule_type_code_list,
db_schedule_type_code_list;
significant_date_list := unsub_significant_date_list,
db_significant_date_list;
task_name_list := unsub_task_name_list,
db_task_name_list;
task_status_code_list := unsub_task_status_code_list,
db_task_status_code_list;
else
latest_scheduled_dtm_list := db_latest_scheduled_dtm_list;
master_GUID_list := db_master_GUID_list;
order_name_list := db_order_name_list;
order_type_code_list := db_order_type_code_list;
performed_to_dtm_list := db_performed_to_dtm_list;
process_type_list := db_process_type_list;
schedule_type_code_list := db_schedule_type_code_list;
significant_date_list := db_significant_date_list;
task_name_list := db_task_name_list;
task_status_code_list := db_task_status_code_list;
endif; /* exist task_name_list */
;;
evoke:
;;
logic:
/* Always conclude true to return information to the calling MLM */
conclude true;
;;
action:
Return ( latest_scheduled_dtm_list,
master_GUID_list,
order_name_list,
order_type_code_list,
performed_to_dtm_list,
process_type_list,
schedule_type_code_list,
significant_date_list,
task_name_list,
task_status_code_list );
;;
end:

View File

@@ -0,0 +1,561 @@
maintenance:
title: Rules for Duplicate Task Checking;;
mlmname: STD_FUNC_TASK_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 OrderTaskOccurrences according to the rules
stated in the std_duplicate_task.mlm.
Returns information on the duplicate task occurrences to the calling MLM.
;;
explanation: See the explanation in std_duplicate_task.mlm
;;
keywords: Duplicate Task;
;;
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;
/********************************************************************************/
/* Do Not Changes these Internal MLM Variables */
exact_msg:= "exact";
performed_msg:= "performed";
scheduled_msg:= "scheduled";
same_item_type:= "same item";
same_therapeutic_class_type:= "same therapeutic class";
similar_task_type:= "similar task";
conflict_type:= "conflict";
possible_conflict_type:= "possible conflict";
no_std_message_type:= "no std message";
/*==============================================================================*/
(task_name,
task_occurrence_guid,
task_status_code,
task_summary_line,
is_primary_task,
originating_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 ):= ARGUMENT;
/* Declares MLMs which can be called */
func_task_duration:= MLM {{{SINGLE-QUOTE}}}std_func_task_duration{{{SINGLE-QUOTE}}};
func_task_retrieval:= MLM {{{SINGLE-QUOTE}}}std_func_task_retrieval{{{SINGLE-QUOTE}}};
/* Gets the Client GUID */
client_guid := read last {ClientInfo: GUID};
/* Gets the evoking task occurrence{{{SINGLE-QUOTE}}}s Duplicate Policy */
(catalog_name,
duplicate_policy_guid ):= read last
{"SELECT Name, DuplicatePolicyGUID "
|| " FROM CV3CatalogItemTask "
|| " WHERE GUID = " || SQL(task_catalog_item_guid)
|| " AND Active = 1 "};
/* Continue if "check for duplicates" is marked in the Item-Catalog */
If exist duplicate_policy_guid
then
/* Gets evoking OrderTaskOccurrence{{{SINGLE-QUOTE}}}s duplicate policy information */
(task_loc_group_guid_list,
task_scope_list,
task_performed_time_list,
task_performed_unit_list,
task_exact_time_list,
task_exact_unit_list,
task_scheduled_time_list,
task_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 task_scope_list
then
If any (patient_loc_group = task_loc_group_guid_list)
then
loc_group_found := patient_loc_group = task_loc_group_guid_list;
else
loc_group_found := task_loc_group_guid_list is null;
endif;
loc_is_excluded := last (loc_is_excluded_list where loc_group_found);
endif; /* if exist task_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 */
/*--------------------------------------------------*/
task_loc_grp:= last (task_loc_group_guid_list
where loc_group_found);
task_scope:= last (task_scope_list
where loc_group_found);
task_performed_time:= last (task_performed_time_list
where loc_group_found);
task_performed_unit:= last (task_performed_unit_list
where loc_group_found);
task_exact_time:= last (task_exact_time_list
where loc_group_found);
task_exact_unit:= last (task_exact_unit_list
where loc_group_found);
task_scheduled_time:= last (task_scheduled_time_list
where loc_group_found);
task_scheduled_unit:= last (task_scheduled_unit_list
where loc_group_found);
/*-------------------------------------*/
/* Converts EXACT TIME into Arden Time */
/*-------------------------------------*/
If task_exact_time >= 0
and task_exact_unit is string
then
exact_duration := call func_task_duration with
(task_exact_time, task_exact_unit, frequency_unit);
If task_exact_unit = "days"
then exact_low_time:= (day floor of task_significant_date)
- exact_duration ;
exact_high_time:= (day floor of task_significant_date)
+ exact_duration + (1 day) - (1 second);
else exact_low_time:= task_significant_date - exact_duration;
exact_high_time:= task_significant_date + exact_duration;
endif; /* if task_exact_unit = */
endif; /* If task_exact_time >= 0 */
if exact_duration is NOT Duration
then
xxx_debug1:= "made EXACT time substitution";
/* Substitute times */
exact_low_time:= task_significant_date;
exact_high_time:= task_significant_date;
endif; /* if exact_duration is NOT Duration */
/*-----------------------------------------*/
/* Converts PERFORMED TIME into Arden Time */
/*-----------------------------------------*/
If task_performed_time >= 0 and task_performed_unit is string
then
performed_duration := call func_task_duration with
(task_performed_time, task_performed_unit, frequency_unit);
If task_performed_unit = "days"
then past_time:= (day floor of task_significant_date)
- performed_duration;
else past_time:= task_significant_date - performed_duration;
endif; /* if task_performed_unit = */
endif; /* if task_performed_time >= 0 ...*/
if performed_duration is NOT Duration
then
xxx_debug2:= "made PAST time substitution";
/* Substitute times */
if task_exact_unit = "Task %"
then
past_time:= task_significant_date - 12 hours;
substituted_past_frequency_date := true;
else
past_time:= task_significant_date;
endif; /* if task_exact_unit = "Task %" */
endif; /* if performed_duration is NOT Duration */
/*-----------------------------------------*/
/* Converts SCHEDULED TIME into Arden Time */
/*-----------------------------------------*/
If task_scheduled_time >= 0 and task_scheduled_unit is string
then
scheduled_duration := call func_task_duration with
(task_scheduled_time, task_scheduled_unit, frequency_unit);
If task_scheduled_unit = "days"
then future_time:= (day floor of task_significant_date)
+ scheduled_duration + (1 day) - (1 second);
else future_time:= task_significant_date + scheduled_duration;
endif; /* if task_scheduled_unit = */
endif; /* if task_scheduled_time >= 0 ...*/
if scheduled_duration is NOT Duration
then
xxx_debug3:= "made FUTURE time substitution";
/* Substitute times */
if task_exact_unit = "Task %"
then
future_time:= task_significant_date + 12 hours;
substituted_future_frequency_date := true;
else
future_time:= task_significant_date;
endif; /* if task_exact_unit = "Task %" */
endif; /* if scheduled_duration is NOT Duration */
/*---------------------------------------------------------*/
/* Determine if the Time Intervals are GOOD. */
/* Also determine if there was a frequency substitutition */
/* so the user can be warned that a complete check */
/* was not done */
/*---------------------------------------------------------*/
/* Check if the past and future are valid times */
has_time_interval := all ((past_time, future_time)are time);
/* Check if the past or future dates used a frequency substitution */
If substituted_past_frequency_date
OR substituted_future_frequency_date
then has_unknown_frequency := true;
else has_unknown_frequency := false;
endif; /* If substituted_past_frequency_date */
/* Only continue duplicate check if there are good dates for the */
/* time-interval for duplicates */
if has_time_interval
then
/*---------------------------------------------------------------------*/
/* Get evoking task{{{SINGLE-QUOTE}}}s Duplicate Item information from the Item-Catalog */
/*---------------------------------------------------------------------*/
/* Get the evoking task occurrence{{{SINGLE-QUOTE}}}s list of Duplicate ITEMS/CLASSES */
(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 CV3CatalogTaskDuplicate "
|| " WHERE CatalogItemTaskGUID = "||SQL(task_catalog_item_guid)
|| " AND Active = 1 "};
/*----------------------------------------------------------------------*/
/* Get the items from Item-Catalog that have a matching Duplicate CLASS */
/*----------------------------------------------------------------------*/
/* If there are any classes associated with the evoking task occurrence, */
/* then get the GUIDs of the items */
// Select same kind of task (primary or follow-up)
if is_primary_task
then
AND_match_task_sequence_number := " AND t.TaskSeqNum = 0";
else
AND_match_task_sequence_number := " AND t.TaskSeqNum <> 0";
endif;
If exist cat_class_value_list
then
other_class_guid_list:= ();
other_class_type_list:= ();
other_class_value_list:= ();
other_class_msg_type_list:= ();
other_class_msg_text_list:= ();
index1_list := 1 seqto (count cat_class_value_list);
for I in index1_list do
single_class_value := last(first I from cat_class_value_list);
single_class_type:= last(first I from cat_class_name_list);
single_class_msg_type:= last(first I from cat_message_type_list);
single_class_message:= last(first I from cat_message_list);
If exist single_class_value
and exist single_class_type
and exist task_catalog_item_guid
then
(temp_catalog_GUID_db,
temp_class_type_db,
temp_class_value_db):= read
{"SELECT t.OrderCatalogMasterItemGUID, "
|| " d.ClassTypeCode, d.ClassValue "
|| " FROM CV3CatalogTaskDuplicate as d"
|| " JOIN CV3CatalogItemTask as t"
|| " ON d.CatalogItemTaskGUID = t.GUID"
|| " WHERE "
|| " d.ClassTypeCode = " || SQL(single_class_type)
|| " AND d.ClassValue = " || SQL(single_class_value)
|| AND_match_task_sequence_number
|| " AND d.CatalogItemTaskGUID <> "
|| SQL(task_catalog_item_guid)} ;
If exist temp_catalog_GUID_db
then
other_class_guid_list:= other_class_guid_list,
temp_catalog_GUID_db;
other_class_type_list:= other_class_type_list,
temp_class_type_db;
other_class_value_list:= other_class_value_list,
temp_class_value_db;
/* Add the MessageType and MessageText */
/* Create the same number of instances as */
/* the temp_catalog_GUID_db list */
for each_catalog_guid in temp_catalog_GUID_db do
other_class_msg_type_list:=
other_class_msg_type_list,
single_class_msg_type;
other_class_msg_text_list:=
other_class_msg_text_list,
single_class_message;
enddo; /* for each_catalog_guid */
endif; /* if exist temp_catalog_GUID_db */
endif; /* if exist single_class_value */
enddo; /* for I */
endif; /* if exist cat_class_value_list */
/*-------------------------------------------------*/
/* Retrieve the task occurrences from the DATABASE */
/*-------------------------------------------------*/
(latest_scheduled_dtm_list,
master_GUID_list,
order_name_list,
order_type_code_list,
performed_to_dtm_list,
process_type_list,
schedule_type_code_list,
significant_date_list,
task_name_list,
task_status_code_list ):= call func_task_retrieval with
(client_guid,
chart_guid,
client_visit_guid,
task_occurrence_guid,
task_name,
task_scope,
is_primary_task,
originating_order_guid,
past_time,
future_time,
tasks_to_be_canceled_string,
schedule_type_code,
order_task_guid );
endif; /* if has_time_interval */
endif; /* if any loc_group_found and not loc_is_excluded */
endif; /* if exist duplicate_policy_guid */
;;
evoke:
;;
logic:
/*-----------------------*/
/* Initializes Variables */
/*-----------------------*/
matching_guid_list:= ();
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:= ();
/*--------------------------------------------------------*/
/* Create the DUP_ITEM_GUID_LIST and its associated lists */
/*--------------------------------------------------------*/
/* These lists are created from the item-catalog information associated */
/* with the Evoking OrderTaskOccurrence object. */
/* The DUP_ITEM_GUID_LIST contains the OrderCatalogMasterItemGUIDs */
/* that are potential duplicates of the EvokingObject */
/* The other lists contain information about the MessageType, MessageText, */
/* etc. which are used to construct the alert message */
/* Step 1: Initialize the lists with the individual ITEMs */
/* The individual ITEMs will have OrderCatalogMasterItemGUIDs in */
/* the cat_dup_item_guid_list */
cat_data_found := cat_dup_item_guid_list is not null;
dup_item_guid_list:= cat_dup_item_guid_list where cat_data_found;
class_name_list:= cat_class_name_list where cat_data_found;
class_value_list:= cat_class_value_list where cat_data_found;
message_type_list:= cat_message_type_list where cat_data_found;
message_list:= cat_message_list where cat_data_found;
/* Step 2: A task is always a duplicate of itself. */
/* Add the evoking object{{{SINGLE-QUOTE}}}s OrderCatalogMasterItemGUID */
/* to the front of the following lists, if the information from the */
/* item-catalog--duplicate checking panel does not include it. */
If item_catalog_guid is not in dup_item_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:= same_item_type, message_type_list;
message_list:= null, message_list;
endif; /* if item_catalog_guid is not in... */
/* Step 3: Add the OrderCatalogMasterItemGUIDs for the CLASSES */
/* and the other associated data to the lists */
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_msg_type_list;
message_list:= message_list, other_class_msg_text_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
/* The matching is done on the OrderCatalogMasterItemGUIDs */
/* Process each GUID one-at-a-time to find a match between the following */
/* Dup_item_guid_list, which are item-catalogs{{{SINGLE-QUOTE}}} OrderCatalogMasterItemGUIDs. */
/* Master_guid_list, which are task occurrences{{{SINGLE-QUOTE}}} OrderCatalogMasterItemGUIDs. */
index2_list := 1 seqto (count dup_item_guid_list);
for J in index2_list do
item_master_guid := last(first J from dup_item_guid_list);
if item_master_guid is in master_guid_list
then
master_guid_found:= item_master_guid = master_guid_list;
temp_guid:= master_guid_list where master_guid_found;
temp_task_name:= task_name_list where master_guid_found;
temp_signif:= significant_date_list where master_guid_found;
temp_latest_scheduled_dtm:= latest_scheduled_dtm_list
where master_guid_found;
temp_order_name:= order_name_list where master_guid_found;
temp_order_type:= order_type_code_list where master_guid_found;
temp_performed_to_dtm:= performed_to_dtm_list where master_guid_found;
temp_process_type:= process_type_list where master_guid_found;
temp_schedule_type:= schedule_type_code_list where master_guid_found;
temp_status:= task_status_code_list where master_guid_found;
matching_guid_list:=
matching_guid_list, temp_guid;
matching_task_name_list:=
matching_task_name_list, temp_task_name;
matching_significant_date_list:=
matching_significant_date_list, temp_signif;
matching_latest_scheduled_dtm_list:=
matching_latest_scheduled_dtm_list, temp_latest_scheduled_dtm;
matching_order_name_list:=
matching_order_name_list, temp_order_name;
matching_order_type_code_list:=
matching_order_type_code_list, temp_order_type;
matching_performed_to_dtm_list:=
matching_performed_to_dtm_list, temp_performed_to_dtm;
matching_process_type_list:=
matching_process_type_list, temp_process_type;
matching_schedule_type_code_list:=
matching_schedule_type_code_list, temp_schedule_type;
matching_task_status_code_list:=
matching_task_status_code_list, temp_status;
/* Find the associated MessageType and MessageText */
For each_guid in temp_guid do
temp_class_value := last(first J from class_value_list);
temp_msg_type := last(first J from message_type_list);
temp_msg_text := last(first J from message_list);
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 */
task_time:= time of each_guid;
relative_date:= now;
If task_time >= exact_low_time AND task_time <= exact_high_time
then correct_msg:= exact_msg;
elseif task_time < relative_date
then correct_msg:= performed_msg;
elseif task_time > relative_date
then correct_msg:= scheduled_msg;
else correct_msg:= null;
endif; /* if task_time */
matching_time_msg_list:= matching_time_msg_list, correct_msg;
enddo; /* for each_guid */
endif; /* if item_master_guid is in master_guid_list */
enddo; /* for J */
endif; /* if any(dup_item_guid_list...*/
/* All remaining, matched task occurrences are considered duplicates */
/* Concludes true to return data to the calling MLM */
conclude true;
;;
action:
return( 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 );
;;
end:

View File

@@ -0,0 +1,531 @@
maintenance:
title: Extraction of Dosage Range Criteria;;
mlmname: STD_FUNC_TOTAL_DAILY_DOSE_CAT;;
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: Finds the appropriate dose-range criteria from the order{{{SINGLE-QUOTE}}}s item-catalog and
returns the information to the calling MLM.
;;
explanation: This MLM assists the STD_TOTAL_DAILY_Dose_Exceeded MLM with dose-range checking.
A large list of arguments is passed to this MLM, and they are used to find
the most appropriate dose-range criteria (AGE, BSA, or WEIGHT)
for the patient.
If the ORDERED-DOSE is being checking and the "PER WT OR M2" field has a
valid uom (kg,lb,oz,g,m2), then the upper and lower dose-ranges will be
(1) multiplied by the patient{{{SINGLE-QUOTE}}}s weight or BSA and
(2) rounded using the rules found in the SYS_round_dosage MLM,
if there is a valid route.
If the DOSE-PER is being checking and the "PER WT OR M2" field has a
valid uom (kg,lb,oz,g,m2), then the upper and lower dose-ranges will NOT be
multiplied or rounded.
The dose-ranges and other pertinent information are returned to the calling MLM.
See the STD_TOTAL_DAILY_Dose_Exceeded MLM for further information.
;;
keywords: single dose; average daily dose; total daily dose; dosage range
;;
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:
(age_string,
birthday,
birthmonthnum,
BSA_number_rounded,
BSA_string,
catalog_item_obj,
day_string,
drug_name,
gm_string,
kg_string,
lb_string,
m2_string,
month_string,
order_med_per_uom,
order_med_route,
order_med_significant_date,
order_med_units,
ounce_string,
intl_patient_gender,
uom_facility_code,
uom_sys_code,
week_string,
weight_string,
wt_kg,
year_string):= ARGUMENT;
// Set to true if logging is needed.
log_execution_info := false;
/* Declare the MLMs that can be called */
round_dose_func := MLM {{{SINGLE-QUOTE}}}SYS_round_dosage{{{SINGLE-QUOTE}}};
/* Get the reference to the CatalogItemDosage object */
order_catalog_item_dosage_obj:= read last
{OrderCatalogMasterItem: CatalogItemDosage
REFERENCING catalog_item_obj };
/* Get the Dosage range data from the catalog item when the routes */
/* Match to the order. */
(facility_gender_codes,
gender_codes,
criteria_type_codes,
criteria_type_high_codes,
criteria_type_low_codes,
criteria_type_facility_uoms,
routes,
range_low_codes,
range_high_codes,
range_uoms,
range_per_facility_uoms) := read
{ CatalogItemDosage: GenderCode, GenderTypeIntlCode, CriteriaTypeCode,
CriteriaTypeHigh, CriteriaTypeLow, CriteriaTypeUom, RouteCode,
RangeLow, RangeHigh, RangeUom, RangePerUom
REFERENCING order_catalog_item_dosage_obj
WHERE RouteCode = order_med_route
and RangeUom = order_med_units
and (CriteriaTypeCode = age_string
or CriteriaTypeCode = bsa_string
or CriteriaTypeCode = weight_string) };
;;
evoke:
;;
logic:
/* Intializes variables */
criteria_type_uoms:= ();
dose_per_string:= "Dose Per";
dose_reg_string:= "Dose Reg";
found_criteria:= false;
range_per_uoms:= ();
/*-----------------------------------------------------------------------------*/
/* Check and flag existence of any criteria for BSA, wt, age, or Average Daily */
/*-----------------------------------------------------------------------------*/
If any (criteria_type_codes = age_string) then
found_age_criteria := TRUE;
else
found_age_criteria := FALSE;
endif;
If any (criteria_type_codes = bsa_string) then
found_BSA_criteria := TRUE;
else
found_BSA_criteria := FALSE;
endif;
If any (criteria_type_codes = weight_string) then
found_weight_criteria := TRUE;
else
found_weight_criteria := FALSE;
endif;
If any (range_per_facility_uoms = m2_string) then
found_PER_M2_criteria := TRUE;
else
found_PER_M2_criteria := FALSE;
endif;
if ANY (range_per_facility_uoms = kg_string)
OR ANY (range_per_facility_uoms = gm_string)
OR ANY (range_per_facility_uoms = lb_string)
OR ANY (range_per_facility_uoms = ounce_string)
then
found_PER_WT_criteria := TRUE;
else
found_PER_WT_criteria := FALSE;
endif;
If any (facility_gender_codes is NOT NULL)
then
found_gender_code_criteria := TRUE;
else
found_gender_code_criteria := FALSE;
endif;
/*------------------------------*/
/* Checks if the MLM should run */
/*------------------------------*/
If exist(range_high_codes) and any(range_high_codes > 0)
then
/* Convert patient weight to grams */
if wt_kg is number
and wt_kg > 0
then wt_gm:= wt_kg * 1000;
endif; /* if wt_kg is number and and wt_kg > 0 */
/* Converts facility-defined UOM codes to the System{{{SINGLE-QUOTE}}}s CoreUOM codes */
/* CV3CatalogItemDosage.CriteriaTypeUom and */
/* CV3CatalogItemDosage.RangePerUom are replaced with CoreUOM codes. */
/* The MLM will continue to use the facility-defined */
/* CV3CatalogItemDosage.RangeUom */
temp_numbers:= 1 seqto count(criteria_type_facility_uoms);
for k in temp_numbers do
found_k:= temp_numbers = k;
temp_criteria_type_uoms:= last (criteria_type_facility_uoms
where found_k);
temp_range_per_uoms:= last (range_per_facility_uoms where found_k);
criteria_type_uoms:= criteria_type_uoms,
last (uom_sys_code
where (uom_facility_code = temp_criteria_type_uoms));
range_per_uoms:= range_per_uoms,
last (uom_sys_code where (uom_facility_code = temp_range_per_uoms));
enddo; /* for k */
/*-------------------------*/
/* BSA (Body Surface Area) */
/*-------------------------*/
/* Checks the Dosage-range for the patient{{{SINGLE-QUOTE}}}s current BSA (body surface area) */
if not found_criteria
and exist BSA_number_rounded
then
type_name:= BSA_string;
value:= BSA_number_rounded;
/* Determines which records are applicable--we will use the first one */
temp_found_dosage_record :=
((gender_codes = intl_patient_gender) or
(facility_gender_codes = "" ) or
(facility_gender_codes is null)) and
(criteria_type_codes = type_name) and
(value >= criteria_type_low_codes) and
(value < criteria_type_high_codes) and
(order_med_units = range_uoms) and
(M2_string = criteria_type_uoms);
/* Determine if there is a match for DOSE-PER */
found_per_dose_record:=
temp_found_dosage_record and
(order_med_per_uom = range_per_uoms);
/* Set the Dose Calculation Method and the Found Dosage Record */
if any (found_per_dose_record)
then
found_dosage_record:= found_per_dose_record;
dose_calc_method:= dose_per_string;
elseif any (temp_found_dosage_record)
then
found_dosage_record:= temp_found_dosage_record;
dose_calc_method:= dose_reg_string;
endif; /* if any (found_per_dose_record) */
lower_dose := first (range_low_codes where found_dosage_record);
upper_dose := first (range_high_codes where found_dosage_record);
units:= first (range_uoms where found_dosage_record);
per_units:= first (range_per_uoms where found_dosage_record);
/* Checks if a match was found by checking if the doses are numbers */
/* Stops looking after finding the first match */
If lower_dose is number and upper_dose is number
then found_criteria:= true;
endif;
endif; /* if not found_criteria and exist BSA_number_rounded */
/*--------*/
/* WEIGHT */
/*--------*/
/* Checks the Dosage-range for the patient{{{SINGLE-QUOTE}}}s current WEIGHT, */
/* when BSA is unavailable */
if not found_criteria
and wt_gm is number
and wt_gm > 0
then
type_name := weight_string;
/* Finds all the rows that apply to WEIGHT and */
/* Eliminates duplicates weight-units and */
/* Creates an unique list of sorted weight-units by ascending size */
temp_wt_unit_list:= (criteria_type_uoms
where weight_string = criteria_type_codes);
wt_unit_list:= (gm_string, ounce_string, lb_string, kg_string )
where it is in temp_wt_unit_list;
/* Processes all possible kinds of WEIGHT to find a match */
for some_wt_unit in wt_unit_list do
if not found_criteria
then
/* Saves the weight unit */
wt_unit:= some_wt_unit;
/* Converts the patient{{{SINGLE-QUOTE}}}s weight into the expects units */
if wt_unit = kg_string then value:= wt_gm/1000; /* kilogram */
elseif wt_unit = gm_string then value:= wt_gm; /* gram */
elseif wt_unit = lb_string then value := wt_gm/453.6; /* pound */
elseif wt_unit = ounce_string then value:= wt_gm/28.35; /* ounce */
endif;
/* Determines which records are applicable-MLM uses the first one*/
temp_found_dosage_record :=
((gender_codes = intl_patient_gender) or
(facility_gender_codes = "" ) or
(facility_gender_codes is null )) and
(criteria_type_codes = type_name) and
(value >= criteria_type_low_codes) and
(value < criteria_type_high_codes) and
(order_med_units = range_uoms) and
(wt_unit = criteria_type_uoms);
/* Determine if there is a match for DOSE-PER */
found_per_dose_record:=
temp_found_dosage_record and
(order_med_per_uom = range_per_uoms);
/* Set the Dosa Calculation Method and the Found Dosage Record */
if any (found_per_dose_record)
then
found_dosage_record:= found_per_dose_record;
dose_calc_method:= dose_per_string;
elseif any (temp_found_dosage_record)
then
found_dosage_record:= temp_found_dosage_record;
dose_calc_method:= dose_reg_string;
endif; /* if any (found_per_dose_record) */
/* Extracts the data that will be used for Dosage range checking */
lower_dose:= first (range_low_codes where found_dosage_record);
upper_dose:= first (range_high_codes where found_dosage_record);
units:= first (range_uoms where found_dosage_record);
per_units:= first (range_per_uoms where found_dosage_record);
/* Checks if a match was found by checking if the doses are numbers */
/* Stops looking after finding the first match */
If lower_dose is number and upper_dose is number
then found_criteria:= true;
endif;
endif; /* if not found_criteria */
enddo; /* for some_wt_unit */
endif; /* if not found_criteria and wt_gm is number ... */
/*-----*/
/* AGE */
/*-----*/
/* Checks the Dosage-range for the patient{{{SINGLE-QUOTE}}}s current AGE, */
/* when BSA and Weight are unavailable. */
/* A valid birthday is required for the appropriate age calculation */
/* The age of adults and older children can be calculated with the birth-year */
/* when the month and day are not available. */
/* However, the age of an infant can be over-estimated based solely */
/* on the birth-year. Therefore infant must have */
/* a valid birth-month and birth-year before an age calculation is attempted. */
/* If the patient{{{SINGLE-QUOTE}}}s birth month is 0, */
/* then only the birth-year is available for the age calculation. */
/* In this case, don{{{SINGLE-QUOTE}}}t use the age-based dosage range data for */
/* infants or children under age 3 years. */
if birthday is time then
has_valid_birthdate:= true;
if birthMonthNum = 0 then
age_value:= (order_med_significant_date-birthday)/(1 year);
if age_value <= 3 then
has_valid_birthdate:= false;
endif;
endif;
endif; /* if birthday is time */
/* Check the age-based dosage range data when there is a valid birthdate */
if not found_criteria
and has_valid_birthdate
then
type_name:= age_string;
/* Finds all the rows that apply to AGE and */
/* Eliminates duplicates weight-units and */
/* Creates an unique list of sorted age-units by ascending age */
temp_age_unit_list:= (criteria_type_uoms
where age_string = criteria_type_codes);
age_unit_list:= (day_string, week_string, month_string, year_string)
where it is in temp_age_unit_list;
/* Processes all possible kinds of AGE to find a match */
for some_age_unit in age_unit_list do
if not found_criteria
then
/* Saves age unit */
age_unit:= some_age_unit;
/* Converts the patient{{{SINGLE-QUOTE}}}s AGE into the expected units */
if age_unit = year_string
then value:= (order_med_significant_date - birthday)/(1 year);
elseif age_unit= month_string
then value:= (order_med_significant_date - birthday)/(1 month);
elseif age_unit = week_string
then value:= (order_med_significant_date - birthday)/(1 week);
elseif age_unit = day_string
then value:= (order_med_significant_date - birthday)/(1 day);
endif; /* if age_unit */
/* Determines which records are applicable--MLM uses the first one */
temp_found_dosage_record :=
((gender_codes = intl_patient_gender) or
(facility_gender_codes = "" ) or
(facility_gender_codes is null )) and
(criteria_type_codes = type_name) and
(value >= criteria_type_low_codes) and
(value < criteria_type_high_codes) and
(order_med_units = range_uoms) and
(age_unit = criteria_type_uoms);
/* Determine if there is a match for DOSE-PER */
found_per_dose_record:=
temp_found_dosage_record and
(order_med_per_uom = range_per_uoms);
/* Set the Dosa Calculation Method and the Found Dosage Record */
if any (found_per_dose_record)
then
found_dosage_record:= found_per_dose_record;
dose_calc_method:= dose_per_string;
elseif any (temp_found_dosage_record)
then
found_dosage_record:= temp_found_dosage_record;
dose_calc_method:= dose_reg_string;
endif; /* if any (found_per_dose_record) */
/* Extracts the data that will be used for Dosage range checking */
lower_dose:= first (range_low_codes where found_dosage_record);
upper_dose:= first (range_high_codes where found_dosage_record);
units:= first (range_uoms where found_dosage_record);
per_units:= first (range_per_uoms where found_dosage_record);
/* Checks if a match was found by checking if the doses are numbers */
/* Stops looking after finding the first match */
If lower_dose is number and upper_dose is number
then found_criteria:= true;
endif; /* If lower_dose is number ... */
endif; /* if not found_criteria */
enddo; /* for some_age_unit */
endif; /* if not found_criteria */
/*-------------------------*/
/* PER WT OR M2 CONVERSION */
/*-------------------------*/
/* Converts doses based on the patient{{{SINGLE-QUOTE}}}s weight whenever there is a: */
/* (1) {{{SINGLE-QUOTE}}}per unit{{{SINGLE-QUOTE}}} of body weight (PER WT OR M2), (2) weight for the patient, */
/* and (3) regular dose calculation */
if found_criteria
and exists per_units
and dose_calc_method = dose_reg_string
then
if per_units is in (kg_string, gm_string, lb_string, ounce_string)
then
if wt_gm > 0
then
If per_units = kg_string
then lower_dose:= lower_dose * wt_gm/1000;
upper_dose:= upper_dose * wt_gm/1000;
elseif per_units = gm_string
then lower_dose:= lower_dose * wt_gm;
upper_dose:= upper_dose * wt_gm;
elseif per_units = lb_string
then lower_dose:=lower_dose * wt_gm/453.6;
upper_dose:= upper_dose * wt_gm/453.6;
elseif per_units = ounce_string
then lower_dose:=lower_dose * wt_gm/28.35;
upper_dose:= upper_dose * wt_gm/28.35;
endif; /* if per_units = */
else
/* Stops MLM when there are valid weight units (per_units) */
/* and invalid body weight (wt_gm) */
found_criteria:= false;
endif; /* wt_gm > 0 */
elseif per_units = m2_string
then
if BSA_number_rounded is number
and BSA_number_rounded > 0
then
lower_dose:= lower_dose * BSA_number_rounded;
upper_dose:= upper_dose * BSA_number_rounded;
else
/* Stops MLM when there is a valid M2 and invalid BSA number */
found_criteria:= false;
endif; /* if BSA_number_rounded is number */
endif; /* if per_units */
/* ROUND the dose generated by the PER WT OR M2 */
/* When there is a route */
/* And save the original unrounded doses */
if (exist lower_dose or exist upper_dose)
and exist order_med_route
then
unrounded_lower_dose:= lower_dose;
unrounded_upper_dose:= upper_dose;
(rounding_error_msg, lower_dose):=
call round_dose_func with lower_dose, order_med_route ;
(rounding_error_msg, upper_dose):=
call round_dose_func with upper_dose, order_med_route ;
endif; /* if exist lower_dose or exist upper_dose */
endif; /* if found_criteria and exists per_units... */
else
xxx_debug_check:= "Medication does not have Dosage-range checking";
endif; /* If exist(range_high_codes)... */
/* Set the UOM according to the Dosage Calculation Method */
if dose_calc_method = dose_per_string
then corrected_uom:= units || "/" || order_med_per_uom;
else corrected_uom:= units;
endif; /* if dose_calc_method */
/* Always conclude true to return variables to calling MLM */
CONCLUDE TRUE;
;;
action:
return (found_criteria, dose_calc_method, lower_dose, upper_dose,
corrected_uom, per_units, type_name,
found_age_criteria, found_BSA_criteria, found_weight_criteria,
found_gender_code_criteria,found_PER_WT_criteria,found_PER_M2_criteria);
;;
end:

View File

@@ -0,0 +1,114 @@
maintenance:
title: Validate and format numeric data in text field;;
mlmname: STD_FUNC_VALIDATE_AND_FORMAT_TEXT_AS_NUMERIC;;
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: Checks that a given string contains only numeric characters
(May also contain a decimal point). It also formats that string
based on the strFormatString that is passed from the calling MLM.
;;
explanation: This MLM will check that all of the characters in strTextToValidateAndFormat
are numeric values or a decimal point. If bAllowDecimals = true, then the
MLM will also consider a decimal point to be a valid character. Otherwise,
only standard numeric characters (0-9) will be considered valid.
If strTextToValidate is a valid numeric string, the MLM will format the
string based on the strFormatString format specification. For further
information on acceptable format specifications, please refer to the
Arden syntax guide. NOTE: If you wish to validate the data but do not wish
to format it, set strFormatString := null;
;;
keywords: validate; format numeric data ;;
knowledge:
type: data-driven;;
data:
/* List Arguments passed by the calling MLM */
(strTextToValidateAndFormat, //the numeric string to be validated
strFormatString, //Arden syntax format specification (ie "%.2f") or null
bAllowDecimals //whether or not this field allows decimal values
):= ARGUMENT;
/***************Make Changes To Spelling And Flags In This Section**************/
/* Set to true if logging is needed.*/
log_execution_info := false;
/*******************************************************************************/
ValidNumericValues := ("1","2","3","4","5","6","7","8","9","0");
;;
evoke: ;;
logic:
characterList := extract characters strTextToValidateAndFormat;
cnt := count (characterList);
indexList := 1 SEQTO cnt;
bDecimalFound := false;
IsValid := true;
//Parses the string into individual characters and checks that each character
//is either numeric or a decimal. It also makes sure that there is only one
//decimal.
for X in indexList do
ch := characterList[X];
if ch IS NOT IN ValidNumericValues then
if bAllowDecimals = true then
//check if ch is a decimal but make sure there is only one...
if (string(ch) = string(".")) AND bDecimalFound = false then
bDecimalFound := true;
else
IsValid := false;
endif;
else
IsValid := false;
endif;
endif;
enddo;
If IsValid = true then
if strFormatString IS NOT NULL then
strFormattedString := (strTextToValidateAndFormat as number)
formatted with strFormatString;
else
strFormattedString := strTextToValidateAndFormat;
endif;
endif;
conclude true;
;;
action:
return (IsValid, strFormattedString);
;;
end:

View File

@@ -0,0 +1,144 @@
maintenance:
title: Set the Actions for Venipuncture Alerts;;
mlmname: STD_FUNC_VENIPUNCTURE_ACTIONS;;
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: This MLM is used by the Venipuncture checking MLMs to call another
MLM to create the AlertAction object and to populate them with data.
;;
explanation: This MLM will do the following:
1. Call the STD_Func_Create_Alert_Action_Object MLM to create an instance
of the AlertAction object.
2. Process the data that was sent to it and populate each AlertAction object.
3. Create a list of the objects and return it to the call program.
;;
keywords:
;;
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;
/********************************************************************************/
// Instantiate the variables associated with the Arguments
(order_guid, //GUID of the Evoking Object
matching_action_item_status_list, //List of STRINGs for the ActionItemStatus
matching_order_guid_list, //List of GUIDs for the ActionItemID
matching_name_list, //List of STRINGs for the ActionItemName
matching_master_guid_list, //List of GUIDs for ActionEnterpriseItemID
matching_short_message_list, //List of STRINGs for the ShortMessage
matching_is_suspended_list ) //List of Booleans for Suspended Orders
:= ARGUMENT;
// Declare the MLM that can be called by this MLM
func_create_alert_action_object := MLM {{{SINGLE-QUOTE}}}STD_Func_Create_Alert_Action_Object{{{SINGLE-QUOTE}}};
// Execute only when this MLM is called by the editor
if called_by_editor then
obj := read last
{ Order: THIS
WHERE GUID = order_guid };
EvokingObject := obj;
endif;
//---------------------------------------------
// Call the MLM to Create AlertAction Objects
//---------------------------------------------
// Get data from the Evoking Object
(evoking_catalog_item_guid,
evoking_object_name):= read last
{Order: OrderCatalogMasterItemGUID, Name
REFERENCING EvokingObject };
// Set Values for AlertAction data
evoking_object_table := "CV3Order";
action_item_table := "CV3Order";
mlm_name := "STD_VENIPUNCTURE";
alert_action_object_list := ();
counter_list := 1 seqto (count matching_order_guid_list );
for JJ in counter_list do
// Process Through the Lists
// to Set Variables that will populate the AlertAction object
action_item_name := matching_name_list[JJ];
action_item_catalog_item_guid := matching_master_guid_list[JJ];
action_item_guid := matching_order_guid_list[JJ];
action_item_status := matching_action_item_status_list [JJ];
is_suspended := matching_is_suspended_list[JJ];
short_message := matching_short_message_list[JJ];
// Create the correct action_event_list for EXISTING and UNSUBMITTED orders
if action_item_status = "Existing"
then
//Do NOT suspend an order that is already suspended.
if is_suspended
then action_event_list := "DC-Cancel", "Modify";
else action_event_list := "DC-Cancel", "Modify", "Suspend";
endif; //if is_suspended
elseif action_item_status = "Unsubmitted"
then action_event_list := "Delete", "Modify";
endif;
for action_event in action_event_list do
// Create the AlertAction Object
alert_action_obj:= call func_create_alert_action_object with
(evoking_object_table,
action_item_table) ;
// Set the Shared Values for a Single Instance of the AlertAction Object
alert_action_obj.EvokingEnterpriseItemID := evoking_catalog_item_guid;
alert_action_obj.EvokingObjectID := order_guid;
alert_action_obj.EvokingObjectName := evoking_object_name;
alert_action_obj.ActionEvent := action_event;
alert_action_obj.ActionItemStatus := action_item_status;
alert_action_obj.ActionItemID := action_item_guid;
alert_action_obj.ActionItemName := action_item_name;
alert_action_obj.ActionEnterpriseItemID := action_item_catalog_item_guid;
alert_action_obj.MLMName := mlm_name;
alert_action_obj.ShortMessage := short_message;
// Add AlertAction object to a list
alert_action_object_list := alert_action_object_list, alert_action_obj;
enddo; //for action_event
enddo; //for JJ
;;
evoke:
;;
logic:
conclude true;
;;
action:
return alert_action_object_list;
;;
end:

View File

@@ -0,0 +1,67 @@
maintenance:
title: Standard assemblies and namespaces;;
mlmname: std_include_libs;;
arden: version 2.5;;
version: 18.4;;
institution: Allscripts Corporation, 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: The purpose of this MLM is to include the .NET Assemblies and
namespaces required by most ObjectPlus MLMs
;;
explanation: Include this MLM at the start of any MLM that will
be making any .NET calls standard System and ObjectPlus
assemblies
Example:
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
;;
keywords:
;;
knowledge:
type: data-driven;;
data:
using "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using "System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
using "ObjectsPlusXA.SCM";
using "Sunrise.Tasking.ServiceContracts";
using namespace "System";
using namespace "System.Exception";
using namespace "System.Windows.Forms";
using namespace "ObjectsPlusXA.SunriseClinicalManager";
using namespace "Sunrise.Tasking.ServiceContracts";
using namespace "Sunrise.Tasking.ServiceContracts.Enums";
;;
priority: 50
;;
evoke:
;;
logic:
;;
action:
;;
Urgency: 50;;
end:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,835 @@
maintenance:
title: Total Daily Dose Exceeded warning;;
mlmname: STD_TOTAL_DAILY_DOSE_EXCEEDED;;
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: Provides a warning if the current dose being scanned will exceed the daily total
allowed for this medication order item for this patient.
;;
explanation:
Total Daily Dose Limit Exceeded Warnings are based on Dosage Range Criteria defined
for the Order Item compared to the current dose to be administered summed with the
previous doses given in the past 24 hours. Based on settings this MLM will not alert
if the entering provider was issued a Dosage Alert at Order Entry and the order was
verified by Pharmacy. The MLM can also be set not to alert for patients with missing
physical characteristic data or for patients at particular locations.
REQUIRED FIELDS:
(When an appropriate criteria cannot be found, there will not be an alert.)
- The patient data must be present for:
* Age
* Height
* Weight
* Gender
- The task occurrence form fields must include:
* TaskDose
* TaskUOM
* TaskRoute
- The facility must map the following "Core UOM" to their "Dictionary Code"
in the Unit Of Measure Dictionary:
* BSA: M2
* Weight: kg, g, lb, oz
* Age: year, month, week, day
NOTE THE FOLLOWING ARE NOT INCLUDED IN MEDICATION DOSE RANGE CHECKING:
- This MLM is NOT currently using Base Solution, Base Solution UOM,
IV Rate, or IV Rate UOM fields to perform Dose Range checking on order entry
or modification.
- Generic item matches are NOT included.
The only TASKs that are checked include those tasks that orignate from matching
Catalog Order Items. That is they are the same medication in the Item Catalog.
At this release Tasks and Occurrences that orginate from the same
OrderCatalogMasterItem will have a matching CatalogItemTaskGUID and there is
a one to one relationship between OrderCatalogMasterItem and CatalogItemTask.
- Tasks with diffrernt uom are NOT included in the calculations.
Only Tasks with matching units of measure will be totaled since there is means of
converting units of measure. There is no Conversion table available in this
release.
- IV-ADDITIVES are NOT considered when doing dosage range checks; concentrations
and amounts are entered on flowsheets, not on IV tasks.
To calculate the {{{SINGLE-QUOTE}}}Total Dose Daily Dose Allowed{{{SINGLE-QUOTE}}}, the Dose Range Criteria for the parent
order of this task occurrence will be examined. The MLM will determine if a dose range
has been specified in the item catalog for one of the following {{{SINGLE-QUOTE}}}Total Daily" criteria
types:
- BSA - Total Daily
- Weight - Total Daily
- Age - Total Daily
If data are available for more than one criteria type, the priority will be in the order
listed above.
An alert will be generated for the first method encountered where the total dose is
outside of the recommended Total Daily dose.
If a matching criteria is found, the total daily dose determined. Calculations are
performed if a PER method is defined such as per kg or per M2.
The following patient characteristics will be used to determine if the specified total
daily dose is appropriate:
(1) patient body surface area (BSA),
(2) patient weight, and
(3) patient age
(4) gender, if listed on the Total Daily dose criteria
Absence of a patient characteristic required to perform the calculation will result in
an alert warning that the calculation cannot be determined due to missing data.
SPECIAL CONSIDERATIONS:
a. The SYS_CALC_BSA.mlm calculates the Body Surface Area (BSA) for
Dosage Range MLMs. SYS_CALC_BSA.mlm has two BSA formulas (standard or pediatric).
If patient is 18.0 years or younger, Pediatric BSA formula is used.
If age of patient cannot be determined due to missing birth year,
facility{{{SINGLE-QUOTE}}}s preference in the enterprise profile for BSAFormula.
Should facility{{{SINGLE-QUOTE}}}s preference be needed and BSAFormula has not been set, then
Standard BSA formula will be used. In addition, calculated BSA value
is rounded to two decimal places.
b. When patient has a partial birthday (missing birth month), then
dosage range check by AGE will not be done if patient is less than
3 years old (an age based on the birth year).
c. The MLM uses data from Unit of Measure dictionary and Dosage Range panel in
the Item-Catalog. The Unit of Measure dictionary maps facility-defined UOM called
"Dictionary Code" to System-defined UOM called "Core UOM." "Dictionary Codes" in
Dosage Range panel of item-catalog.
When calculating dose-ranges, only "Criteria Unit" and "Dosage Per-Wt-or-M2"
fields are converted from facility-defined UOM (Dictionary Code) to System-defined
"Core UOM";
d. "Dosage Unit" is not converted. For example if one tasks dosage is in grains and
one in umg, the doses are not converted to the same unit of measure.
f. The absence of an alert can mean one of the following:
* The all the doses were within the acceptable range.
* The appropriate criteria could not be found; so the Dosage could not be checked.
* No item matches were found for the item in this task.
;;
keywords: total daily dose, exceeded
;;
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 a decision.log is needed.*/
log_execution_info := false;
/* Set these flags to limit alerting.*/
no_alert_if_RxVerified := TRUE; // no alerts if Rx has verified all the orders
alert_if_patient_data_missing := TRUE; // issue alert if patient data is missing
alert_limited_locations := FALSE; // no alerts for particular patient locations
/* Insert the CV3Location.Code for each location that will not issue alerts in this list */
no_alert_locations := ("NGH |1C |","NGH |2A |");
/* The facility must map its Dictionary Codes to the Core UOM in the Units of Measure */
/* Dictionary. The MLM converts the facility-defined units of measure to the System- */
/* defined values in the Unit of Measure Dictionary called CoreUOM. */
lb_string:= "lb";
gm_string:= "g";
kg_string:= "kg";
M2_string:= "M2";
ounce_string:= "oz";
day_string:= "day";
month_string:= "month";
week_string:= "week";
year_string:= "year";
/* Change the message within the quotes if a different short-message is needed.*/
dose_exceeded_alert := destination { Alert: Warning, "Daily Dosage Exceeded", high,
chart, "Dosage Administration Alert", 5010,"DoNotSend",
"Must Acknowledge and Comment" };
/* Called on scanning event for Tasks */
medication_scan := event {OrderTaskOccurrenceIntendToAdmin User OrderTaskOccurrence :
WHERE OrderTask.TaskSeqNum = 0};
/***************************************************************************************/
/* DO NOT CHANGE the following System-defined values */
age_total_daily_dose_string:= "Age - Total Daily";
BSA_total_daily_dose_string:= "BSA - Total Daily";
weight_total_daily_dose_string:= "Weight - Total Daily";
continue_processing := TRUE;
found_range:= FALSE;
found_total_daily_dose:= FALSE;
more_than_one_task_in_sum := FALSE;
first_dose_given := FALSE;
mismatched_occ_uom_found := FALSE;
mismatched_med_uom_found := FALSE;
missing_data_error := FALSE;
missing_age := FALSE;
missing_weight := FALSE;
missing_height := FALSE;
past_administered_doses := 0;
pharmacy_verified_current := FALSE;
pharmacy_verified_all_past := FALSE;
err_msg := "";
missing_data_msg := "";
mismatched_past_occurrences_msg := "";
mismatched_occ_uom_msg := "";
mismatched_med_uom_msg := "";
alert_detail_text := "";
alert_msg := "none";
/* Execute only when this MLM is called by the editor */
if called_by_editor then
task_obj:= read last
{OrderTaskOccurrence: This,
WHERE TaskName = "Ampicillin Dosage:500"
and EXIST TaskDose
// AND SignificantDtm = 2004-11-17T15:00:00
AND TaskStatusCode = "Performed"
};
EvokingObject:= task_obj;
endif;
/* Declare MLMs which can be called */
find_daily_dose_range := MLM {{{SINGLE-QUOTE}}}std_func_total_daily_dose_cat{{{SINGLE-QUOTE}}} ;
calculate_BSA:= MLM {{{SINGLE-QUOTE}}}sys_calc_BSA{{{SINGLE-QUOTE}}};
/* Declare function for adding commas into numbers */
add_commas := MLM {{{SINGLE-QUOTE}}}SYS_FORMAT_NUMBER{{{SINGLE-QUOTE}}};
/**************************************************************************************/
/* Check Client location immediately if if client in "no alert" location, if so, exit */
/**************************************************************************************/
if alert_limited_locations
then
/* Get the patient{{{SINGLE-QUOTE}}}s current location, assigned or temporary */
if called_by_editor then
patient_loc_guid:= read last
{ClientVisit: BusinessRuleLocationGUID };
else
patient_loc_guid:= read last
{ClientVisit: BusinessRuleLocationGUID};
endif; /* if called by editor */
/* Get the Code for the GUID */
patient_loc_code:= read last
{"SELECT Code "
|| " FROM CV3Location "
|| " WHERE GUID = "|| SQL (patient_loc_guid)
, PrimaryTime = TouchedWhen };
endif; /* if alert_limited_locations */
if (patient_loc_code in no_alert_locations) AND alert_limited_locations
then
continue_processing := FALSE;
else
/*******************************************************(****************/
/* Get current task occurrence data - use to get Dose Range Criteria */
/************************************************************************/
/* Get information from the Current Evoking OrderTaskOccurrence */
(occurrence_name,
occurrence_guid,
occurrence_client_guid,
occurrence_summary_line,
occurrence_dose,
occurrence_uom,
occurrence_route,
occurrence_status_code,
occurrence_catalog_item_task_guid,
occurrence_order_guid,
occurrence_significant_dtm,
occurrence_performed_from_dtm,
order_obj,
order_task_obj,
back_up_obj ) := read last
{OrderTaskOccurrence: TaskName, GUID, ClientGUID, SummaryLine,
TaskDose, TaskUOM, TaskRouteCode, TaskStatusCode,
CatalogItemTaskGUID, OrderGUID, SignificantDtm,
PerformedFromDtm, Order, OrderTask, Backup
REFERENCING EvokingObject};
/* Get the reference to the current order{{{SINGLE-QUOTE}}}s Dosage Information */
(order_name,
order_med_uom,
order_med_route,
order_med_frequency,
order_med_significant_date,
chart_guid,
order_guid,
order_catalog_item_obj,
order_component_obj,
order_CMI_GUID,
order_GUID ) := read last
{ Order: Name, UOM, OrderRouteCode,
FrequencyCode, SignificantDtm, ChartGUID, GUID,
OrderCatalogMasterItem, OrderComponent,
OrderCatalogMasterItemGUID, GUID
REFERENCING order_obj};
/* Get the reference to the CatalogItemDosage object */
ordercatalog_item_dosage_obj:= read last
{OrderCatalogMasterItem: CatalogItemDosage REFERENCING order_catalog_item_obj };
/* Get the dosage range HIGH info from the item-catalog. */
/* Match to the order route and one of the Total Daily Dose Criteria Type Codes. */
(total_daily_range_high_codes,
total_daily_range_units,
total_daily_range_units_per,
total_daily_criteria_lows,
total_daily_criteria_highs,
total_daily_criteria_units,
total_daily_gender_code):= read { CatalogItemDosage:
RangeHigh,
RangeUom,
RangePerUom,
CriteriaTypeLow,
CriteriaTypeHigh,
CriteriaTypeUom,
GenderCode
REFERENCING ordercatalog_item_dosage_obj
WHERE RouteCode = order_med_route
AND CriteriaTypeCode is in (age_total_daily_dose_string,
BSA_total_daily_dose_string, weight_total_daily_dose_string ) };
/* Only retrieve other data if the medication has a Total Daily Dosage range */
If exist(total_daily_range_high_codes) and any (total_daily_range_high_codes > 0)
then
/* Get the patient{{{SINGLE-QUOTE}}}s birthday and other relevant data */
(client_guid,
client_birthdate,
client_birthMonthNum,
client_gender,
client_gender_internal,
client_info_obj ) := read last
{ ClientInfo: GUID, BirthDateTime, BirthMonthNum, GenderCode,
GenderTypeIntlCode, this, };
If NOT exists client_birthdate
then
missing_age:= TRUE;
missing_data_msg := missing_data_msg ||"\nPatient{{{SINGLE-QUOTE}}}s age must be entered "
||"to check Dose Range Limits. ";
endif;
/****************************************************/
/* Get Site Preferences for height, weight and BSA */
/****************************************************/
/* Get the BSA calculation preference */
/* This SQL statement will cause a table scan */
/* But the table only has 400 rows, so the impact is minimal */
BSA_formula_preference:= read last
{"SELECT Value "
|| " FROM HVCEnvProfile "
|| " WHERE Code = {{{SINGLE-QUOTE}}}BSAFormula{{{SINGLE-QUOTE}}} "
|| " AND HierarchyCode = {{{SINGLE-QUOTE}}}Client Info{{{SINGLE-QUOTE}}} " };
/* Retrieve the facility{{{SINGLE-QUOTE}}}s scope pref for HEIGHT */
general_scope_for_ht := read last
{"SELECT case when ScopeLevel = 3 then 1 else 0 end "
|| " FROM CV3PhysicalNoteType "
|| " WHERE Code = " || SQL("HEIGHT")};
/* Set the scope to retrieve the Height */
if general_scope_for_ht = 1
then ht_patient_chart_str:= "";
else ht_patient_chart_str:= " AND ChartGUID = " || SQL(chart_guid);
endif;
/* Retrieve the facility{{{SINGLE-QUOTE}}}s scope preference for WEIGHT */
general_scope_for_wt := read last
{"SELECT case when ScopeLevel = 3 then 1 else 0 end "
|| " FROM CV3PhysicalNoteType "
|| " WHERE Code = " || SQL("WEIGHT")};
/* Set the scope to retrieve the Weight */
if general_scope_for_wt = 1
then wt_patient_chart_str:= "";
else wt_patient_chart_str:= " AND ChartGUID = " || SQL(chart_guid);
endif;
/****************************************************/
/* Retrieve height and weight from the database */
/****************************************************/
/* Retrieve Height*/
/* Warning--keep this SQL in synch with business rules on patient height */
(ht_cm_str,
ht_date) := read last
{"SELECT Text, TouchedWhen "
|| " FROM CV3PhysicalNoteDeclaration"
|| " WHERE ClientGUID = " || SQL(client_guid)
|| ht_patient_chart_str
|| " AND Active = 1 "
|| " AND TypeCode = " || SQL("HEIGHT")
|| " AND Status = " || SQL("Active")
, PrimaryTime = TouchedWhen };
/* Convert height strings to numbers */
ht_cm:= ht_cm_str as number;
/* Retrieve patient{{{SINGLE-QUOTE}}}s actual current weight (expected in grams) */
/* Warning--keep this SQL in synch with
business rules on patient weight */
(wt_gm_str,
wt_date) := read last
{"SELECT Text, TouchedWhen "
|| " FROM CV3PhysicalNoteDeclaration"
|| " WHERE ClientGUID = "
|| SQL(client_guid)
|| wt_patient_chart_str
|| " AND Active = 1 "
|| " AND TypeCode = " || SQL("WEIGHT")
|| " AND Status = " || SQL("Active")
, PrimaryTime = TouchedWhen };
/* Convert weight string to number and convert grams to kilograms */
wt_kg := (wt_gm_str as number)/1000;
/*------------------------*/
/* CHECK FOR MISSING DATA */
/*------------------------*/
/* Check to see if height is present */
if ht_cm is number
and ht_cm > 0
then
missing_height := FALSE;
else
missing_height:= TRUE;
missing_data_msg := missing_data_msg || "\nPatient{{{SINGLE-QUOTE}}}s height must be "
||"entered to check Dose Range Limits. ";
endif;
/* Check to see if weight is present */
if wt_kg is number
and wt_kg > 0
then
missing_weight := FALSE;
else
missing_weight := TRUE;
missing_data_msg := missing_data_msg ||"\nPatient{{{SINGLE-QUOTE}}}s weight must be "
||"entered to check Dose Range Limits. ";
endif;
/* Check to see if gender is required for any dose critiera */
if any(total_daily_gender_code) <> NULL
then
if not exist client_gender
then
missing_gender := TRUE;
missing_data_msg := missing_data_msg ||"\nPatient{{{SINGLE-QUOTE}}}s gender must be "
||"entered to check Dose Range Limits. ";
endif;
endif; /* Check to see if gender is required */
/* No point in continuing if critial data is missing */
If missing_height and missing_weight and missing_age
then
missing_data_error := TRUE;
endif; /* If missing ht,wt, and age */
/*-------------------*/
/* Calculate the BSA */
/*-------------------*/
If NOT missing_height and NOT missing_weight
then
BSA_number_rounded:= Call calculate_BSA with
BSA_formula_preference,
ht_cm,
wt_kg,
client_info_obj;
endif; /* If NOT missing height or weight */
/* Get the Units of Measure info */
(uom_facility_code,
uom_sys_code):= read
{"SELECT Code, CoreUOM "
|| " FROM CV3UnitOfMeasure"
|| " WHERE Active = 1" };
/****************************************************************/
/* Get the first Total Daily range that applies to this patient */
/****************************************************************/
// This paramenter can be blank and return Total Daily criteria.
order_med_per_uom := "";
(found_total_daily_dose,
total_daily_dose_calc_method,
total_daily_lower_dose,
total_daily_upper_dose,
total_daily_units,
total_daily_per_uom,
total_daily_type_name ):= call find_daily_dose_range with
(age_total_daily_dose_string,
client_birthdate,
client_birthmonthnum,
BSA_number_rounded,
BSA_total_daily_dose_string,
order_catalog_item_obj,
day_string,
order_name,
gm_string,
kg_string,
lb_string,
m2_string,
month_string,
order_med_per_uom,
order_med_route,
order_med_significant_date,
order_med_uom,
ounce_string,
client_gender_internal,
uom_facility_code,
uom_sys_code,
week_string,
weight_total_daily_dose_string,
wt_kg,
year_string);
if found_total_daily_dose
then
// check if the order uom mataches the order task occurence uom
mismatched_med_uom_found := (order_med_uom <> occurrence_uom);
/********************************************************************/
/* Obtain the past administerations based on matching OrderGUID */
/********************************************************************/
/* Set interval to look back for administered doses */
past_start_time := occurrence_performed_from_dtm - 24 hours;
/* Get a list of past 24 hours administrations of this med */
(past_occurrences_dose_list,
past_occurrences_UOM_list,
past_occurrences_route_list,
past_occurrences_name_list,
past_occurrences_PerformedDtm_list,
past_occurrences_OrderGUID_list,
past_occurrences_order_RxStatusType ):= Read
{" SELECT oto.TaskDose, "
|| " oto.TaskUom, "
|| " oto.TaskRouteCode, "
|| " oto.TaskName, "
|| " ConvPerformedFromDtm.TimeValue as PerformedFromDtmOffset, "
|| " oto.OrderGUID, "
|| " me.RxStatusType "
|| " FROM CV3OrderTaskOccurrence oto JOIN CV3MedicationExtension me ON"
|| " oto.OrderGUID = me.GUID"
|| " JOIN CV3Order o ON"
|| " o.ClientGUID = oto.ClientGUID AND o.GUID = oto.OrderGUID"
|| " JOIN CV3ClientVisit cv ON"
|| " o.ClientGUID = cv.ClientGUID AND o.ClientVisitGUID = cv.GUID"
|| " CROSS APPLY dbo.SXADBConvertLocalToOffsetTblFn(cv.TimeZone, oto.PerformedFromDtm) AS ConvPerformedFromDtm "
|| " WHERE oto.ClientGUID = "
|| SQL(occurrence_client_guid)
|| " AND oto.CatalogItemTaskGUID = "
|| SQL(occurrence_catalog_item_task_guid)
|| " AND oto.PerformedFromDtm >= "
|| SQL(past_start_time)
|| " AND oto.PerformedFromDtm < "
|| SQL(occurrence_performed_from_dtm)
|| " order by oto.PerformedFromDtm"};
/************************************************************************/
/* Step through the list to add each to the total or to error message. */
/************************************************************************/
If exist past_occurrences_dose_list
then
first_dose_given := FALSE;
/* Check to see if all past orders were verified */
if ANY past_occurrences_order_RxStatusType <> 2
then
pharmacy_verified_all_past := FALSE;
endif; /* if any past type <>2 */
// step through the list and sum the past doses with matching uom
list_index := 1 seqto (count past_occurrences_dose_list);
for x in list_index do
temp_dose := first
(past_occurrences_dose_list where list_index = x);
temp_uom := first
(past_occurrences_uom_list where list_index = x);
temp_route := first
(past_occurrences_route_list where list_index = x);
temp_name := first
(past_occurrences_name_list where list_index = x);
temp_performed := first
(past_occurrences_PerformedDtm_list where list_index = x);
temp_order_GUID := first
(past_occurrences_OrderGUID_list where list_index = x);
if temp_order_GUID <> occurrence_order_guid
then
more_than_one_task_in_sum := TRUE;
endif;
if temp_uom = occurrence_uom
then
temp_dose := temp_dose as number;
past_administered_doses :=
past_administered_doses + temp_dose;
else
mismatched_occ_uom_found := TRUE;
temp_occurrence := "\n"||temp_name||" "
||temp_dose||" "||temp_uom||" "||temp_route
||" administered on " ||temp_performed;
mismatched_past_occurrences_msg :=
mismatched_past_occurrences_msg,temp_occurrence;
endif; /* if temp_uom = occurrence_uom */
enddo; // step through the list and sum
else
more_than_one_task_in_sum := FALSE;
first_dose_given := TRUE;
endif; /* If exist past_occurrences_dose_list */
/* For first dose or single order event, check for alert at order entry */
if first_dose_given and NOT more_than_one_task_in_sum
then
(alert_match_guid):= Read
{" SELECT CV3AlertDeclaration.GUID"
|| " FROM CV3AlertDeclaration "
|| " WHERE CV3AlertDeclaration.pObjectGUID = "
|| SQL(occurrence_order_guid)
|| " AND CV3AlertDeclaration.MLMName = {{{SINGLE-QUOTE}}}STD_DOSAGE{{{SINGLE-QUOTE}}}"
, PrimaryTime = SignificantDtm };
if exists alert_match_guid
then
alert_at_order := TRUE;
/* Check to see if phamacy verified this order */
(Rx_verify_type_2):= Read
{" SELECT CV3MedicationExtension.RxStatusType"
|| " FROM CV3MedicationExtension "
|| " WHERE CV3MedicationExtension.GUID = "
|| SQL(occurrence_order_guid)
|| " AND CV3MedicationExtension.RxStatusType = 2" };
if exists Rx_verify_type_2
then
pharmacy_verified_current := TRUE;
endif;
endif; /* if exists alert_match_guid */
endif; /* if first_dose */
/* Add the current dose being scanned to the past administered dose */
total_dose:= (occurrence_dose as number) + past_administered_doses;
/* Compose Alert Message now that the data has been obtained. */
If total_daily_type_name = "Age - Total Daily"
then
Alert_msg := "Based on this patient{{{SINGLE-QUOTE}}}s age, ";
elseIf total_daily_type_name = "Weight - Total Daily"
then
Alert_msg := "Based on this patient{{{SINGLE-QUOTE}}}s weight, ";
else
Alert_msg := "Based on this patient{{{SINGLE-QUOTE}}}s BSA, ";
endif; /* If total_daily_type_name */
/* Round to the nearest 0.001 */
total_daily_upper_dose_rounded:= ((((int((total_daily_upper_dose
+ 0.00051)*1000))/1000 )
formatted with "%.4f") AS NUMBER);
total_daily_upper_dose_rounded := call add_commas
with ( total_daily_upper_dose_rounded );
total_dose_rounded:= ((((int((total_dose
+ 0.00051)*1000))/1000)
formatted with "%.4f") AS NUMBER);
total_dose_rounded := call add_commas
with ( total_dose_rounded);
Alert_msg:= Alert_msg || "the Total Daily Dose"
|| " for a patient fitting this profile and route is: "
|| total_daily_upper_dose_rounded
|| " " || order_med_uom || "."
|| "\nWith this dose, in the past 24 hours this "
|| "patient will have received : "
|| "\n {{+B}}{{+C}}Dose Total{{-B}}{{-C}}(in 24 hours): {{+B}}{{+C}}"
|| total_dose_rounded
|| " " || occurrence_uom || " {{-B}}{{-C}}" ;
mismatched_occ_uom_msg := "\n{{+B}}The following tasks have a different "
|| "unit of measure. {{-B}}"
|| "\nTherefore, they have not been included in calculations. "
|| "Please manually verify if the current dosage will "
|| "exceed the Total Daily Dose Range limits."
|| mismatched_past_occurrences_msg;
If Alert_msg = "none"
then
Alert_msg := mismatched_occ_uom_msg;
endif; /*If Alert_msg := "none" */
If mismatched_med_uom_found
then
mismatched_med_uom_msg := "\n\n{{+B}}The administered dose for the current task has a different "
|| "unit of measure compared to the original medication{{{SINGLE-QUOTE}}}s unit of measure. {{-B}}\n"
|| "The current task dose unit of measure is {{+B}}{{+C}}" || occurrence_uom || "{{-B}}{{-C}}"
|| " whereas the medication was ordered in {{+B}}{{+C}}" || order_med_uom || "{{-B}}{{-C}}.\n\n"
|| "Please manually verify if the current dosage will "
|| "exceed the Total Daily Dose Range limits.";
Alert_msg := Alert_msg || mismatched_med_uom_msg;
endif;
If mismatched_occ_uom_found
then
Alert_msg := Alert_msg|| "\n"|| mismatched_occ_uom_msg;
endif; /* if mismatched_occ_uom_found */
else
if missing_height or missing_age or missing_weight or missing_gender
then
missing_data_error := TRUE;
endif;
endif; /* if found_total_daily_dose ... */
else
// if NO Total Daily Dose criteria then stop processing
continue_processing:= false;
endif; /* If exist(total_daily_range_high_codes) */
endif; /* if patient_loc_code in no_alert_locations */
;;
evoke:
medication_scan;
;;
logic:
/* Stop Processing MLM when continue_processing was false. */
if NOT continue_processing
OR (alert_at_order
AND
((pharmacy_verified_current AND pharmacy_verified_all_past AND no_alert_if_RxVerified)
OR(pharmacy_verified_current AND NOT more_than_one_task_in_sum)))
then
conclude false;
endif;
If exists total_dose
AND exists total_daily_upper_dose
AND (total_dose > (total_daily_upper_dose as number))
AND order_med_uom = occurrence_uom
then
alert_detail_text := "{{+B}}{{+C}}{{+U}}"
|| "Total Daily Dose Exceeded for " || order_name
|| "{{-U}}{{-B}}{{-C}}\n\n" || Alert_msg;
conclude true;
elseif missing_data_error AND alert_if_patient_data_missing
then
err_msg := "{{+B}}There are dose range limits set for this drug. However, "
|| "Total Daily Dose Limits could not be checked due to "
|| "missing patient data:{{-B}} " || missing_data_msg;
conclude true;
elseif mismatched_med_uom_found
then
alert_detail_text := "{{+B}}{{+C}}{{+U}}"
|| "Total Daily Dose Checking Not Performed{{-U}}{{-B}}{{-C}}\n\n"
|| Alert_msg;
conclude true;
elseif mismatched_occ_uom_found
then
alert_detail_text := "{{+B}}{{+C}} {{+U}}"
|| "Total Daily Dose could not be determined{{-U}}{{-B}}{{-C}}\n\n"
|| Alert_msg;
conclude true;
else
conclude false;
endif;
;;
action:
/* Create an alert message */
If missing_data_error then
write err_msg
at dose_exceeded_alert;
else
write alert_detail_text
at dose_exceeded_alert;
endif;
;;
Urgency: 60;;
end:

View File

@@ -0,0 +1,947 @@
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:

View File

@@ -0,0 +1,102 @@
maintenance:
title: Visit Record Package at Print;;
mlmname: STD_VR_CHART_PACKAGE_PRINT;;
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) 2016 - 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: If all components are configured, this MLM generates an external file of the Visit Record when it is printed from the application. The file
is encrypted. It will have the same content and formatting as if it were printed.
;;
explanation: Several settings must be configured this MLM to be evoked.
1. Site must have an SFTP server.
2. A package definition must be defined in the Visit Record Configuration tool (Chart Packaging Definition).
3. In Visit Record Definition, the package definition name must be selected from the Package at Print area.
See the Visit Record Installation and Configuration Guide for more details.
;;
keywords: Visit Record;Chart Package;Package
;;
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}}: 2017-04-21
;;
knowledge:
type: data-driven;;
data:
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
//*** calling the package Logic ***//
//
// Specify which .NET assemblies need to be loaded for ObjectsPlus
//Defines the alert in case of error
Error_occurred := false;
error_destination := destination { Alert } with [
alert_type := "Warning",
short_message := "Chart Packaging at Print Error from MLM",
priority := "low",
scope := "chart",
Rule_group := "Chart Packaging at Print Error from MLM",
Rule_number := 1003,
Rule_subgroup := "",
Send_with_order := "",
Alert_dialog_settings := "",
Display_alert := true ];
//***********************************************************************************************
clientVisitObject := read last { ClientVisit: this };
stateInfoObject := read last { StateInfo: this};
//Call Chart Packaging at Printing here
using "Sunrise.ChartPackaging.Processor";
using namespace "Sunrise.ChartPackaging.Processor";
try
PackagingClass := NEW NET_Object {{{SINGLE-QUOTE}}}Packaging{{{SINGLE-QUOTE}}};
ApplicationName := "Emergency Care";
void := call PackagingClass.CreatePackageFromPrintJob with (clientVisitObject.GUID);
endtry;
catch exception ex0
Error_occurred := true;
error_message := ex0.Message;
endcatch;
;;
priority: 50
;;
evoke:
;;
logic:
conclude true;
;;
action:
if (Error_occurred) then
write error_message AT error_destination;
endif;
;;
Urgency: 50;;
end: