1972 lines
85 KiB
Plaintext
1972 lines
85 KiB
Plaintext
maintenance:
|
|
|
|
title: Checks the Single, Average-Daily, and Total-Daily Dose Ranges;;
|
|
mlmname: STD_FUNC_DOSAGE_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: The MLM assists the STD_Dosage MLM to determine if a medication dose
|
|
may be out of range.
|
|
;;
|
|
explanation: This MLM, the STD_FUNC_DOSAGE_CAT MLM and the STD_Func_Dosage_Multum
|
|
contain the rules that determine if the SINGLE DOSE, AVERAGE DAILY DOSE,
|
|
or the TOTAL DAILY DOSE are 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;
|
|
|
|
(
|
|
chart_guid,
|
|
user_data_code,
|
|
user_value,
|
|
user_data_touched_when,
|
|
use_multum_dosage_data,
|
|
use_item_catalog_dosage_data,
|
|
catalog_drc_type_const,
|
|
core_uom_const,
|
|
ht_cm,
|
|
show_irregular_message,
|
|
show_under_24_hour_message,
|
|
show_has_shift_frequency_message,
|
|
show_user_scheduled_weekly_message,
|
|
intentionally_unmapped_frequency_list,
|
|
alert_if_missing_flags,
|
|
med_data_list,
|
|
patient_info,
|
|
valid_height_days_for_age,
|
|
valid_weight_days_for_age,
|
|
Creatinine_Clearance_Result_name,
|
|
Creatinine_Clearance_Result_valid_days,
|
|
EstCrCl_equation_preference,
|
|
EstCrC_calculate_with_BSA_preference,
|
|
show_Debug_statements,
|
|
column_catalog_name,
|
|
column_Multum_name
|
|
) := ARGUMENT;
|
|
|
|
/*******************Make Changes To Spelling And Flags In This Section***************/
|
|
|
|
// Set to true if logging is needed.
|
|
log_execution_info := false;
|
|
|
|
/*************************************************************************************/
|
|
|
|
// DO NOT CHANGE the following System-defined values
|
|
dose_per_string:= "Dose Per";
|
|
dose_reg_string:= "Dose Reg";
|
|
|
|
/*=================================================================================*/
|
|
|
|
/* Declare the MLMs that can be called */
|
|
calc_BSA := MLM {{{SINGLE-QUOTE}}}sys_calc_BSA{{{SINGLE-QUOTE}}};
|
|
func_dosage_cat := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_cat{{{SINGLE-QUOTE}}};
|
|
func_dosage_messages := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_messages{{{SINGLE-QUOTE}}};
|
|
func_dosage_tracker := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_tracker{{{SINGLE-QUOTE}}};
|
|
func_dosage_trim := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_trim{{{SINGLE-QUOTE}}};
|
|
func_dosage_trim_adjusted := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_trim_adjusted{{{SINGLE-QUOTE}}};
|
|
func_dosage_multum := MLM {{{SINGLE-QUOTE}}}STD_func_dosage_multum{{{SINGLE-QUOTE}}};
|
|
func_calc_est_crcl := MLM {{{SINGLE-QUOTE}}}SYS_CALC_EST_CRCL{{{SINGLE-QUOTE}}};
|
|
|
|
dosage_range_list := ();
|
|
med_dosage_map_list := ();
|
|
|
|
/* Get current visit timezone. */
|
|
(visit_timezone) := read last
|
|
{ClientVisit: timezone };
|
|
|
|
/* Get the patient{{{SINGLE-QUOTE}}}s birthday and other relevant data */
|
|
(client_guid,
|
|
birthdatetime,
|
|
birthday,
|
|
birthMonthNum,
|
|
birthDayNum,
|
|
birthtime,
|
|
patient_gender,
|
|
intl_patient_gender,
|
|
client_info_obj ) := read last
|
|
{ ClientInfo: GUID, BirthdateTime, Birthdate, BirthMonthNum, BirthDayNum, BirthTime, GenderCode,
|
|
GenderTypeIntlCode, this, };
|
|
|
|
//MTZ: set birthday with evoking object visit time zone
|
|
birthday := birthday as Time OVERRIDETIMEZONE visit_timezone;
|
|
|
|
// Get the BSA calculation preference used by the MLMS:
|
|
// SYS_CALC_BSA MLM and SYS_CALC_EST_CRCL
|
|
BSA_formula_preference := read last
|
|
{"SELECT Value "
|
|
|| " FROM HVCEnvProfile "
|
|
|| " WHERE Code = {{{SINGLE-QUOTE}}}BSAFormula{{{SINGLE-QUOTE}}} "
|
|
|| " AND HierarchyCode = {{{SINGLE-QUOTE}}}Client Info{{{SINGLE-QUOTE}}} " };
|
|
|
|
/* 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" };
|
|
|
|
|
|
if use_multum_dosage_data
|
|
then
|
|
/* Get the patient dialysis type*/
|
|
/* Retrieve the facility{{{SINGLE-QUOTE}}}s scope preference for dialysis type */
|
|
general_scope_for_dialysis := read last
|
|
{"SELECT CASE WHEN ScopeLevel = 3 THEN 1 ELSE 0 END "
|
|
|| " FROM CV3PhysicalNoteType "
|
|
|| " WHERE Code = " || SQLEX("Dialysis")};
|
|
|
|
/* Set the scope to retrieve the Dialysis */
|
|
if general_scope_for_dialysis = 1
|
|
then dialysis_patient_chart_str:= "";
|
|
else dialysis_patient_chart_str:= " AND ChartGUID = " || SQLEX(chart_guid);
|
|
endif;
|
|
|
|
/* Retrieve from database*/
|
|
/* Warning--keep SQL in synch with business rules on patient height */
|
|
(dialysis_type_str,
|
|
dialysis_date) := read last
|
|
{"SELECT Text, TouchedWhen "
|
|
|| " FROM CV3PhysicalNoteDeclaration"
|
|
|| " WHERE ClientGUID = " || SQLEX(client_guid)
|
|
|| dialysis_patient_chart_str
|
|
|| " AND Active = 1 "
|
|
|| " AND TypeCode = " || SQLEX("DIALYSIS")
|
|
|| " AND Status = " || SQLEX("Active")
|
|
, PrimaryTime = TouchedWhen };
|
|
|
|
/* Retrieve the facility{{{SINGLE-QUOTE}}}s scope preference for has liver disease*/
|
|
general_scope_for_liver := read last
|
|
{"SELECT CASE WHEN ScopeLevel = 3 THEN 1 ELSE 0 END "
|
|
|| " FROM CV3PhysicalNoteType "
|
|
|| " WHERE Code = " || SQLEX("LIVERFUNC")};
|
|
|
|
/* Set the scope to retrieve the has liver disease string */
|
|
if general_scope_for_liver = 1
|
|
then liver_patient_chart_str:= "";
|
|
else liver_patient_chart_str:= " AND ChartGUID = " || SQLEX(chart_guid);
|
|
endif;
|
|
|
|
/* Retrieve from database*/
|
|
/* Warning--keep SQL in synch with business rules on patient liver disease */
|
|
(has_liver_disease_str,
|
|
has_liver_disease_date) := read last
|
|
{"SELECT Text, TouchedWhen "
|
|
|| " FROM CV3PhysicalNoteDeclaration"
|
|
|| " WHERE ClientGUID = " || SQLEX(client_guid)
|
|
|| liver_patient_chart_str
|
|
|| " AND Active = 1 "
|
|
|| " AND TypeCode = " || SQLEX("LIVERFUNC")
|
|
|| " AND Status = " || SQLEX("Active")
|
|
, PrimaryTime = TouchedWhen };
|
|
|
|
// patient info obj property value for liver disease
|
|
patient_info.Liver := new Patient_Property_Obj;
|
|
patient_info.Liver.type := "Liver Disease";
|
|
patient_info.Liver.date := has_liver_disease_date;
|
|
|
|
if has_liver_disease_str is null
|
|
then
|
|
has_liver_disease_str:= "Unknown";
|
|
patient_info.Liver.is_missing := true;
|
|
endif; /* if has_liver_disease_str */
|
|
|
|
// set has_liver_disease_bit
|
|
if has_liver_disease_str = "Yes"
|
|
then
|
|
has_liver_disease_bit := 1;
|
|
elseif has_liver_disease_str = "No"
|
|
then
|
|
has_liver_disease_bit := 0;
|
|
else
|
|
has_liver_disease_bit := null;
|
|
endif;
|
|
|
|
patient_info.Liver.value := has_liver_disease_str;
|
|
|
|
// If Dialysis is HEMO or Peritoneal then do not need to retrieve Creatinine
|
|
if ( dialysis_type_str in ("Hemo", "Peritoneal"))
|
|
then
|
|
patient_info.Renal := new Patient_Property_Obj;
|
|
patient_info.Renal.type := "Renal";
|
|
|
|
if (dialysis_type_str = "Hemo")
|
|
then
|
|
patient_info.Renal.value := "hemodialysis";
|
|
else
|
|
patient_info.Renal.value := "peritoneal dialysis";
|
|
endif;
|
|
|
|
patient_info.Renal.date := dialysis_date;
|
|
else
|
|
creatinine_OBJECT := object [
|
|
value,
|
|
enteredDate,
|
|
isSerum
|
|
];
|
|
|
|
creatinine_list := ();
|
|
creatinine_on_order_form := false;
|
|
|
|
// Get the creatinine values from the Order entry form if the control exists
|
|
// This value will always be assumed to be the correct and latest
|
|
// Code first checks for the Creatinine Clearance values and if not found then looks for
|
|
// the Serum Creatinine.
|
|
//MTZ: when building data initial time, the enteredDate will be enterprise tz and convert to visit tz later
|
|
creatinine_order_str := first (user_value where user_data_code = "CreatCrClValue_ECLP") as String;
|
|
if creatinine_order_str <> "null" and length of creatinine_order_str > 0
|
|
then
|
|
//creatinine_order_date := first (user_value where user_data_code = "CreatCrClEntered_ECLP");
|
|
creatinine_order_date := now; // Assume now since Order User Data has priority over the DB
|
|
|
|
creatinine_clearance_order := new creatinine_OBJECT;
|
|
creatinine_clearance_order.Value := creatinine_order_str as number;
|
|
time of creatinine_clearance_order := creatinine_order_date;
|
|
creatinine_clearance_order.enteredDate := creatinine_order_date;
|
|
creatinine_clearance_order.isSerum := false;
|
|
creatinine_on_order_form := true;
|
|
|
|
creatinine_list := creatinine_list, creatinine_clearance_order;
|
|
|
|
else
|
|
creatinine_order_str := first (user_value where user_data_code = "CreatSCRValue_ECLP") as String;
|
|
if creatinine_order_str <> "null" and length of creatinine_order_str > 0
|
|
then
|
|
|
|
//creatinine_order_date := first (user_value where user_data_code = "CreatSCREntered_ECLP");
|
|
creatinine_order_date := now; // Assume now since Order User Data has priority over the DB
|
|
|
|
serum_creatinine_order := new creatinine_OBJECT;
|
|
serum_creatinine_order.Value := creatinine_order_str as number;
|
|
time of serum_creatinine_order := creatinine_order_date;
|
|
serum_creatinine_order.enteredDate := creatinine_order_date;
|
|
serum_creatinine_order.isSerum := true;
|
|
creatinine_on_order_form := true;
|
|
|
|
creatinine_list := creatinine_list, serum_creatinine_order;
|
|
endif;
|
|
|
|
endif;
|
|
|
|
// If there is no Creatinine defined on the order form then need to check
|
|
// the database.
|
|
if not creatinine_on_order_form
|
|
then
|
|
|
|
// Get the Serum result name and valid days from the Environment Profile
|
|
(Serum_Creatinine_Result_Name,
|
|
Serum_Creatinine_Result_valid_days) := read last
|
|
{ "select ( select value from HVCEnvProfile " ||
|
|
" where HierarchyCode={{{SINGLE-QUOTE}}}CDS|Expert Drug Profile{{{SINGLE-QUOTE}}} AND " ||
|
|
" Code={{{SINGLE-QUOTE}}}Serum Creatinine Result Name{{{SINGLE-QUOTE}}}) as Name, " ||
|
|
" ( select value from HVCEnvProfile " ||
|
|
" where HierarchyCode={{{SINGLE-QUOTE}}}CDS|Expert Drug Profile{{{SINGLE-QUOTE}}} AND " ||
|
|
" Code={{{SINGLE-QUOTE}}}Valid Serum Creatinine Days{{{SINGLE-QUOTE}}}) as ValidDays" };
|
|
|
|
// Retrieve a serum creatinine from the Physical Note Declaration. Make sure
|
|
// it is still valid.
|
|
validDate := now - (Serum_Creatinine_Result_valid_days as number) days;
|
|
isFromPhysicalNote := 1;
|
|
(creatinine_physicalNote_str,
|
|
creatinine_physicalNote_date) := read last
|
|
{ "EXEC SCMSerumCreatinineOrClearanceSelPR "
|
|
|| SQLEX(client_guid) || " ,"
|
|
|| SQLEX("SCR") || " ,"
|
|
|| SQL(validDate) || " ," //no need to convert to datetimeoffset
|
|
|| SQLEX(isFromPhysicalNote )
|
|
, PrimaryTime = PerformedDtm}; //PerformedDtm is CV3PhysicalNoteDeclaration.TouchedWhen
|
|
|
|
|
|
if creatinine_physicalNote_str is not null
|
|
then
|
|
creatinine_physicalNote := new creatinine_OBJECT;
|
|
creatinine_physicalNote.value := creatinine_physicalNote_str as number;
|
|
time of creatinine_physicalNote := creatinine_physicalNote_date;
|
|
creatinine_physicalNote.enteredDate := creatinine_physicalNote_date;
|
|
creatinine_physicalNote.isSerum := true;
|
|
|
|
creatinine_list := creatinine_list, creatinine_physicalNote;
|
|
endif;
|
|
|
|
if Serum_Creatinine_Result_Name is not null
|
|
then
|
|
|
|
validDate := now - (Serum_Creatinine_Result_valid_days as number) days;
|
|
isFromPhysicalNote := 0;
|
|
(creatinine_result_str,
|
|
creatinine_result_date) := read last
|
|
{ "EXEC SCMSerumCreatinineOrClearanceSelPR "
|
|
|| SQLEX(client_guid) || " ,"
|
|
|| SQLEX(Serum_Creatinine_Result_Name) || " ,"
|
|
|| SQL(validDate) || " ," // no need to convert to datetimeoffset
|
|
|| SQLEX(isFromPhysicalNote)
|
|
, PrimaryTime = PerformedDtm}; //PerformedDtm is CV3BasicObservationView.PerformedDtm
|
|
|
|
if creatinine_result_str is not null
|
|
then
|
|
creatinine_result := new creatinine_OBJECT;
|
|
creatinine_result.value := creatinine_result_str as number;
|
|
time of creatinine_result := creatinine_result_date;
|
|
creatinine_result.enteredDate := creatinine_result_date;
|
|
creatinine_result.isSerum := true;
|
|
|
|
creatinine_list := creatinine_list, creatinine_result;
|
|
endif;
|
|
|
|
endif;
|
|
|
|
if Creatinine_Clearance_Result_name is not null
|
|
then
|
|
|
|
validDate := now - (Creatinine_Clearance_Result_valid_days as number) days;
|
|
isFromPhysicalNote := 0;
|
|
(creatinine_clearance_result_str,
|
|
creatinine_clearance_result_date) := read last
|
|
{ "EXEC SCMSerumCreatinineOrClearanceSelPR "
|
|
|| SQLEX(client_guid) || " ,"
|
|
|| SQLEX(Creatinine_Clearance_Result_name) || " ,"
|
|
|| SQL(validDate) || " ," // no need to convert to datetimeoffset
|
|
|| SQLEX(isFromPhysicalNote)
|
|
, PrimaryTime = PerformedDtm}; //PerformedDtm is CV3BasicObservationView.PerformedDtm
|
|
|
|
if creatinine_clearance_result_str is not null
|
|
then
|
|
creatinine_clearance_result := new creatinine_OBJECT;
|
|
creatinine_clearance_result.value := creatinine_clearance_result_str as number;
|
|
time of creatinine_clearance_result := creatinine_clearance_result_date;
|
|
creatinine_clearance_result.enteredDate := creatinine_clearance_result_date;
|
|
creatinine_clearance_result.isSerum := false;
|
|
|
|
creatinine_list := creatinine_list, creatinine_clearance_result;
|
|
endif;
|
|
|
|
endif;
|
|
|
|
endif;
|
|
|
|
calc_needed := false;
|
|
patient_info.Creatinine := new Patient_Property_Obj;
|
|
patient_info.Creatinine.type := "Creatinine";
|
|
|
|
latest_creatinine := creatinine_list[last index maximum 1 from (creatinine_list.enteredDate)];
|
|
|
|
// Need to calculate the estimated creatinine clearance if the latest creatinine value
|
|
// retrieved is a serum.
|
|
if latest_creatinine.isSerum
|
|
then
|
|
|
|
( error_message, EstCrCl_number_rounded,
|
|
EstCrCl_formula, weight_used, BSA_used ) := call func_calc_est_crcl with
|
|
EstCrCl_equation_preference,
|
|
BSA_formula_preference,
|
|
patient_info.Height.value,
|
|
patient_info.Weight.value,
|
|
latest_creatinine.value,
|
|
EstCrC_calculate_with_BSA_preference,
|
|
client_Info_obj;
|
|
|
|
if error_message is not null AND length of error_message > 0
|
|
then
|
|
patient_info.Creatinine.value := null;
|
|
patient_info.Creatinine.is_missing := true;
|
|
else
|
|
patient_info.Creatinine.value := EstCrCl_number_rounded;
|
|
patient_info.Creatinine.is_missing := false;
|
|
endif;
|
|
else
|
|
patient_info.Creatinine.value := latest_creatinine.value;
|
|
endif;
|
|
//MTZ: convert enteredDate to visit time zone from enterprise
|
|
patient_info.Creatinine.date := latest_creatinine.enteredDate as time visit_timezone;
|
|
|
|
endif;
|
|
|
|
endif;
|
|
|
|
// Check to see if gender is required for any dose critiera
|
|
patient_info.Gender := new Patient_Property_Obj;
|
|
patient_info.Gender.type := "Gender";
|
|
patient_info.Gender.value := patient_gender;
|
|
|
|
if not exist patient_gender
|
|
then
|
|
patient_info.Gender.is_missing := TRUE;
|
|
else
|
|
patient_info.Gender.is_missing := FALSE;
|
|
endif; //if not exist patient_gender
|
|
|
|
if intl_patient_gender = "U" or intl_patient_gender = "O"
|
|
then
|
|
patient_info.Gender.unknown_other := TRUE;
|
|
else
|
|
patient_info.Gender.unknown_other := FALSE;
|
|
endif; //if intl_patient_gender = "U" or "O"
|
|
|
|
if exist patient_gender and
|
|
not exist intl_patient_gender
|
|
then
|
|
patient_info.Gender.is_unmapped := TRUE;
|
|
else
|
|
patient_info.Gender.is_unmapped := FALSE;
|
|
endif;
|
|
|
|
//Create objects that summarize data needed for
|
|
//Total Daily Dose and Average Daily Dose checking
|
|
(total_tracker_list,
|
|
average_tracker_list )
|
|
:= call func_dosage_tracker with med_data_list;
|
|
|
|
;;
|
|
evoke:
|
|
;;
|
|
logic:
|
|
|
|
//------------------------------------------------
|
|
// Process each Medication in the Med_Data Object
|
|
//------------------------------------------------
|
|
for med_data in med_data_list do
|
|
missing_data_msg := "";
|
|
drug_name := med_data.order_med_name ;
|
|
catalog_item_obj:= med_data.order_catalog_item_obj;
|
|
|
|
// Significant_date is important in several calculations and cannot
|
|
// be NULL. Set it to be the first calculated admin time. If this
|
|
// is null then take the calcStart_dtm.
|
|
if med_data.order_med_significant_date is null
|
|
then
|
|
med_data.order_med_significant_date := first med_data.admin_dtm_list;
|
|
if med_data.order_med_significant_date is null
|
|
then
|
|
med_data.order_med_significant_date := med_data.calcStart_dtm;
|
|
endif;
|
|
endif;
|
|
|
|
//-----------------------------------------------------
|
|
// Determine if DOSE PER or DOSE REG Should be Used for Range Check
|
|
//-----------------------------------------------------
|
|
|
|
// The SINGLE dose should always be checked with the setting from the order.
|
|
single_order_calc_per_uom := med_data.updated_calc_med_per_uom;
|
|
|
|
// Complex Order should have their AVERAGE and TOTAL doses check with DOSE REG.
|
|
// by setting the variable below to NULL.
|
|
// All other orders should use the setting from the order.
|
|
If med_data.med_order_type = "Complex Order"
|
|
then
|
|
average_order_calc_per_uom := NULL;
|
|
total_order_calc_per_uom := NULL;
|
|
else
|
|
average_order_calc_per_uom := med_data.updated_calc_med_per_uom;
|
|
total_order_calc_per_uom := med_data.updated_calc_med_per_uom;
|
|
endif;
|
|
|
|
/*----------------------------------------------------------------*/
|
|
/* Set the WEIGHT and associated data for the Dosage Range Checks */
|
|
/*----------------------------------------------------------------*/
|
|
calc_text := med_data.calc_text;
|
|
dose_basis := med_data.dose_basis;
|
|
wt_kg := med_data.wt_kg;
|
|
|
|
//---------------------------
|
|
// Calculate the Patient Age
|
|
//---------------------------
|
|
// 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 4 years.
|
|
if birthday is time then
|
|
has_valid_birthdate:= true;
|
|
patient_birthday_info_on_order := new Patient_Birthday_Info_Obj;
|
|
|
|
order_significant_date := med_data.order_med_significant_date;
|
|
|
|
age_value:= (order_significant_date-birthday)/(1 year);
|
|
if birthMonthNum = 0 and age_value < 4 then
|
|
has_valid_birthdate:= false;
|
|
endif;
|
|
|
|
month_value := (order_significant_date-birthday)/(1 month);
|
|
if has_valid_birthdate and BirthDayNum = 0 and month_value < 4 then
|
|
has_valid_birthdate:= false;
|
|
endif;
|
|
|
|
// Calculate the patient age in days
|
|
// Patient age in days
|
|
patient_age_in_days := (order_significant_date - birthday)/(1 day);
|
|
|
|
// if patient age < 4 days, then recalculate total using formula:
|
|
// Order.SignificantDtm (Birthday at 00:00 + HH:MM of birth time from CV3Client.BirthTime)
|
|
if has_valid_birthdate and patient_age_in_days < 4
|
|
then
|
|
if not exists birthtime
|
|
then
|
|
//[New born birth-time missing]: check on birth time range, Birthday "from" and "to" value will be needed.
|
|
//Birthday To value set to 23:59:
|
|
if patient_age_in_days >= 1 then
|
|
birth_time_to := ("23:59:00" as time);
|
|
estimated_birthday_to := birthday + (birth_time_to - (day floor of birth_time_to));
|
|
else
|
|
estimated_birthday_to := now as time visit_timezone;
|
|
endif;
|
|
else
|
|
// Update the birthday to include birthtime when baby is less than 4 days old
|
|
birthday := birthdatetime;
|
|
Endif;
|
|
|
|
endif;
|
|
|
|
sig_extract_year := extract year order_significant_date;
|
|
birthday_extract_year := extract year birthday;
|
|
|
|
sig_extract_month := extract month order_significant_date;
|
|
birthday_extract_month := extract month birthday;
|
|
|
|
sig_extract_day := extract day order_significant_date;
|
|
birthday_extract_day := extract day birthday;
|
|
|
|
had_birthday := true;
|
|
if (sig_extract_month = birthday_extract_month)
|
|
then
|
|
if (sig_extract_day < birthday_extract_day)
|
|
then
|
|
had_birthday := false;
|
|
endif;
|
|
elseif (sig_extract_month < birthday_extract_month)
|
|
then
|
|
had_birthday := false;
|
|
endif;
|
|
|
|
age_years_value := sig_extract_year - birthday_extract_year;
|
|
if (had_birthday = false)
|
|
then
|
|
age_years_value := age_years_value - 1;
|
|
endif;
|
|
|
|
// construct the string used to display the age
|
|
age_months_value := (order_significant_date - birthday) / (1 month);
|
|
age_days_value := (order_significant_date - birthday) / (1 day);
|
|
age_hours_value := (order_significant_date - birthday) / (1 hour);
|
|
|
|
age_str := "";
|
|
if (age_years_value >= 1)
|
|
then
|
|
age_str := age_years_value formatted with "%d" || " year(s)";
|
|
elseif (age_months_value >= 1)
|
|
then
|
|
age_str := age_months_value formatted with "%d" || " month(s)";
|
|
elseif (age_days_value >= 1)
|
|
then
|
|
age_str := age_days_value formatted with "%d" || " day(s)";
|
|
elseif (age_hours_value >= 1)
|
|
then
|
|
age_str := age_hours_value formatted with "%d" || " hour(s)";
|
|
endif;
|
|
|
|
//[New born birth-time missing]: fillup birthday related info structure
|
|
patient_birthday_info_on_order.birthday := birthday;
|
|
patient_birthday_info_on_order.age_str := age_str;
|
|
patient_birthday_info_on_order.age_year_value := age_years_value;
|
|
patient_birthday_info_on_order.age_month_value := age_months_value;
|
|
patient_birthday_info_on_order.age_week_value := (order_significant_date - birthday) / (1 week);
|
|
patient_birthday_info_on_order.age_day_value := age_days_value;
|
|
patient_birthday_info_on_order.age_hour_value := age_hours_value;
|
|
patient_birthday_info_on_order.age_max_inhour_str := patient_birthday_info_on_order.age_hour_value formatted with "%d" || " hour(s)";
|
|
|
|
if estimated_birthday_to is not null then
|
|
patient_birthday_info_on_order.is_estimated_birthday := true;
|
|
patient_birthday_info_on_order.estimated_birthday_to := estimated_birthday_to;
|
|
patient_birthday_info_on_order.age_year_min_value := (order_significant_date - estimated_birthday_to) / (1 year);
|
|
patient_birthday_info_on_order.age_month_min_value := (order_significant_date - estimated_birthday_to) / (1 month);
|
|
patient_birthday_info_on_order.age_week_min_value := (order_significant_date - estimated_birthday_to) / (1 week);
|
|
patient_birthday_info_on_order.age_day_min_value := (order_significant_date - estimated_birthday_to) / (1 day);
|
|
patient_birthday_info_on_order.age_hour_min_value := (order_significant_date - estimated_birthday_to) / (1 hour);
|
|
patient_birthday_info_on_order.age_min_inhour_str := patient_birthday_info_on_order.age_hour_min_value formatted with "%d" || " hour(s)";
|
|
endif;
|
|
else
|
|
has_valid_birthdate := false;
|
|
endif;
|
|
|
|
//-----------------------------------------
|
|
// Perform weight/height currentness check
|
|
//-----------------------------------------
|
|
if has_valid_birthdate
|
|
then
|
|
patient_age := order_significant_date - birthday;
|
|
|
|
// Perform weight validity check
|
|
valid_weight_duration := last (valid_weight_days_for_age.duration
|
|
where (valid_weight_days_for_age.FromAge <= patient_age and
|
|
valid_weight_days_for_age.ToAge > patient_age ));
|
|
|
|
// compute weight duration
|
|
weight_duration := now - patient_info.Weight.date;
|
|
|
|
// Weight is not current, set it to zero
|
|
if (weight_duration > valid_weight_duration)
|
|
then
|
|
wt_kg := null;
|
|
endif;
|
|
|
|
// Perform height validity check
|
|
valid_height_duration := last (valid_height_days_for_age.duration
|
|
where (valid_height_days_for_age.FromAge <= patient_age and
|
|
valid_height_days_for_age.ToAge > patient_age ));
|
|
|
|
// compute the height duration
|
|
height_duration := now - patient_info.Height.date;
|
|
|
|
// if height is not current, set it to zero
|
|
if (height_duration > valid_height_duration)
|
|
then
|
|
ht_cm := null;
|
|
endif;
|
|
|
|
// Update the is missing flag
|
|
if (wt_kg is number and wt_kg > 0)
|
|
then patient_info.Weight.not_current := FALSE;
|
|
else patient_info.Weight.not_current := TRUE;
|
|
endif; //if wt_kg is number
|
|
|
|
|
|
// Check to see if height is present
|
|
if ht_cm is number
|
|
and ht_cm > 0
|
|
then patient_info.Height.not_current := FALSE;
|
|
else patient_info.Height.not_current := TRUE;
|
|
endif; //if ht_cm is number
|
|
|
|
endif;
|
|
|
|
//-------------------
|
|
// Calculate the BSA
|
|
//-------------------
|
|
if ht_cm is number
|
|
and wt_kg is number
|
|
and ht_cm > 0
|
|
and wt_kg > 0
|
|
then
|
|
BSA_number_rounded:= Call calc_BSA with
|
|
BSA_formula_preference, ht_cm, wt_kg, client_info_obj;
|
|
|
|
patient_info.BSA := new Patient_Property_Obj;
|
|
patient_info.BSA.type := "BSA";
|
|
patient_info.BSA.value := BSA_number_rounded;
|
|
patient_info.BSA.is_missing := ((BSA_number_rounded is NULL) or (BSA_number_rounded = 0));
|
|
|
|
endif; /* if ht_cm is number */
|
|
|
|
//----------------------------------
|
|
// Check SINGLE Dosage Range
|
|
//----------------------------------
|
|
|
|
// Find the SINGLE Dose medications with the same Name, UOM, Route, and PerUOM
|
|
// OR both PerUOM are NULL.
|
|
//-----------------------------------------------------------------------------
|
|
found_med_data := med_data_list where
|
|
(med_data_list.med_order_type = med_data.med_order_type
|
|
AND med_data_list.order_med_name = med_data.order_med_name
|
|
AND (med_data_list.order_med_units = med_data.order_med_units
|
|
OR (med_data_list.order_med_units is null AND med_data.order_med_units is null))
|
|
AND ( med_data_list.order_med_route = med_data.order_med_route
|
|
OR (med_data_list.order_med_route is null AND med_data.order_med_route is null)
|
|
)
|
|
AND ((med_data_list.calc_med_per_uom = med_data.calc_med_per_uom)
|
|
OR (med_data_list.calc_med_per_uom is null
|
|
AND med_data.calc_med_per_uom is null))
|
|
AND (med_data_list.order_med_dose_low is not null AND
|
|
med_data.order_med_dose_low is not null )
|
|
AND // If complex order (complex order or complex order with IV additive), don{{{SINGLE-QUOTE}}}t process the master complex order
|
|
( ( (any (med_data_list.med_order_type = "Complex Order")) AND (med_data.sort_number > 1))
|
|
OR
|
|
(not any (med_data_list.med_order_type = "Complex Order")) // not a complex order
|
|
)
|
|
AND med_data_list.order_med_significant_date = med_data.order_med_significant_date
|
|
);
|
|
|
|
// Find the dosage range for the SINGLE DOSE
|
|
//------------------------------------------
|
|
// Only retreive the dosage range data once for each Item-Catalog/Multum
|
|
// by checking to see if the dosage range data has already been retrieved
|
|
if (not exist med_data.retrieved_dose_range_data
|
|
and exist med_data.order_med_dose_low )
|
|
then
|
|
|
|
if use_item_catalog_dosage_data
|
|
then
|
|
(item_cat_dosage_range_list,
|
|
item_cat_missing_route,
|
|
item_cat_unmapped_route,
|
|
item_cat_missing_uom,
|
|
item_cat_unmapped_uom,
|
|
item_cat_uom_conversion_issue
|
|
):= call func_dosage_cat with
|
|
(
|
|
drug_name,
|
|
med_data.is_order,
|
|
catalog_item_obj,
|
|
med_data.grouper_id,
|
|
med_data.multum_dnum,
|
|
med_data.multum_mmdc,
|
|
med_data.order_med_route,
|
|
med_data.order_med_route_id,
|
|
med_data.generic_route,
|
|
med_data.order_med_significant_date,
|
|
med_data.order_med_units,
|
|
med_data.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
|
|
);
|
|
|
|
// Performed item catalog dosage look up for the medication
|
|
found_med_data.retrieved_dose_range_data := true;
|
|
found_med_data.missing_route := found_med_data.missing_route or item_cat_missing_route;
|
|
found_med_data.unmapped_route := found_med_data.unmapped_route or item_cat_unmapped_route;
|
|
found_med_data.missing_uom := found_med_data.missing_uom or item_cat_missing_uom;
|
|
found_med_data.unmapped_uom := found_med_data.unmapped_uom or item_cat_unmapped_uom;
|
|
found_med_data.uom_conversion_issue:= found_med_data.uom_conversion_issue
|
|
or item_cat_uom_conversion_issue;
|
|
|
|
item_cat_dosage_range_list.patient_age_at_order := age_str;
|
|
|
|
// create map between medication and the single or contraindication multum values
|
|
single_item_cat_dosage_range_list := item_cat_dosage_range_list
|
|
where (item_cat_dosage_range_list.dosage_type in ("single"));
|
|
|
|
found_single_dose := any (single_item_cat_dosage_range_list where single_item_cat_dosage_range_list.match_found = true);
|
|
|
|
// add the item catalog for single dosage ranges to the dosage range list
|
|
if ((exists single_item_cat_dosage_range_list) and (count single_item_cat_dosage_range_list > 0))
|
|
then
|
|
single_item_cat_dosage_range_list.dosage_type := "single";
|
|
dosage_range_list := dosage_range_list, single_item_cat_dosage_range_list;
|
|
|
|
// update the sort number
|
|
list_count := count dosage_range_list;
|
|
dosage_range_list.sort_number := 1 seqto list_count;
|
|
|
|
// create map between medication and the single item catalog dosage range value
|
|
for single_item_cat_dosage_range in single_item_cat_dosage_range_list
|
|
do
|
|
if single_item_cat_dosage_range.match_found
|
|
then
|
|
for found_med_data_item in found_med_data
|
|
do
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_med_data_item.sort_number;
|
|
map_item.med_name := found_med_data_item.order_med_name;
|
|
map_item.dosage_range_sort_number := single_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := single_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := single_item_cat_dosage_range.match_found;
|
|
enddo;
|
|
else // missing data dosage range is just mapped to first occurence of the medication
|
|
found_med_data_item := last found_med_data[1];
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_med_data_item.sort_number;
|
|
map_item.med_name := found_med_data_item.order_med_name;
|
|
map_item.dosage_range_sort_number := single_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := single_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := single_item_cat_dosage_range.match_found;
|
|
endif; // if single_item_cat_dosage_range.match_found
|
|
enddo; // for single_item_cat_dosage_range in single_item_cat_dosage_range_list
|
|
endif; // if (count single_item_cat_dosage_range_list > 0)
|
|
endif;
|
|
|
|
if ( use_multum_dosage_data
|
|
and has_valid_birthdate )
|
|
then
|
|
if med_data.is_order
|
|
then
|
|
if (catalog_item_obj.DrcGrouperID is null
|
|
and exists catalog_item_obj.DrugCatalogKey
|
|
and not catalog_item_obj.DrugCatalogKeyIsIgnored)
|
|
then
|
|
found_med_data.unmapped_grouper := true;
|
|
endif;
|
|
|
|
if (catalog_item_obj.DrugCatalogKey is null
|
|
and not catalog_item_obj.DrugCatalogKeyIsIgnored)
|
|
then
|
|
found_med_data.unmapped_drug := true;
|
|
endif;
|
|
endif;
|
|
|
|
// Get the corresponding dosage range data from multum
|
|
(multum_dosage_range_list,
|
|
multum_missing_route,
|
|
multum_unmapped_route,
|
|
multum_missing_uom,
|
|
multum_unmapped_uom,
|
|
multum_uom_conversion_issue ):= call func_dosage_multum with
|
|
(
|
|
med_data.grouper_id,
|
|
drug_name,
|
|
med_data.multum_dnum,
|
|
med_data.multum_mmdc,
|
|
med_data.order_med_route,
|
|
med_data.order_med_route_id,
|
|
med_data.generic_route,
|
|
med_data.order_med_significant_date,
|
|
med_data.order_med_units,
|
|
med_data.order_med_uom_id,
|
|
med_data.order_med_frequency,
|
|
med_data.multum_freq_id,
|
|
med_data.med_order_type,
|
|
patient_birthday_info_on_order,
|
|
wt_kg,
|
|
BSA_number_rounded,
|
|
intl_patient_gender,
|
|
has_liver_disease_bit,
|
|
dialysis_type_str,
|
|
patient_info.Creatinine.value,
|
|
intentionally_unmapped_frequency_list,
|
|
alert_if_missing_flags,
|
|
med_data.is_order,
|
|
patient_info,
|
|
core_uom_const
|
|
);
|
|
|
|
// Performed multum dosage range data look up for this medication
|
|
found_med_data.retrieved_dose_range_data := true;
|
|
found_med_data.uom_conversion_issue :=found_med_data.uom_conversion_issue or multum_uom_conversion_issue;
|
|
found_med_data.missing_route := found_med_data.missing_route or multum_missing_route;
|
|
found_med_data.unmapped_route := found_med_data.unmapped_route or multum_unmapped_route;
|
|
found_med_data.missing_uom := found_med_data.missing_uom or multum_missing_uom;
|
|
found_med_data.unmapped_uom := found_med_data.unmapped_uom or multum_unmapped_uom;
|
|
|
|
multum_dosage_range_list.patient_age_at_order := age_str;
|
|
|
|
// add the item catalog for single dosage ranges to the dosage range list
|
|
if (count multum_dosage_range_list > 0)
|
|
then
|
|
|
|
dosage_range_list := dosage_range_list, multum_dosage_range_list;
|
|
|
|
// update the sort number
|
|
list_count := count dosage_range_list;
|
|
dosage_range_list.sort_number := 1 seqto list_count;
|
|
|
|
// create map between medication and the single or contraindication multum values
|
|
single_contraindication_multum_dosage_list := multum_dosage_range_list
|
|
where (multum_dosage_range_list.dosage_type in ("single", "contraindication"));
|
|
|
|
for multum_dosage_range_item in single_contraindication_multum_dosage_list
|
|
do
|
|
if ( multum_dosage_range_item.match_found
|
|
and multum_dosage_range_item.is_range )
|
|
then
|
|
for found_med_data_item in found_med_data
|
|
do
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_med_data_item.sort_number;
|
|
map_item.med_name := found_med_data_item.order_med_name;
|
|
map_item.dosage_range_sort_number := multum_dosage_range_item.sort_number;
|
|
map_item.dosage_type := multum_dosage_range_item.dosage_type;
|
|
map_item.match_found := multum_dosage_range_item.match_found;
|
|
map_item.dose_frequency := multum_dosage_range_item.dose_frequency;
|
|
map_item.frequency_issue := multum_dosage_range_item.frequency_issue;
|
|
|
|
enddo;
|
|
else
|
|
// missing criteria (match not found) or contraindication
|
|
// These items should be mapped to the medicaiton as dosage comparion will not be done
|
|
found_med_data_item := last found_med_data[1];
|
|
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_med_data_item.sort_number;
|
|
map_item.med_name := found_med_data_item.order_med_name;
|
|
map_item.dosage_range_sort_number := multum_dosage_range_item.sort_number;
|
|
map_item.dosage_type := multum_dosage_range_item.dosage_type;
|
|
map_item.match_found := multum_dosage_range_item.match_found;
|
|
|
|
// if match found, and not a range means it{{{SINGLE-QUOTE}}}s a contraindication
|
|
if (multum_dosage_range_item.match_found and
|
|
multum_dosage_range_item.dosage_type = "contraindication")
|
|
then
|
|
found_med_data_item.contraindication_found := true;
|
|
endif;
|
|
endif; // if multum_dosage_range_item.found_match
|
|
enddo; // for multum_dosage_range_item in single_contraindication_multum_dosage_list
|
|
endif; //if (count multum_dosage_range_list > 0)
|
|
|
|
// Set the Single Dosage Criteria in the Med_Data objects
|
|
// that have the same Name, Route, UOM, and PerUOM
|
|
// OR both PerUOM are NULL.
|
|
single_dosage_ranges := dosage_range_list where dosage_range_list.dosage_type = "single";
|
|
endif;
|
|
endif; //if not exist med_data.retrieved_dose_range_data
|
|
|
|
// Compare the medication single dose with the dosage range data
|
|
all_single_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "single" );
|
|
|
|
found_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number = med_data.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_single_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "single");
|
|
|
|
|
|
for map_item in found_maps
|
|
do
|
|
dosage_range := last dosage_range_list[map_item.dosage_range_sort_number];
|
|
|
|
// Set the Low & High Values for the SINGLE DOSE
|
|
//----------------------------------------------
|
|
// Set compound versus simple //
|
|
if dosage_range.dose_calc_method = dose_per_string
|
|
then
|
|
// Set the single dose for the COMPOUND UOM (xxx/kg or xxx/m2)
|
|
map_item.med_dose_high := med_data.calc_med_dose_high;
|
|
map_item.med_dose_low := med_data.calc_med_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units || "/" || med_data.calc_med_per_uom;
|
|
|
|
sample_vals := med_data.calc_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
else
|
|
// Set the single dose for the SIMPLE UOM (mg, cc, etc.)
|
|
map_item.med_dose_high:= med_data.order_med_dose_high;
|
|
map_item.med_dose_low:= med_data.order_med_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units;
|
|
|
|
sample_vals := med_data.order_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
endif; // if dosage_range.dose_calc_method = dose_per_string
|
|
|
|
// Apply unit conversion if necessary
|
|
high_low_list := (
|
|
map_item.med_dose_high,
|
|
map_item.med_dose_low);
|
|
|
|
// Call the MLM to trim the decimals
|
|
rounded_high_low_list := call func_dosage_trim_adjusted with
|
|
sample_vals, dosage_range.conversion_factor, high_low_list;
|
|
|
|
map_item.adjusted_dose_high := rounded_high_low_list[1];
|
|
map_item.adjusted_dose_low := rounded_high_low_list[2];
|
|
map_item.adjusted_dose_uom := dosage_range.corrected_uom;
|
|
|
|
// CLINICAL RULE -- Determine if Dose is Out of Range for SINGLE DOSE
|
|
//--------------------------------------------------------------------
|
|
map_item.above_range := false;
|
|
map_item.below_range := false;
|
|
if (map_item.adjusted_dose_low < dosage_range.lower_dose)
|
|
then
|
|
map_item.below_range := true;
|
|
elseif (map_item.adjusted_dose_high > dosage_range.upper_dose)
|
|
then
|
|
map_item.above_range := true;
|
|
endif;
|
|
|
|
enddo;
|
|
med_data.outside_single_dosage_range := any found_maps.above_range
|
|
or any found_maps.below_range;
|
|
|
|
//----------------------------------
|
|
// Check TOTAL-DAILY Dosage Range
|
|
//----------------------------------
|
|
|
|
// Find the TOTAL-DAILY Dose medications
|
|
// with the same Name, UOM, and Route as the SINGLE DOSE
|
|
//--------------------------------------------------------------------
|
|
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.uom = med_data.order_med_units
|
|
or (total_tracker_list.uom is null and med_data.order_med_units is null))
|
|
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.start_date = med_data.order_med_significant_date));
|
|
|
|
for total_tracker in found_total_tracker do
|
|
|
|
// Only retreive the TOTAL DAILY dosage range criteria once for each Item-Catalog
|
|
// by checking to see if the criteria has already been stored in the object
|
|
|
|
if not exist total_tracker.retrieved_dose_range_data
|
|
AND exist med_data.retrieved_dose_range_data
|
|
then
|
|
// Find the dosage range for TOTAL DAILY DOSE
|
|
//--------------------------------------------
|
|
if use_item_catalog_dosage_data
|
|
then
|
|
// create map between medication and the total item catalog values
|
|
total_item_cat_dosage_range_list := item_cat_dosage_range_list
|
|
where (item_cat_dosage_range_list.dosage_type in ("total"));
|
|
|
|
// Set the Total Dosage Criteria in the Total_Tracker objects
|
|
//-----------------------------------------------------------
|
|
|
|
// Performed item catalog dosage look up for the medication
|
|
found_total_tracker.retrieved_dose_range_data := true;
|
|
|
|
// add the item catalog for total dosage ranges to the dosage range list
|
|
if ((exists total_item_cat_dosage_range_list) and (count total_item_cat_dosage_range_list > 0))
|
|
then
|
|
total_item_cat_dosage_range_list.dosage_type := "total";
|
|
|
|
dosage_range_list := dosage_range_list, total_item_cat_dosage_range_list;
|
|
|
|
// update the sort number
|
|
list_count := count dosage_range_list;
|
|
dosage_range_list.sort_number := 1 seqto list_count;
|
|
|
|
// create map between medication and the total item catalog dosage range value
|
|
for total_item_cat_dosage_range in total_item_cat_dosage_range_list
|
|
do
|
|
if total_item_cat_dosage_range.match_found
|
|
then
|
|
for found_total_tracker_item in found_total_tracker
|
|
do
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_total_tracker_item.sort_number;
|
|
map_item.med_name := found_total_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := total_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := total_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := total_item_cat_dosage_range.match_found;
|
|
enddo;
|
|
else // missing data dosage range is just mapped to first occurence of the medication
|
|
found_total_tracker_item := last found_total_tracker[1];
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_total_tracker_item.sort_number;
|
|
map_item.med_name := found_total_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := total_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := total_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := total_item_cat_dosage_range.match_found;
|
|
endif; // if total_item_cat_dosage_range.match_found
|
|
enddo; // for total_item_cat_dosage_range in total_item_cat_dosage_range_list
|
|
endif; // if ((exists total_item_cat_dosage_range_list) and (count total_item_cat_dosage_range_list > 0))
|
|
|
|
endif; //if use_item_catalog_dosage_data
|
|
|
|
if use_multum_dosage_data
|
|
then
|
|
total_dosage_ranges := dosage_range_list where dosage_range_list.dosage_type = "total";
|
|
found_total_tracker.retrieved_dose_range_data := true;
|
|
|
|
// create map between medication and the single or contraindication multum values
|
|
total_multum_dosage_list := multum_dosage_range_list
|
|
where (multum_dosage_range_list.dosage_type in ("total"));
|
|
|
|
for multum_dosage_range_item in total_multum_dosage_list
|
|
do
|
|
if ( multum_dosage_range_item.match_found
|
|
and multum_dosage_range_item.is_range )
|
|
then
|
|
for found_total_tracker_item in found_total_tracker
|
|
do
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_total_tracker_item.sort_number;
|
|
map_item.med_name := found_total_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := multum_dosage_range_item.sort_number;
|
|
map_item.dosage_type := multum_dosage_range_item.dosage_type;
|
|
map_item.match_found := multum_dosage_range_item.match_found;
|
|
enddo;
|
|
else
|
|
// missing criteria (match not found)
|
|
// These items should be mapped to the medicaiton as dosage comparion will not be done
|
|
found_total_tracker_item := last found_total_tracker[1];
|
|
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_total_tracker_item.sort_number;
|
|
map_item.med_name := found_total_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := multum_dosage_range_item.sort_number;
|
|
map_item.dosage_type := multum_dosage_range_item.dosage_type;
|
|
map_item.match_found := multum_dosage_range_item.match_found;
|
|
endif; // if multum_dosage_range_item.found_match
|
|
enddo; // for multum_dosage_range_item in total_multum_dosage_list
|
|
endif; // if use_multum_dosage_data
|
|
|
|
found_total_tracker.found_total_daily_dose := any (total_item_cat_dosage_range.match_found)
|
|
or any (total_multum_dosage_list.match_found);
|
|
endif; //if not exist total_tracker.retrieved_dose_range_data
|
|
|
|
|
|
// Process Clinical Rule Once for each Total Tracker
|
|
// by checking if it has already been processed
|
|
// the field outside_total_daily_dose is NULL if it has not been processed.
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Compare the medication total dose with the dosage range data
|
|
all_total_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "total" );
|
|
|
|
found_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number = total_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_total_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "total");
|
|
|
|
for map_item in found_maps
|
|
do
|
|
dosage_range := last dosage_range_list[map_item.dosage_range_sort_number];
|
|
|
|
// Set the Low & High Values for the TOTAL DAILY DOSE
|
|
//----------------------------------------------------
|
|
if dosage_range.dose_calc_method = dose_per_string
|
|
then // Set the total dose for the COMPOUND UOM (xxx/kg or xxx/m2)
|
|
|
|
// Find the correct conversion factor
|
|
if dosage_range.calc_per_core_uom = core_uom_const.M2_string
|
|
then conversion_factor_total := BSA_number_rounded;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.kg_string
|
|
then conversion_factor_total := wt_kg;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.gm_string
|
|
then conversion_factor_total := wt_kg * 1000;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.lb_string
|
|
then conversion_factor_total := wt_kg * 2.2045855 ;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.ounce_string
|
|
then conversion_factor_total := wt_kg * 2.2045855 * 16 ;
|
|
else
|
|
conversion_factor_total := 1 ;
|
|
endif; //if dosage_range.calc_per_core_uom
|
|
|
|
// Calculate and Set the dose for the COMPOUND UOM
|
|
order_total_dose_high:= total_tracker.total_dose_high / conversion_factor_total;
|
|
order_total_dose_low:= total_tracker.total_dose_low / conversion_factor_total;
|
|
|
|
// Round the DOSE-PER number to within 1 decimal point of the criteria.
|
|
//----------------------------------------------------------------------
|
|
// Example: If the upper dose criteria has 2 decimal points,
|
|
// then round to 3 decimals.
|
|
|
|
// Initalize Variables
|
|
high_low_list := order_total_dose_high, order_total_dose_low;
|
|
|
|
sample_vals := med_data.calc_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
|
|
// Call the MLM to trim the decimals
|
|
rounded_high_low_list := call func_dosage_trim with
|
|
sample_vals, high_low_list;
|
|
|
|
// Save the Calculated COMPOUND UOM into the Total_Tracker Object
|
|
total_tracker.total_calc_med_dose_high := rounded_high_low_list[1];
|
|
total_tracker.total_calc_med_dose_low := rounded_high_low_list[2];
|
|
|
|
map_item.med_dose_high := total_tracker.total_calc_med_dose_high;
|
|
map_item.med_dose_low := total_tracker.total_calc_med_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units || "/" || med_data.calc_med_per_uom;
|
|
|
|
sample_vals := med_data.calc_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
else
|
|
/* Set the total dose for the SIMPLE UOM (mg, cc, etc.) */
|
|
order_total_dose_high:= total_tracker.total_dose_high;
|
|
order_total_dose_low:= total_tracker.total_dose_low;
|
|
|
|
map_item.med_dose_high := total_tracker.total_dose_high;
|
|
map_item.med_dose_low := total_tracker.total_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units;
|
|
|
|
sample_vals := med_data.order_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
endif; // if dosage_range.dose_calc_method = dose_per_string
|
|
|
|
// Apply unit conversion if necessary
|
|
high_low_list := (
|
|
map_item.med_dose_high,
|
|
map_item.med_dose_low );
|
|
|
|
// Call the MLM to trim the decimals
|
|
rounded_high_low_list := call func_dosage_trim_adjusted with
|
|
sample_vals, dosage_range.conversion_factor, high_low_list;
|
|
|
|
map_item.adjusted_dose_high := rounded_high_low_list[1];
|
|
map_item.adjusted_dose_low := rounded_high_low_list[2];
|
|
map_item.adjusted_dose_uom := dosage_range.corrected_uom;
|
|
|
|
// CLINICAL RULE -- Determine if Dose is Out of Range for TOTAL DAILY DOSE
|
|
//-------------------------------------------------------------------------
|
|
// use the dose values before rounding to compare
|
|
map_item.above_range := false;
|
|
map_item.below_range := false;
|
|
|
|
IF (map_item.adjusted_dose_high > dosage_range.upper_dose)
|
|
then
|
|
map_item.above_range := true;
|
|
elseif (map_item.adjusted_dose_low < dosage_range.lower_dose)
|
|
then
|
|
// low dose out of range, needs more checking.
|
|
if total_tracker.has_full_24hrs_doses = false and total_tracker.is_last_24hr_interval = true
|
|
then
|
|
if total_tracker.med_order_type <> "Complex Order"
|
|
then
|
|
map_item.below_range := true;
|
|
endif; // if total_tracker.med_order_type <> "Complex Order"
|
|
else
|
|
map_item.below_range := true;
|
|
endif; // if total_tracker.is_24hr_doses = false
|
|
endif; // if map_item.adjusted_dose_high > dosage_range.upper_dose
|
|
enddo; // for map_item in found_maps
|
|
|
|
total_tracker.outside_total_daily_dose := any found_maps.above_range
|
|
or any found_maps.below_range;
|
|
|
|
enddo; // for total_tracker
|
|
|
|
|
|
//----------------------------------
|
|
// Check AVERAGE-DAILY Dosage Range
|
|
//----------------------------------
|
|
// Average-Daily Dosage Range should be checked for Regular and IV-Additives.
|
|
// If a Complex Order does NOT have a Total-Daily dosage-range criteria,
|
|
// then substitute the Average-Daily criteria to do a dosage-range check
|
|
// for the Total-Daily.
|
|
if med_data.med_order_type is in ("Regular", "IV-Additive")
|
|
or (med_data.med_order_type = "Complex Order"
|
|
and NO (found_total_tracker.found_total_daily_dose where it is present))
|
|
// Note: {{{SINGLE-QUOTE}}}where it is present{{{SINGLE-QUOTE}}} assures that the list does not contain
|
|
// any NULL values before processing it with the NO operator.
|
|
then
|
|
|
|
// Find the AVERAGE-DAILY Dose medications
|
|
// with the same Name, UOM, and Route as the SINGLE DOSE
|
|
//-------------------------------------------------------------------
|
|
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.uom = med_data.order_med_units
|
|
OR (average_tracker_list.uom is null and med_data.order_med_units is null))
|
|
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.start_date = med_data.order_med_significant_date)
|
|
);
|
|
|
|
for average_tracker in found_average_tracker do
|
|
|
|
// Only retreive the AVERAGE DAILY dosage range criteria once for each Item-Catalog
|
|
// by checking to see if the criteria has already been stored in the object
|
|
|
|
if not exist average_tracker.retrieved_dose_range_data
|
|
AND exist med_data.retrieved_dose_range_data
|
|
then
|
|
// Find the dosage range AVERAGE DAILY DOSE
|
|
//------------------------------------------
|
|
if use_item_catalog_dosage_data
|
|
then
|
|
// create map between medication and the average item catalog values
|
|
average_item_cat_dosage_range_list := item_cat_dosage_range_list
|
|
where (item_cat_dosage_range_list.dosage_type in ("average"));
|
|
|
|
// Set the Total Dosage Criteria in the Average_Tracker objects
|
|
//--------------------------------------------------------------
|
|
found_average_tracker.retrieved_dose_range_data := true;
|
|
found_average_tracker.found_average_daily_dose := any (average_item_cat_dosage_range_list.match_found);
|
|
|
|
// add the item catalog for average dosage ranges to the dosage range list
|
|
if ((exists average_item_cat_dosage_range_list) and (count average_item_cat_dosage_range_list > 0))
|
|
then
|
|
average_item_cat_dosage_range_list.dosage_type := "average";
|
|
dosage_range_list := dosage_range_list, average_item_cat_dosage_range_list;
|
|
|
|
// update the sort number
|
|
list_count := count dosage_range_list;
|
|
dosage_range_list.sort_number := 1 seqto list_count;
|
|
|
|
// create map between medication and the average item catalog dosage range value
|
|
for average_item_cat_dosage_range in average_item_cat_dosage_range_list
|
|
do
|
|
if average_item_cat_dosage_range.match_found
|
|
then
|
|
for found_average_tracker_item in found_average_tracker
|
|
do
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_average_tracker_item.sort_number;
|
|
map_item.med_name := found_average_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := average_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := average_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := average_item_cat_dosage_range.match_found;
|
|
enddo;
|
|
else // missing data dosage range is just mapped to first occurence of the medication
|
|
found_average_tracker_item := last found_average_tracker[1];
|
|
map_item := new Medication_Dosage_Range_Map;
|
|
med_dosage_map_list := med_dosage_map_list, map_item;
|
|
map_item.med_sort_number := found_average_tracker_item.sort_number;
|
|
map_item.med_name := found_average_tracker_item.med_name;
|
|
map_item.dosage_range_sort_number := average_item_cat_dosage_range.sort_number;
|
|
map_item.dosage_type := average_item_cat_dosage_range.dosage_type;
|
|
map_item.match_found := average_item_cat_dosage_range.match_found;
|
|
endif; // if average_item_cat_dosage_range.match_found
|
|
enddo; // for average_item_cat_dosage_range in average_item_cat_dosage_range_list
|
|
endif; // if ((exists average_item_cat_dosage_range_list) and (count average_item_cat_dosage_range_list > 0))
|
|
endif; // if use_item_catalog_dosage_data
|
|
endif; //if not exist average_tracker.retrieved_dose_range_data
|
|
|
|
|
|
// Process Clinical Rule Once for each Average Tracker
|
|
// by checking if it has already been processed
|
|
// the field outside_total_daily_dose is NULL if it has not been processed.
|
|
//--------------------------------------------------------------------------
|
|
// Compare the medication average dose with the dosage range data
|
|
all_average_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "average" );
|
|
|
|
found_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number = average_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_average_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "average");
|
|
|
|
for map_item in found_maps
|
|
do
|
|
dosage_range := last dosage_range_list[map_item.dosage_range_sort_number];
|
|
// Set the Low & High Values for the AVERAGE DAILY DOSE
|
|
//------------------------------------------------------
|
|
if dosage_range.dose_calc_method = dose_per_string
|
|
then // Set the average dose for the COMPOUND UOM (xxx/kg or xxx/m2)
|
|
|
|
// Find the correct conversion factor
|
|
if dosage_range.calc_per_core_uom = core_uom_const.M2_string
|
|
then conversion_factor_ave := BSA_number_rounded;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.kg_string
|
|
then conversion_factor_ave := wt_kg;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.gm_string
|
|
then conversion_factor_ave := wt_kg * 1000;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.lb_string
|
|
then conversion_factor_ave := wt_kg * 2.2045855 ;
|
|
elseif dosage_range.calc_per_core_uom = core_uom_const.ounce_string
|
|
then conversion_factor_ave := wt_kg * 2.2045855 * 16 ;
|
|
else
|
|
conversion_factor_ave := 1 ;
|
|
endif; //if dosage_range.calc_per_core_uom
|
|
|
|
// Calculate and Set the dose for the COMPOUND UOM
|
|
order_average_dose_high :=
|
|
average_tracker.average_dose_high / conversion_factor_ave;
|
|
order_average_dose_low :=
|
|
average_tracker.average_dose_low / conversion_factor_ave;
|
|
|
|
// Round the DOSE-PER number to within 1 decimal point of the criteria.
|
|
//----------------------------------------------------------------------
|
|
// Example: If the upper dose criteria has 2 decimal points,
|
|
// then round to 3 decimals.
|
|
|
|
// Initalize Variables
|
|
high_low_list := order_average_dose_high, order_average_dose_low;
|
|
|
|
sample_vals := dosage_range.lower_dose, dosage_range.upper_dose;
|
|
|
|
// Call the MLM to round to one extra decimal point based on the low/high numbers for the DRC range.
|
|
// uom_conversion_factor is the conversion factor between the order dose UOM and dose range UOM. For example,
|
|
// 1. if order dose is in G, DRC range UOM is G, uom_conversion_factor = 1000;
|
|
// 2. if order dose is in MG, DRC range UOM is G, uom_conversion_factor = 0.001;
|
|
// 3. if order dose UOM and DRC range UOM are same, uom_conversion_factor = 1.
|
|
// "sample_vals / dosage_range.uom_conversion_factor" is used to be the sample values to trim the extra
|
|
// decimal points. So the rounded values will have one extra decimal point based on the DRC range low/high
|
|
// number in the scenario where UOM conversion is involved. uom_conversion_factor values are saved in core load
|
|
// table SXAUnitOfMeasureConversion. Currently the values in this table are all dividable.
|
|
rounded_high_low_list := call func_dosage_trim with
|
|
sample_vals / dosage_range.uom_conversion_factor, high_low_list;
|
|
|
|
// Save the Calculated COMPOUND UOM into the Average_Tracker Object
|
|
average_tracker.average_calc_med_dose_high := rounded_high_low_list[1];
|
|
average_tracker.average_calc_med_dose_low := rounded_high_low_list[2];
|
|
|
|
map_item.med_dose_high := average_tracker.average_calc_med_dose_high;
|
|
map_item.med_dose_low := average_tracker.average_calc_med_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units || "/" || med_data.calc_med_per_uom;
|
|
|
|
sample_vals := med_data.calc_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
else
|
|
/* Set the average dose for the SIMPLE UOM (mg, cc, etc.) */
|
|
order_average_dose_high:= average_tracker.average_dose_high;
|
|
order_average_dose_low:= average_tracker.average_dose_low;
|
|
|
|
map_item.med_dose_high := order_average_dose_high;
|
|
map_item.med_dose_low := order_average_dose_low;
|
|
map_item.med_dose_uom := med_data.order_med_units;
|
|
|
|
high_low_list := (
|
|
map_item.med_dose_high,
|
|
map_item.med_dose_low );
|
|
|
|
sample_vals := dosage_range.lower_dose, dosage_range.upper_dose;
|
|
|
|
// Call the MLM to round to one extra decimal point based on the low/high numbers for the DRC range.
|
|
// uom_conversion_factor is the conversion factor between the order dose UOM and dose range UOM. For example,
|
|
// 1. if order dose is in G, DRC range UOM is G, uom_conversion_factor = 1000;
|
|
// 2. if order dose is in MG, DRC range UOM is G, uom_conversion_factor = 0.001;
|
|
// 3. if order dose UOM and DRC range UOM are same, uom_conversion_factor = 1.
|
|
// "sample_vals / dosage_range.uom_conversion_factor" is used to be the sample values to trim the extra
|
|
// decimal points. So the rounded values will have one extra decimal point based on the DRC range low/high
|
|
// number in the scenario where UOM conversion is involved. uom_conversion_factor values are saved in core load
|
|
// table SXAUnitOfMeasureConversion. Currently the values in this table are all dividable.
|
|
rounded_high_low_list := call func_dosage_trim with
|
|
sample_vals / dosage_range.uom_conversion_factor, high_low_list;
|
|
map_item.med_dose_high := rounded_high_low_list[1];
|
|
map_item.med_dose_low := rounded_high_low_list[2];
|
|
|
|
sample_vals := med_data.order_med_dose_low, dosage_range.lower_dose, dosage_range.upper_dose;
|
|
endif; // if dosage_range.dose_calc_method = dose_per_string
|
|
|
|
// Apply unit conversion if necessary
|
|
high_low_list := (
|
|
map_item.med_dose_high,
|
|
map_item.med_dose_low );
|
|
|
|
// Call the MLM to trim the decimals
|
|
rounded_high_low_list := call func_dosage_trim_adjusted with
|
|
sample_vals, dosage_range.conversion_factor, high_low_list;
|
|
|
|
map_item.adjusted_dose_high := rounded_high_low_list[1];
|
|
map_item.adjusted_dose_low := rounded_high_low_list[2];
|
|
map_item.adjusted_dose_uom := dosage_range.corrected_uom;
|
|
|
|
// CLINICAL RULE -- Determine if Dose is Out of Range for AVERAGE DAILY DOSE
|
|
//---------------------------------------------------------------------------
|
|
|
|
map_item.above_range := false;
|
|
map_item.below_range := false;
|
|
|
|
if map_item.adjusted_dose_high > dosage_range.upper_dose
|
|
then
|
|
map_item.above_range := true;
|
|
elseif (map_item.adjusted_dose_low < dosage_range.lower_dose)
|
|
then
|
|
// low dose out of range, needs more checking.
|
|
if average_tracker.has_full_24hrs_doses = false and average_tracker.is_last_24hr_interval = true
|
|
then
|
|
if average_tracker.med_order_type <> "Complex Order"
|
|
then
|
|
map_item.below_range := true;
|
|
endif; // if average_tracker.med_order_type <> "Complex Order"
|
|
else
|
|
map_item.below_range := true;
|
|
endif; // if average_tracker.has_full_24hrs_doses = false and average_tracker.is_last_24hr_interval = true
|
|
endif; // if order_average_dose_high > dosage_range.upper_dose
|
|
enddo; //for map_item in found_maps
|
|
|
|
average_tracker.outside_average_daily_dose := any found_maps.below_range
|
|
or any found_maps.above_range;
|
|
|
|
enddo; //for average_tracker
|
|
|
|
endif; //if med_data.med_order_type is in ("Regular", "IV-Additive")
|
|
|
|
|
|
enddo; // for med_data
|
|
|
|
//-------------------------------
|
|
// Special Creatinine Rules
|
|
//-------------------------------
|
|
// Extra creatinine values were retrieved.
|
|
// We only need to display these values when there{{{SINGLE-QUOTE}}}s a dialysis outside range, or creatinine outside range
|
|
all_creatinine_dose_ranges := dosage_range_list where (dosage_range_list.creatinine_criteria is not null);
|
|
patient_criteria_dose_ranges := all_creatinine_dose_ranges where all_creatinine_dose_ranges.crcl_within_range;
|
|
|
|
// Check if there{{{SINGLE-QUOTE}}}s dialysis or creatinine outside range
|
|
show_other_creatinine_values := count (med_dosage_map_list where
|
|
med_dosage_map_list.dosage_range_sort_number in patient_criteria_dose_ranges.sort_number
|
|
AND
|
|
( // patient crcl range in supplemental
|
|
med_dosage_map_list.match_found = false
|
|
OR
|
|
// patient crcl range is contraindication
|
|
med_dosage_map_list.dosage_type = "contraindication"
|
|
OR
|
|
// patient crcl range is outside range
|
|
( med_dosage_map_list.above_range = true OR med_dosage_map_list.below_range = true)
|
|
)) > 0;
|
|
|
|
if (count all_creatinine_dose_ranges > 0 and not show_other_creatinine_values)
|
|
then
|
|
// When the patient creatinine dose range is within range, remove the default and
|
|
// other creatinine (these dose ranges already have match_found as false)
|
|
// When there is no patient creatinine dose range found, remove the other creatinine
|
|
// values (which already have match_found as false).
|
|
// - The default range value won{{{SINGLE-QUOTE}}}t exist if there are other dose ranges with match_found is true.
|
|
// - If the default range is the only one that matches patient critieria, it will have the
|
|
// match_found as true, and will be kept
|
|
dose_ranges_to_remove := dosage_range_list where
|
|
(
|
|
dosage_range_list.match_found = false
|
|
AND ( dosage_range_list.is_default = true
|
|
OR dosage_range_list.sort_number in all_creatinine_dose_ranges.sort_number
|
|
)
|
|
);
|
|
|
|
// There{{{SINGLE-QUOTE}}}s no renal outside range
|
|
// Remove the additional creatinine maps from the map list
|
|
no_creatinine_med_dosage_map_list := med_dosage_map_list where
|
|
(med_dosage_map_list.dosage_range_sort_number not in
|
|
dose_ranges_to_remove.sort_number);
|
|
|
|
med_dosage_map_list := no_creatinine_med_dosage_map_list;
|
|
endif;
|
|
|
|
//--------------------------------
|
|
// CLINICAL RULES -- Missing Data
|
|
//--------------------------------
|
|
patient_info.Age := new Patient_Property_Obj;
|
|
patient_info.Age.type := "Age";
|
|
patient_info.Age.value := age_str;
|
|
patient_info.Age.is_missing := not has_valid_birthdate;
|
|
|
|
|
|
// If any medication has missing route or uom conversion issue set the value
|
|
missing_route := any med_data_list.missing_route;
|
|
unmapped_route := any med_data_list.unmapped_route;
|
|
|
|
missing_uom := any med_data_list.missing_uom;
|
|
unmapped_uom := any med_data_list.unmapped_uom;
|
|
uom_conversion_issue := any med_data_list.uom_conversion_issue;
|
|
|
|
//------------------------------------------
|
|
// Clinical Rule For Weekly <User Schedule>
|
|
//------------------------------------------
|
|
// The Average Daily Dose for a Weekly schedule cannot be determined
|
|
// because there can be days in the week when a patient does not receive any medications.
|
|
// The formula for Average Daily Dosage assumes that the patient receives
|
|
// medication each day in order to compute an average.
|
|
// RULE: Suppress any Average Daily Dose alert
|
|
// when the Frequency is <User Schedule>
|
|
// and the schedule in "Weekly"
|
|
|
|
if ANY (med_data_list.order_interval = "Weekly" )
|
|
and ANY (med_data_list.order_med_frequency = "<User Schedule>" )
|
|
and ANY (average_tracker_list.found_average_daily_dose )
|
|
then
|
|
// Find all average dosage range and average maps
|
|
average_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "average" );
|
|
|
|
average_maps := med_dosage_map_list where ( med_dosage_map_list.dosage_type = "average");
|
|
|
|
// Set <User Scheduled> Weekly Flag to true
|
|
average_tracker_list.user_scheduled_weekly_used := TRUE;
|
|
|
|
// Suppress Alert for Outside Average Daily Dose by setting it to false.
|
|
// And set the Suppress_Alert audit trail flag
|
|
average_tracker_list.outside_average_daily_dose := FALSE;
|
|
average_tracker_list.suppress_alert := TRUE;
|
|
average_dosage_range.match_found := false;
|
|
average_maps.above_range := false;
|
|
average_maps.below_range := false;
|
|
endif; //if ANY (med_data_list.order_interval = "Weekly" )
|
|
|
|
|
|
//---------------------------------------------
|
|
// Clinical Rule For Irregular <User Schedule>
|
|
//---------------------------------------------
|
|
|
|
// If the frequency is <User Schedule>
|
|
// and the type of schedule is "Irregular"
|
|
// and the order is a "Regular" or "IV-Additive Order"
|
|
// and there are average-daily dose criteria
|
|
// and the flag for showing irregular message is true
|
|
// then show the Alert that average-daily dose could not be checked.
|
|
//
|
|
// This rules does not apply to Complex Orders
|
|
// because we do not check their average-daily doses and
|
|
// because the user cannot select an "Irregular" schedule
|
|
|
|
if ANY (med_data_list.order_interval = "Irregular" )
|
|
and ANY (med_data_list.order_med_frequency = "<User Schedule>" )
|
|
and ANY (average_tracker_list.found_average_daily_dose )
|
|
then
|
|
// Find all average dosage range and average maps
|
|
average_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "average" );
|
|
|
|
average_maps := med_dosage_map_list where ( med_dosage_map_list.dosage_type = "average");
|
|
|
|
// Set Irregular Flag to true
|
|
average_tracker_list.irregular_schedule_used := TRUE;
|
|
|
|
// Suppress Alert for Outside Average Daily Dose
|
|
// by setting it to false.
|
|
average_tracker_list.outside_average_daily_dose := FALSE;
|
|
average_tracker_list.suppress_alert := TRUE;
|
|
average_dosage_range.match_found := false;
|
|
average_maps.above_range := false;
|
|
average_maps.below_range := false;
|
|
endif; //if ANY (med_data_list.order_interval = "Irregular" )
|
|
|
|
|
|
|
|
//----------------------------------------------------
|
|
// Clinical Rule For Doses Administered Under 24 Hours
|
|
//----------------------------------------------------
|
|
// DO NOT alert if the order is a loading dose for
|
|
// a NOW & THEN complex order. This type of order has
|
|
// a NULL frequency and a time interval of 1 minute.
|
|
//
|
|
// If the user has selected StopAfter
|
|
// and the duration of the order is < 24 hours
|
|
// and (Total Dose Criteria exists or Average Dose Criteria Exists)
|
|
// 1. DO NOT alert if the user selected StopAfter X-Times or StopAfter X-Days
|
|
// because the Total Dose and Average Dose can be determined.
|
|
// 2. DO Alert if the user selected StopAter X-Minutes or StopAfter X-Hours
|
|
// that resuls in a duration under 24 hours
|
|
// because the Total Dose and Average Dose cannot be determined.
|
|
//
|
|
// If the user has NOT selected StopAfter
|
|
// and ((StopDtm - SignificantDtm) < 24 hours
|
|
// and (Total Dose Criteria exists or Average Dose Criteria Exists)
|
|
// then Alert Total Dose and/or Average Dose cannot be determined.
|
|
|
|
|
|
for med_data in med_data_list do
|
|
|
|
// Initialize Variable
|
|
met_criteria_under_24_hours := FALSE;
|
|
|
|
//Calculate the Duration of the Order
|
|
if med_data.stop_after_option_type = 1
|
|
then order_duration := med_data.stop_after_value DAY;
|
|
elseif med_data.stop_after_option_type = 2
|
|
then order_duration := med_data.stop_after_value HOUR;
|
|
elseif med_data.stop_after_option_type = 3
|
|
then order_duration := med_data.stop_after_value MINUTE;
|
|
elseif exist med_data.stop_dtm
|
|
then order_duration := med_data.stop_dtm - med_data.order_med_significant_date;
|
|
else
|
|
order_duration := NULL;
|
|
endif;
|
|
|
|
// Determine if Order has Met the Criteria for Duration Under 24 Hours
|
|
if order_duration < 24 hours
|
|
then
|
|
if med_data.med_order_type = "Complex Order"
|
|
and med_data.order_med_frequency is NULL
|
|
and order_duration = 1 minute
|
|
then
|
|
// This is a loading dose for a NOW and THEN order
|
|
// so do not alert about under 24-hours.
|
|
met_criteria_under_24_hours := FALSE;
|
|
elseif med_data.stop_after_option_type = 1 //days
|
|
or med_data.stop_after_option_type = 4 //times
|
|
then
|
|
met_criteria_under_24_hours := FALSE;
|
|
elseif ( med_data.stop_after_option_type = 2 //hours
|
|
or med_data.stop_after_option_type = 3 ) //minutes
|
|
and med_data.admin_dtm_list_calc_method = "MLM" // estimated method
|
|
then
|
|
met_criteria_under_24_hours := TRUE;
|
|
elseif exist med_data.stop_dtm
|
|
and (med_data.stop_after_option_type = 0 //not a stopafter
|
|
or med_data.stop_after_option_type is NULL)
|
|
and med_data.admin_dtm_list_calc_method = "MLM" // estimated method
|
|
then
|
|
met_criteria_under_24_hours := TRUE;
|
|
else
|
|
met_criteria_under_24_hours := FALSE; // formally TRUE
|
|
endif;
|
|
endif; //order_duration < 24 hours
|
|
|
|
// Find the Matching Average Tracker and Total Tracker Objects
|
|
// That have Average Daily or Total Daily Dose Criteria
|
|
if met_criteria_under_24_hours
|
|
then
|
|
|
|
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.uom = med_data.order_med_units
|
|
AND average_tracker_list.route = med_data.order_med_route
|
|
AND average_tracker_list.found_average_daily_dose );
|
|
|
|
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.uom = med_data.order_med_units
|
|
AND total_tracker_list.route = med_data.order_med_route
|
|
AND total_tracker_list.found_total_daily_dose );
|
|
|
|
|
|
all_average_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "average" );
|
|
|
|
found_average_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number in found_average_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_average_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "average");
|
|
|
|
found_average_dosage_range := dosage_range_list where (
|
|
dosage_range_list.sort_number in found_average_maps.dosage_range_sort_number);
|
|
|
|
all_total_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "total" );
|
|
|
|
found_total_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number in found_total_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_total_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "total");
|
|
|
|
found_total_dosage_range := dosage_range_list where (
|
|
dosage_range_list.sort_number in found_total_maps.dosage_range_sort_number);
|
|
|
|
if exist found_average_tracker
|
|
then
|
|
// Set flags in Object
|
|
found_average_tracker.met_criteria_under_24_hours := met_criteria_under_24_hours;
|
|
|
|
// Suppress Alert for Outside Average Daily Dose by setting it to false.
|
|
// And setting the Suppress_Alert flag as a audit trail.
|
|
found_average_tracker.outside_average_daily_dose := FALSE;
|
|
found_average_tracker.suppress_alert := TRUE;
|
|
found_average_maps.above_range := false;
|
|
found_average_maps.below_range := false;
|
|
found_average_dosage_range.match_found := false;
|
|
endif;
|
|
|
|
if exist found_total_tracker
|
|
then
|
|
// Set flags in Object
|
|
found_total_tracker.met_criteria_under_24_hours := met_criteria_under_24_hours;
|
|
|
|
// Suppress Alert for Outside Total Daily Dose by setting it to false.
|
|
// And setting the Suppress_Alert flag as a audit trail.
|
|
found_total_tracker.outside_total_daily_dose := FALSE;
|
|
found_total_tracker.suppress_alert := TRUE;
|
|
|
|
found_total_maps.above_range := false;
|
|
found_total_maps.below_range := false;
|
|
found_total_dosage_range.match_found := false;
|
|
endif;
|
|
endif; // if met_criteria_under_24_hours
|
|
enddo; //for med_data
|
|
|
|
// If any fequency in the component list is based on shift then
|
|
// a warning needs to be displayed.
|
|
if any med_data_list.isShiftFrequency = true
|
|
then
|
|
|
|
shiftData := med_data_list where
|
|
(med_data_list.isShiftFrequency = true);
|
|
|
|
// Only warn if an Average or Total warning was calculated.
|
|
found_average_tracker := average_tracker_list where
|
|
(average_tracker_list.med_order_type is in (shiftData.med_order_type)
|
|
AND average_tracker_list.med_name is in (shiftData.order_med_name)
|
|
AND average_tracker_list.uom is in (shiftData.order_med_units)
|
|
AND average_tracker_list.route is in (shiftData.order_med_route)
|
|
AND average_tracker_list.found_average_daily_dose
|
|
AND average_tracker_list.outside_average_daily_dose );
|
|
|
|
found_total_tracker := total_tracker_list where
|
|
(total_tracker_list.med_order_type is in (shiftData.med_order_type)
|
|
AND total_tracker_list.med_name is in (shiftData.order_med_name)
|
|
AND total_tracker_list.uom is in (shiftData.order_med_units)
|
|
AND total_tracker_list.route is in (shiftData.order_med_route)
|
|
AND total_tracker_list.found_total_daily_dose
|
|
AND total_tracker_list.outside_total_daily_dose );
|
|
|
|
all_average_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "average" );
|
|
|
|
found_average_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number in found_average_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_average_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "average");
|
|
|
|
found_average_dosage_range := dosage_range_list where (
|
|
dosage_range_list.sort_number in found_average_maps.dosage_range_sort_number);
|
|
|
|
all_total_dosage_range := dosage_range_list where (dosage_range_list.match_found AND
|
|
dosage_range_list.dosage_type = "total" );
|
|
|
|
found_total_maps := med_dosage_map_list where (med_dosage_map_list.med_sort_number in found_total_tracker.sort_number AND
|
|
med_dosage_map_list.dosage_range_sort_number in all_total_dosage_range.sort_number AND
|
|
med_dosage_map_list.dosage_type = "total");
|
|
|
|
found_total_dosage_range := dosage_range_list where (
|
|
dosage_range_list.sort_number in found_total_maps.dosage_range_sort_number);
|
|
|
|
// If some administration times were generated, they need to be supressed
|
|
// for the items that used the shift based frequency
|
|
if exists found_average_tracker then
|
|
found_average_tracker.met_criteria_has_shift_frequency := true;
|
|
// Suppress Alert for Outside Average Daily Dose by setting it to false.
|
|
// And setting the Suppress_Alert flag as a audit trail.
|
|
found_average_tracker.outside_average_daily_dose := FALSE;
|
|
found_average_tracker.suppress_alert := TRUE;
|
|
found_average_maps.above_range := false;
|
|
found_average_maps.below_range := false;
|
|
found_average_dosage_range.match_found := false;
|
|
endif;
|
|
|
|
if exists found_total_tracker then
|
|
found_total_tracker.met_criteria_has_shift_frequency := true;
|
|
// Suppress Alert for Outside Total Daily Dose by setting it to false.
|
|
// And setting the Suppress_Alert flag as a audit trail.
|
|
found_total_tracker.outside_total_daily_dose := FALSE;
|
|
found_total_tracker.suppress_alert := TRUE;
|
|
found_total_maps.above_range := false;
|
|
found_total_maps.below_range := false;
|
|
found_total_dosage_range.match_found := false;
|
|
endif;
|
|
endif;
|
|
|
|
med_dosage_map_list.sort_number := 1 seqto (count med_dosage_map_list);
|
|
|
|
hard_stop_low_doses := dosage_range_list where dosage_range_list.hard_stop_low = true;
|
|
hard_stop_high_doses := dosage_range_list where dosage_range_list.hard_stop_high = true;
|
|
med_with_hard_Stop := exists (med_dosage_map_list
|
|
where (med_dosage_map_list.dosage_range_sort_number in hard_stop_low_doses.sort_number and med_dosage_map_list.below_range)
|
|
or (med_dosage_map_list.dosage_range_sort_number in hard_stop_high_doses.sort_number and med_dosage_map_list.above_range)
|
|
or (med_dosage_map_list.dosage_type = "contraindication" and med_dosage_map_list.match_found = true and
|
|
(med_dosage_map_list.dosage_range_sort_number in hard_stop_low_doses.sort_number or med_dosage_map_list.dosage_range_sort_number in hard_stop_high_doses.sort_number)));
|
|
|
|
inapplicable_route_found := exists( dosage_range_list where dosage_range_list.inapplicable_route_conversion_issue = true );
|
|
|
|
map_with_frequency_issue_list := med_dosage_map_list
|
|
where med_dosage_map_list.dose_frequency not in intentionally_unmapped_frequency_list
|
|
and med_dosage_map_list.frequency_issue is not null;
|
|
|
|
show_frequency_warning := exists (map_with_frequency_issue_list)
|
|
and ( ( alert_if_missing_flags.unmapped_frequency
|
|
and any (map_with_frequency_issue_list.frequency_issue = "unmapped"))
|
|
or ( any (map_with_frequency_issue_list.frequency_issue = "too frequent")));
|
|
|
|
|
|
// get the catalog dose ranges that match the prescription only at the
|
|
// dnum level
|
|
dnum_match_catalog_dose_range_list := ();
|
|
if (not med_data_list[1].is_order)
|
|
then
|
|
dnum_match_catalog_dose_range_list := dosage_range_list where
|
|
dosage_range_list.match_found = false
|
|
AND dosage_range_list.is_multum = false
|
|
AND dosage_range_list.dnum_ic_match_found = true;
|
|
endif;
|
|
|
|
/*----------------------------------*/
|
|
/* Format Alert Range Error Details */
|
|
/*----------------------------------*/
|
|
if any med_data_list.outside_single_dosage_range
|
|
OR any med_data_list.contraindication_found
|
|
OR any average_tracker_list.outside_average_daily_dose
|
|
OR any total_tracker_list.outside_total_daily_dose
|
|
OR (any average_tracker_list.user_scheduled_weekly_used
|
|
and show_user_scheduled_weekly_message )
|
|
OR (any average_tracker_list.irregular_schedule_used
|
|
and show_irregular_message )
|
|
OR (any total_tracker_list.met_criteria_under_24_hours
|
|
and show_under_24_hour_message)
|
|
OR (any average_tracker_list.met_criteria_under_24_hours
|
|
and show_under_24_hour_message)
|
|
OR (any total_tracker_list.met_criteria_has_shift_frequency
|
|
and show_has_shift_frequency_message)
|
|
OR (any average_tracker_list.met_criteria_has_shift_frequency
|
|
and show_has_shift_frequency_message)
|
|
OR (patient_info.Age.is_missing
|
|
and alert_if_missing_flags.patient_age)
|
|
OR (patient_info.Gender.is_missing
|
|
and alert_if_missing_flags.patient_gender)
|
|
OR (patient_info.Gender.unknown_other
|
|
and alert_if_missing_flags.patient_gender)
|
|
OR ( ( patient_info.Height.is_missing
|
|
or patient_info.Height.not_current )
|
|
and alert_if_missing_flags.patient_height)
|
|
OR ( ( patient_info.Weight.is_missing
|
|
or patient_info.Weight.not_current )
|
|
and alert_if_missing_flags.patient_weight)
|
|
OR (missing_route
|
|
and alert_if_missing_flags.route)
|
|
OR (unmapped_route
|
|
and alert_if_missing_flags.unmapped_route)
|
|
OR (uom_conversion_issue
|
|
and alert_if_missing_flags.uom_conversion)
|
|
OR (missing_uom
|
|
and alert_if_missing_flags.uom)
|
|
OR (unmapped_uom
|
|
and alert_if_missing_flags.unmapped_uom)
|
|
OR (patient_info.Gender.is_unmapped
|
|
and alert_if_missing_flags.unmapped_gender)
|
|
OR (any med_data_list.unmapped_drug
|
|
and alert_if_missing_flags.unmapped_drug)
|
|
OR (any med_data_list.unmapped_grouper
|
|
and alert_if_missing_flags.unmapped_grouper)
|
|
OR (any patient_info.DNum_Grouper.is_unmapped
|
|
and alert_if_missing_flags.cannot_check_DNUM_Rx_To_Multum)
|
|
OR (exists (dnum_match_catalog_dose_range_list)
|
|
and alert_if_missing_flags.cannot_check_Rx_to_IC )
|
|
OR (any med_data_list.generic_route
|
|
and alert_if_missing_flags.cannot_check_generic_route)
|
|
OR ( inapplicable_route_found
|
|
and alert_if_missing_flags.inapplicable_route )
|
|
OR ( show_frequency_warning )
|
|
then
|
|
(alert_detail_text,
|
|
missing_data_list,
|
|
cannot_check_list,
|
|
alert_abstract ):= call func_dosage_messages with
|
|
(
|
|
ht_cm,
|
|
wt_kg,
|
|
patient_info,
|
|
med_data_list,
|
|
average_tracker_list,
|
|
total_tracker_list,
|
|
dosage_range_list,
|
|
med_dosage_map_list,
|
|
alert_if_missing_flags,
|
|
use_multum_dosage_data,
|
|
show_irregular_message,
|
|
show_under_24_hour_message,
|
|
show_has_shift_frequency_message,
|
|
show_user_scheduled_weekly_message,
|
|
show_Debug_statements,
|
|
column_catalog_name,
|
|
column_Multum_name,
|
|
patient_birthday_info_on_order
|
|
) ;
|
|
endif; //if any med_data_list.outside_single_dosage_range
|
|
|
|
|
|
/* Always Conclude True to Return Data */
|
|
conclude true;
|
|
|
|
;;
|
|
action:
|
|
return
|
|
(alert_detail_text,
|
|
average_tracker_list,
|
|
total_tracker_list,
|
|
missing_data_list,
|
|
cannot_check_list,
|
|
med_with_hard_stop,
|
|
show_frequency_warning,
|
|
alert_abstract);
|
|
|
|
;;
|
|
end:
|