Files
St.Clair/MLMStripper/bin/Debug/FUNC/FUNC_ACS_ALLERGY_SUPPRESS_ALERT.mlm

473 lines
19 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
maintenance:
title: Check Allergy Already Alerted;;
mlmname: FUNC_ACS_ALLERGY_SUPPRESS_ALERT;;
arden: version 2.5;;
version: 16.3;;
institution: Allscripts, Standard MLM;;
author: Allscripts Healthcare Solutions, Inc.;;
specialist: ;;
date: 2016-12-20;;
validation: testing;;
/* P r o p r i e t a r y N o t i c e */
/* Unpublished (c) 2013 - 2015 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: In keeping with alert reduction efforts, work out a way in SCM that when an allergy override has been addressed once,
SCM retains that information and no alert is fired again.
;;
explanation:
If an allergy alert exists in the CV3AlertDeclaration table for this patient, this visit,
and the ingredients of the triggering order are the same and the allergen is the same and
the ordering provider has an OrderRoleType like {{{SINGLE-QUOTE}}}%physician%{{{SINGLE-QUOTE}}} or OrderRoleType = {{{SINGLE-QUOTE}}}CRNP{{{SINGLE-QUOTE}}} or
OrderRoleType = {{{SINGLE-QUOTE}}}PA-C{{{SINGLE-QUOTE}}} the allergy alert should be supressed.
Code changes such that if the physicians decide to only alert once per visit, regardless
of who receives the first alert (%physician%, CRNP, or PA-C) the change can be made by changing
a parameter in the MLM.
All other providers (non-physician, non-physician extenders) will continue to receive allergy alerts as they are currently presented to the end user.
Change History:
12.14.2017 JBickley Created CSR 35068
05.21.2018 TSpicuzza Add logic to only suppress alerts for appropriate users when they are members of the Emergency Department
which is being used as the pilot unit beginning on 5/21/2018. CSR 35068
;;
keywords: allergy; ;;
citations:
;;
knowledge:
type: data-driven;;
data:
(EvokingObject) := argument;
// Specify which .NET assemblies need to be loaded for ObjectsPlus
standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}};
include standard_libs;
// Set to true if logging is needed.
log_execution_info := false;
//***************Make Changes To Spelling And Flags In This Section*************
SuppressAlertOnlyIfCurrentUserHasSeen := true;
SuppressAlertOnlyIfCurrentUserHasAcknowledged := true;
SuppressAlertOnlyIfAlertProceeded := true;
SuppressAlertOnlyIfAlertAcknowledged := true;
SuppressCrossDrugKey := true;
SuppressCrossDrugComponents := true;
PilotDepartment := read last { "select GUID from CV3OrganizationalUnit where name = {{{SINGLE-QUOTE}}}Emergency Department{{{SINGLE-QUOTE}}}"};
// OrderRoleTypesToSuppressSecondaryAlert := read {"select Code from CV3OrderRoleType where Active = 1 and (Code like {{{SINGLE-QUOTE}}}%physician%{{{SINGLE-QUOTE}}} or Code = {{{SINGLE-QUOTE}}}CRNP{{{SINGLE-QUOTE}}} or Code = {{{SINGLE-QUOTE}}}PA-C{{{SINGLE-QUOTE}}})"};
OrderRoleTypesToSuppressSecondaryAlert := read {"select Code from CV3OrderRoleType where Active = 1 and (Code like {{{SINGLE-QUOTE}}}%ed physician%{{{SINGLE-QUOTE}}} or Code = {{{SINGLE-QUOTE}}}CRNP{{{SINGLE-QUOTE}}} or Code = {{{SINGLE-QUOTE}}}PA-C{{{SINGLE-QUOTE}}})"};
//assume the default is to alert the user
SuppressAlert := false;
SuppressAlertReason := "";
/* Get the current user info*/
(user_id,userguid) := read last {UserInfo: idcode, guid};
(ClientGUID, ChartGUID, ClientVisitGUID) := read last {StateInfo: ClientGUID, ChartGUID, VisitGUID};
OrderRoleType := read last
{"Select OrderRoleType "
||" From cv3user with (nolock) "
||" Where Guid = " || SQL(userguid)
||" and OrgUnitGUID = " || PilotDepartment };
/* OrderRoleType := read last
{"Select OrderRoleType "
||" From cv3user with (nolock) "
||" Where Guid = " || SQL(userguid) };
*/
if(called_by_editor)then
//ClientGUID := 3400200;
//ChartGUID := 3400170;
//ClientVisitGUID := 3400270;
// Define object choice "Order", or "ClientPrescription"
Object_Choice :=
//"ClientPrescription";
//"Allergy";
"Order";
if (object_choice = "Order") then
EvokingObject:= read last
{Order: This
WHERE TypeCode = "Medication"
//AND Name = "Acetaminophen 650 mg suppository"
//AND Name = "Tylenol Caplet 500 mg - Oral"
//AND Name = "Acetaminophen-Codeine #3"
//AND Name = "ibuprofen"//"Acetaminophen"
AND Name = "acetaminophen + oxyCODONE 325 mg-5 mg"
};
//EvokingEventType := entered_order.type;
elseif (object_choice = "Allergy") then
EvokingObject:= read last
{Allergy: This};
//EvokingEventType := entered_allergy.type;
else
EvokingObject:= read last
{ClientPrescription: This
WHERE PrescriptionTypeDescription in ("Rx", "Hx")
};
//EvokingEventType := prescription_enter.Type;
endif;
endif;
AlertObj := OBJECT [UserGUID
,Status
,AcknowledgedUserName
,AcknowledgedUserGUID
,PObjectName
,PObjectGUID
,AlertRepositoryGUID
,PrimaryProviderGUID
,Abstract
,TriggeringInfo
,OrderName ];
query := "select alert.UserGUID
,alert.Status
,alert.AcknowledgedUserName
,alert.AcknowledgedUserGUID
,alert.PObjectName
,alert.PObjectGUID
,alert.GUID
,alert.PrimaryProviderGUID
,alert.Abstract
,alert.TriggeringInfo
,o.Name
from CV3AlertRepository alert
left outer join CV3Order o on o.ClientGUID = alert.ClientGUID and o.ChartGUID = alert.ChartGUID and o.GUID = alert.PObjectGUID
left outer join SXAAMBClientPrescription cp on cp.ClientGUID = alert.ClientGUID and cp.ClientVisitGUID = alert.ClientVisitGUID and cp.CDSUniqueIDGUID = alert.PObjectGUID
where alert.MLMName = {{{SINGLE-QUOTE}}}STD_ALLERGY{{{SINGLE-QUOTE}}}
and alert.ClientGUID = " || ClientGUID
//|| " and alert.ChartGUID = " || ChartGUID
|| " and alert.ClientVisitGUID = " || ClientVisitGUID;
Alerts := read as AlertObj {""||query};
if(SuppressAlertOnlyIfCurrentUserHasSeen)then
Alerts := Alerts Where Alerts.UserGUID = userguid;
endif;
if(SuppressAlertOnlyIfCurrentUserHasAcknowledged)then
Alerts := Alerts Where Alerts.AcknowledgedUserGUID = userguid;
endif;
if(SuppressAlertOnlyIfAlertProceeded)then
Alerts := Alerts Where Alerts.OrderName is not null;
endif;
if(SuppressAlertOnlyIfAlertAcknowledged)then
Alerts := Alerts Where Alerts.Status = "Ack";
endif;
if(count(Alerts) > 0)then
if (EvokingObject IS ClientPrescription) then
evoked_from_prescriptions := true;
display_alert_types := display_prescription_alert_other_types,
allergen_type_string;
(evoking_prescription_description,
evoking_prescription_name,
evoking_prescription_NameID,
alert_on_demand_source,
client_guid
) := read last
{ ClientPrescription: PrescriptionTypeDescription, DrugName, GenericNameID, AlertOnDemandSource,
ClientGUID
REFERENCING EvokingObject };
elseif (EvokingObject IS Order) then
evoked_from_prescriptions := false;
display_alert_types:= display_order_alert_other_types,
allergen_type_string;
// Get the order component object associated with the evoking order
(evoking_order_name,
evoking_cat_item_guid,
order_type,
OrdComponentObj,
PharmOrderObj,
evoking_complex_order_type,
OrderVariableComponentObj,
alert_on_demand_source,
client_guid,
alternate_order_type,
AdditionalInfoObj,
BackupObj
) := read last
{ Order: Name, OrderCatalogMasterItemGUID, TypeCode, OrderComponent,
PharmacyOrder, ComplexOrderType, OrderVariableComponent,
AlertOnDemandSource, ClientGUID,
AlternateOrderType, OrderAdditionalInfo, Backup
REFERENCING EvokingObject };
endif;
DrugMappingObj := OBJECT [ocmi_GUID,ocmi_Name,ocmi_TherapeuticCategoryID,TherapeuticCategory,DBStatus,DrugKey,DrugName,DrugSynonymID,function_id,OriginalTouchedWhen,DrugMappingTouchedWhen,GenericName,MMDC,AlternateMappingName,DrugMappingXrefTouchedWhen,IsObsolete];
DrugMappingComponentObj := OBJECT [ocmi_GUID, ocmi_Name, Multum_drug_id, Multum_drug_name ];
ThisOrderDrugMappingDataSQL :=
"DECLARE @OrderName varchar(200) = " || SQL(evoking_order_name) || "
SELECT
ocmi.GUID,
ocmi.Name,
ocmi.TherapeuticCategoryID,
TherapeuticCategory = CASE
WHEN ocmi.TherapeuticCategoryID > 0 THEN
(SELECT category_name FROM SXAMTDrugCategoriesVW
WHERE multum_category_id = ocmi.TherapeuticCategoryID)
ELSE {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}
END,
DBStatus = CASE
WHEN DrugKey IS NOT NULL THEN {{{SINGLE-QUOTE}}}M{{{SINGLE-QUOTE}}}
WHEN DrugKey IS NULL AND ISNULL(IsIgnored,0) = 1 THEN {{{SINGLE-QUOTE}}}I{{{SINGLE-QUOTE}}}
ELSE {{{SINGLE-QUOTE}}}U{{{SINGLE-QUOTE}}}
END,
DrugKey = ISNULL(dm.DrugKey,{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
DrugName = ISNULL(dnv.drug_name,{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
xref.DrugSynonymID,
function_id =
(SELECT MIN(function_id)
FROM SXAMTDrugNameMapVw AS dnm
WHERE dnv.drug_synonym_id = dnm.drug_synonym_id
AND function_id <> 29 ),
OriginalTouchedWhen = ocmi.TouchedWhen,
DrugMappingTouchedWhen = dm.TouchedWhen,
GenericName = CASE
WHEN DrugKey IS NOT NULL THEN
(SELECT drug_name FROM SXAMTDrugNameVW vw
INNER JOIN SXAMTDrugNameMapVW map ON (vw.drug_synonym_id = map.drug_synonym_id)
WHERE function_id = 16 AND drug_id = DrugKey)
ELSE {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}
END,
MMDC = CASE
WHEN xref.DrugSynonymID IS NOT NULL THEN
(SELECT top 1
mmdcXRef.MainMultumDrugCode
FROM SXAMTDrugNameVW AS mtDN
INNER JOIN SXAAMBDrugName AS dn ON dn.DrugCatalogKey = mtDN.drug_synonym_id
INNER JOIN SXAAMBDrugNameMMDCXRef AS mmdcXRef ON mmdcXRef.DrugNameID = dn.DrugNameID
INNER JOIN SXAMTNdcMainMultumDrugCodeVW AS mtMMDC ON mtMMDC.main_multum_drug_code = mmdcXRef.MainMultumDrugCode
INNER JOIN SXAAMBClinicalDataFunctionType AS ft ON ft.FunctionTypeID = mmdcXRef.FunctionTypeID
WHERE mtDN.drug_synonym_id = DrugSynonymID AND ft.DrugCatalogKey IN (59,60) )
ELSE NULL
END,
AlternateMappingName = ISNULL(ocmi.AlternateMappingName, {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
DrugMappingXrefTouchedWhen = xref.TouchedWhen,
IsObsolete = dnv.is_obsolete
from
Cv3OrderCatalogMasterItem AS ocmi
INNER JOIN CV3OrderEntryForm oef ON (ocmi.EntryFormGUID = oef.GUID AND OrderTypeCode = {{{SINGLE-QUOTE}}}Medication{{{SINGLE-QUOTE}}})
LEFT OUTER JOIN CV3DrugMapping AS dm ON (ocmi.GUID = dm.CatalogItemGUID)
LEFT OUTER JOIN CV3DrugMappingXref AS xref ON (ocmi.GUID = xref.CatalogItemGUID AND xref.IsDefaultSynonym = 1)
LEFT OUTER JOIN SXAMTDrugNameVw AS dnv ON (xref.DrugSynonymID = dnv.drug_synonym_id)
AND dnv.is_obsolete = {{{SINGLE-QUOTE}}}F{{{SINGLE-QUOTE}}}
WHERE
ocmi.Name = @OrderName";
ThisOrderDrugMapping := read AS DrugMappingObj last {"" || ThisOrderDrugMappingDataSQL};
if(SuppressCrossDrugKey)then
OtherOrderDrugMappingDataByDrugKeySQL :=
"SELECT
ocmi.GUID,
ocmi.Name,
ocmi.TherapeuticCategoryID,
TherapeuticCategory = CASE
WHEN ocmi.TherapeuticCategoryID > 0 THEN
(SELECT category_name FROM SXAMTDrugCategoriesVW
WHERE multum_category_id = ocmi.TherapeuticCategoryID)
ELSE {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}
END,
DBStatus = CASE
WHEN DrugKey IS NOT NULL THEN {{{SINGLE-QUOTE}}}M{{{SINGLE-QUOTE}}}
WHEN DrugKey IS NULL AND ISNULL(IsIgnored,0) = 1 THEN {{{SINGLE-QUOTE}}}I{{{SINGLE-QUOTE}}}
ELSE {{{SINGLE-QUOTE}}}U{{{SINGLE-QUOTE}}}
END,
DrugKey = ISNULL(dm.DrugKey,{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
DrugName = ISNULL(dnv.drug_name,{{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
xref.DrugSynonymID,
function_id =
(SELECT MIN(function_id)
FROM SXAMTDrugNameMapVw AS dnm
WHERE dnv.drug_synonym_id = dnm.drug_synonym_id
AND function_id <> 29 ),
OriginalTouchedWhen = ocmi.TouchedWhen,
DrugMappingTouchedWhen = dm.TouchedWhen,
GenericName = CASE
WHEN DrugKey IS NOT NULL THEN
(SELECT drug_name FROM SXAMTDrugNameVW vw
INNER JOIN SXAMTDrugNameMapVW map ON (vw.drug_synonym_id = map.drug_synonym_id)
WHERE function_id = 16 AND drug_id = DrugKey)
ELSE {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}
END,
MMDC = CASE
WHEN xref.DrugSynonymID IS NOT NULL THEN
(SELECT top 1
mmdcXRef.MainMultumDrugCode
FROM SXAMTDrugNameVW AS mtDN
INNER JOIN SXAAMBDrugName AS dn ON dn.DrugCatalogKey = mtDN.drug_synonym_id
INNER JOIN SXAAMBDrugNameMMDCXRef AS mmdcXRef ON mmdcXRef.DrugNameID = dn.DrugNameID
INNER JOIN SXAMTNdcMainMultumDrugCodeVW AS mtMMDC ON mtMMDC.main_multum_drug_code = mmdcXRef.MainMultumDrugCode
INNER JOIN SXAAMBClinicalDataFunctionType AS ft ON ft.FunctionTypeID = mmdcXRef.FunctionTypeID
WHERE mtDN.drug_synonym_id = DrugSynonymID AND ft.DrugCatalogKey IN (59,60) )
ELSE NULL
END,
AlternateMappingName = ISNULL(ocmi.AlternateMappingName, {{{SINGLE-QUOTE}}}{{{SINGLE-QUOTE}}}),
DrugMappingXrefTouchedWhen = xref.TouchedWhen,
IsObsolete = dnv.is_obsolete
FROM
CV3DrugMapping AS dm
INNER JOIN Cv3OrderCatalogMasterItem AS ocmi ON (ocmi.GUID = dm.CatalogItemGUID)
INNER JOIN CV3OrderEntryForm oef ON (ocmi.EntryFormGUID = oef.GUID AND OrderTypeCode = {{{SINGLE-QUOTE}}}Medication{{{SINGLE-QUOTE}}})
LEFT OUTER JOIN CV3DrugMappingXref AS xref ON (ocmi.GUID = xref.CatalogItemGUID AND xref.IsDefaultSynonym = 1)
LEFT OUTER JOIN SXAMTDrugNameVw AS dnv ON (xref.DrugSynonymID = dnv.drug_synonym_id)
AND dnv.is_obsolete = {{{SINGLE-QUOTE}}}F{{{SINGLE-QUOTE}}}
WHERE
dm.DrugKey = " || SQL(ThisOrderDrugMapping.DrugKey);
OtherOrdersDrugMappingsByDrugKey := read AS DrugMappingObj {"" || OtherOrderDrugMappingDataByDrugKeySQL};
endif;
if(SuppressCrossDrugComponents)then
SVR,DB := read last {"SELECT @@SERVERNAME,DB_NAME()"};
OtherOrderDrugMappingDataByComponentSQL := "select "
|| " ocmi.GUID, ocmi.Name, mdi.drug_id, mdn.drug_name "
|| " from [" || DB || "_MT].[dbo].multum_drug_id mdi "
|| " join [" || DB || "_MT].[dbo].multum_drug_name mdn "
|| " on mdn.drug_synonym_id = mdi.drug_synonym_id "
|| " join CV3DrugMapping AS dm on dm.DrugKey = mdi.drug_id"
|| " JOIN Cv3OrderCatalogMasterItem AS ocmi ON (ocmi.GUID = dm.CatalogItemGUID) "
|| " where mdi.drug_id in "
|| " (select member_drug_id from [" || DB || "_MT].[dbo].multum_combination_drug mcd "
|| " where mcd.drug_id = " || SQL(ThisOrderDrugMapping.DrugKey) || ")";
OtherOrdersDrugMappingsByComponent := read AS DrugMappingComponentObj {"" || OtherOrderDrugMappingDataByComponentSQL};
OtherOrderDrugMappingDataContainingThisComponentSQL := "select "
|| " ocmi.GUID, ocmi.Name, mdi.drug_id, mdn.drug_name "
|| " from [" || DB || "_MT].[dbo].multum_drug_id mdi "
|| " join [" || DB || "_MT].[dbo].multum_drug_name mdn "
|| " on mdn.drug_synonym_id = mdi.drug_synonym_id "
|| " join CV3DrugMapping AS dm on dm.DrugKey = mdi.drug_id"
|| " JOIN Cv3OrderCatalogMasterItem AS ocmi ON (ocmi.GUID = dm.CatalogItemGUID) "
|| " where mdi.drug_id in "
|| " (select mcd.drug_id from [" || DB || "_MT].[dbo].multum_combination_drug mcd "
|| " where member_drug_id = " || SQL(ThisOrderDrugMapping.DrugKey) || ")";
OtherOrderDrugMappingDataContainingThisComponent := read AS DrugMappingComponentObj {"" || OtherOrderDrugMappingDataContainingThisComponentSQL};
endif;
endif;
;;
evoke:
;;
logic:
if(count(Alerts) = 0)then
SuppressAlert := false;
conclude true;
endif;
If OrderRoleType not in OrderRoleTypesToSuppressSecondaryAlert then
if(user_id <> "services")then
SuppressAlert := false;
conclude true;
endif;
endif;
//if (count(Alerts Where Alerts.OrderName = evoking_order_name) > 0) then
if (count(Alerts Where Alerts.TriggeringInfo = evoking_order_name) > 0) then
SuppressAlert := true;
SuppressAlertReason := "Alert Has Been Triggered For THIS Drug.";
conclude true;
endif;
if(SuppressCrossDrugKey and (count(Alerts Where Alerts.TriggeringInfo in (OtherOrdersDrugMappingsByDrugKey.ocmi_Name)) > 0))then
SuppressAlert := true;
crossDrugName := (first of (Alerts Where Alerts.TriggeringInfo in (OtherOrdersDrugMappingsByDrugKey.ocmi_Name))).TriggeringInfo;
SuppressAlertReason := "Alert Has Been Triggered For a Drug by CrossKey. - " || crossDrugName;
conclude true;
endif;
if(SuppressCrossDrugComponents)then// and (count(Alerts Where Alerts.TriggeringInfo in (OtherOrdersDrugMappingsByComponent.ocmi_Name)) > 0))then
//if all components have been alerted
if(count(OtherOrdersDrugMappingsByComponent) > 0)then
CountAlertsFoundForComponents := 0;
for DrugComponent in OtherOrdersDrugMappingsByComponent do
if(count(Alerts Where Alerts.TriggeringInfo in (DrugComponent.ocmi_Name)) > 0)then
CountAlertsFoundForComponents := CountAlertsFoundForComponents + 1;
endif;
enddo;
if(CountAlertsFoundForComponents = count(OtherOrdersDrugMappingsByComponent))then
SuppressAlert := true;
SuppressAlertReason := "Alert Has Been Triggered For all containing Drugs.";
conclude true;
endif;
endif;
//END if all components have been alerted
//if this drug is a component that has been alerted
if(count(Alerts Where Alerts.TriggeringInfo in (OtherOrderDrugMappingDataContainingThisComponent.ocmi_Name)) > 0)then
SuppressAlert := true;
containingDrugName := (first of (Alerts Where Alerts.TriggeringInfo in (OtherOrderDrugMappingDataContainingThisComponent.ocmi_Name))).TriggeringInfo;
SuppressAlertReason := "Alert Has Been Triggered For a Drug containing this Drug - " || containingDrugName;
conclude true;
endif;
//END if this drug is a component that has been alerted
endif;
conclude true;
;;
action:
return SuppressAlert;
;;
Urgency: 90;;
end: