maintenance: title: Calculate Dosage Based on Actual, Ideal or Adjusted Weight or BSA or AUC;; mlmname: SYS_CALC_DOSAGE;; arden: version 2.5;; version: 18.4;; institution: Allscripts, System MLM;; author: Allscripts Healthcare Solutions, Inc.;; specialist: ;; date: 2018-10-26;; validation: testing;; /* P r o p r i e t a r y N o t i c e */ /* Unpublished (c) 2013 - 2018 Allscripts Healthcare, LLC. and/or its affiliates. All Rights Reserved. P r o p r i e t a r y N o t i c e: This software has been provided pursuant to a License Agreement, with Allscripts Healthcare, LLC. and/or its affiliates, containing restrictions on its use. This software contains valuable trade secrets and proprietary information of Allscripts Healthcare, LLC. and/or its affiliates and is protected by trade secret and copyright law. This software may not be copied or distributed in any form or medium, disclosed to any third parties, or used in any manner not provided for in said License Agreement except with prior written authorization from Allscripts Healthcare, LLC. and/or its affiliates. Notice to U.S. Government Users: This software is {{{SINGLE-QUOTE}}}Commercial Computer Software{{{SINGLE-QUOTE}}}. All product names are the trademarks or registered trademarks of Allscripts Healthcare, LLC. and/or its affiliates. */ /* P r o p r i e t a r y N o t i c e */ library: purpose: Calculates medication per dose based on a Dose Basis. Dose Basis can be Actual, Ideal or Adjusted weight in Kg or Actual, Ideal or Adjusted BSA. In addition, the Dose Basis list has expanded to include the Area Under the Curve (AUC) using measured or Estimated Creatinine Clearance (EstCrCl). EstCrCl can be computed with Jelliffe or Cockcroft-Gault formulas, or a measured value can be entered by the user. This MLM calculates one of the following combinations: - Ordered amounts per DOSE (and optionally Total Daily Dose) from Requested amount per Dose Basis per DOSE - Ordered amount per DOSE (and optionally Total Daily Dose) from Requested amount per Dose Basis per DAY - Actual amount per DOSE per Dose Basis (and optionally Total Daily Dose) from Ordered amount per DOSE - Actual amount per DAY per Dose Basis (and optionally Total Daily Dose) from Ordered amount per DOSE ;; explanation: This MLM is called from C++ code which passes in: - ht_val - height from order form or height/weight dialog in kilograms (kg) - wt_val - weight from order form or height/weight dialog in centimeters (cm) - BSA_val - BSA calculated by SYS_CALC_BSA based on height, weight, and formula - format_type - Either {{{SINGLE-QUOTE}}}Order{{{SINGLE-QUOTE}}} or {{{SINGLE-QUOTE}}}Additive{{{SINGLE-QUOTE}}}, used to prepare text for the CalcInfo field - calc_type - Indicates what field should be calculated - {{{SINGLE-QUOTE}}}Ordered{{{SINGLE-QUOTE}}} - tells MLM to use {{{SINGLE-QUOTE}}}requested_dose{{{SINGLE-QUOTE}}} to compute ordered amount per DOSE from requested per DOSE - {{{SINGLE-QUOTE}}}Actual{{{SINGLE-QUOTE}}} - tells MLM to use {{{SINGLE-QUOTE}}}dose{{{SINGLE-QUOTE}}} to compute actual amounts per DOSE from ordered per DOSE - {{{SINGLE-QUOTE}}}TotalOrdered - tells MLM to use {{{SINGLE-QUOTE}}}requested_dose{{{SINGLE-QUOTE}}} to compute ordered amount per DOSE from requested per DAY - {{{SINGLE-QUOTE}}}TotalActual - tells MLM to use {{{SINGLE-QUOTE}}}dose{{{SINGLE-QUOTE}}} to compute actual amounts per DAY from ordered per DOSE - calculating_total, - indicates if total daily dose should be calculated - TRUE = calculate total after checking for Frequency - FALSE = do not calculate total, Frequency can be NULL - dose - Dose entered by user into {{{SINGLE-QUOTE}}}Ordered{{{SINGLE-QUOTE}}} or {{{SINGLE-QUOTE}}}Requested{{{SINGLE-QUOTE}}} field to be used in Calculations - route - used by dose rounding mlm - frequency - Frequency entered by user to be used in calculations. Frequency is required for daily totals and for computing the ordered and actual amounts when the requested/ordered amount is entered in the daily dose dialog - dose_uom - Unit of measure for medication - dose_basis - Dose Basis as in per weight or BSA, or target AUC. Valid values include: kg kg (ideal) kg (adjusted) m2 m2 (ideal) m2 (adjusted) AUC (Cockcroft-Gault) AUC (Cockcroft-Gault ideal) AUC (Cockcroft-Gault adjusted) AUC (Jelliffe) AUC (Jelliffe ideal) AUC (Jelliffe adjusted) AUC (Jelliffe no BSA) AUC (measured CrCl) AUC (St. Jude{{{SINGLE-QUOTE}}}s Modified-Peds) Flat Dose - EstCrCl_equation_preference - from Creatinine Clearance control, or reset by mlm - serum_creatinine - from Creatinine Clearance control or database - creat_clearance - from Creatinine Clearance control or database, or computed by mlm - is_actual_CrCl - state of "Actual" button on Creatinine Clearance control - requested_dose - Original dose from {{{SINGLE-QUOTE}}}Requested{{{SINGLE-QUOTE}}} field is not used in the Calculations but is used in the CalcInfo string sent back - client_info_obj - Arden ClientInfo object - order_obj - Arden Order Object - weight_type - type of weight used in calculation: "Dry", "Pre-Dialysis" etc. - dose_cap - the maximum dose allowed for the order. From DoseCap field on the order form. - previous_ordered_dose - the "Ordered Amount Per Dose" from the previous call to the MLM. Is the {{{SINGLE-QUOTE}}}uncapped dose{{{SINGLE-QUOTE}}} when the DoseCap was exceeded. See current_order_dose variable definition in the RETURN section below. - override_flag - a flag indicating whether the Dose Calc UI is in the override state. - override_reason - if the override reason is entered, the text is sent to the MLM. and returns the following strings(note numbers cannot contain commas): - error string - containing an error message, if there is one, NULL if no error - new_dose - containing the ordered dose - dose_string - containing text for CalcInfo field - total_daily_dose - containing the daily dose total - actual_dose - contains the actual dose either per dose or per day - dose_basis_message - contains the message "based on BSA (ideal) of #.## m2" or other appropriate message. - current_ordered_dose - the {{{SINGLE-QUOTE}}}Ordered Amount Per Dose{{{SINGLE-QUOTE}}}. If the dose was reset due to exceeding the DoseCap limit, then the dose is the one BEFORE the reset. This value to resent as the {{{SINGLE-QUOTE}}}previous_ordered_dose{{{SINGLE-QUOTE}}} argument in the next call to the MLM. ;; keywords: Dosage Calculation ;; knowledge: type: data-driven;; data: /* Arguments are passed in as STRINGS from the calling C++ or .NET program */ (ht_val, wt_val, BSA_val, format_type, calc_type, calculating_total, dose, route, frequency, dose_uom, dose_basis, EstCrCl_equation_preference, serum_creatinine, creat_clearance, is_actual_CrCl, requested_dose, client_info_obj, order_obj, weight_type, dose_cap, previous_ordered_dose, override_flag, override_reason ) := argument; /*******************Make Changes To Spelling And Flags In This Section*******************/ /* Set to true if logging is needed.*/ log_execution_info := false; /* AUC dose basis strings are used in Area Under Curve dose calculation */ AUC_cg_string := ("AUC (Cockcroft-Gault)", "AUC (Cockcroft-Gault ideal)", "AUC (Cockcroft-Gault adjusted)"); AUC_jlf_string := ("AUC (Jelliffe)", "AUC (Jelliffe ideal)", "AUC (Jelliffe adjusted)", "AUC (Jelliffe no BSA)"); AUC_mCrCl_string := ("AUC (measured CrCl)", "AUC (St. Jude{{{SINGLE-QUOTE}}}s Modified-Peds)"); measured_string := "AUC (measured CrCl)"; AUC_strings := (AUC_cg_string, AUC_jlf_string, AUC_mCrCl_string); /* Used to check the dose basis string(xxx/kg or xxx/m2)from DoseCalcUOM field: */ /* KG means calculate using the weight, M2 means calculate using BSA. */ /* AUC means calculate using an Area Under the Curve formula involving weight or BSA. */ /* FLAT DOSE means do not calculate, return the same value the user entered. */ kg_string:= ("kg", "kg (ideal)","kg (adjusted)"); M2_string:= ("M2", "m2 (ideal)","m2 (adjusted)"); calc_wt_dose_basis_string:= ("kg (ideal)","kg (adjusted)","AUC (Cockcroft-Gault ideal)", "AUC (Cockcroft-Gault adjusted)"); calc_BSA_dose_basis_string:= ("m2 (ideal)","m2 (adjusted)","AUC (Jelliffe ideal)", "AUC (Jelliffe adjusted)", "AUC (St. Jude{{{SINGLE-QUOTE}}}s Modified-Peds)"); ideal_string := ("kg (ideal)","m2 (ideal)","AUC (Cockcroft-Gault ideal)", "AUC (Jelliffe ideal)"); adjusted_string := ("kg (adjusted)","m2 (adjusted)", "AUC (Cockcroft-Gault adjusted)", "AUC (Jelliffe adjusted)"); dose_basis_not_requiring_weight_string := ("Flat Dose", "AUC (measured CrCl)", "AUC (St. Jude{{{SINGLE-QUOTE}}}s Modified-Peds)"); flat_dose_string := "Flat Dose"; /* Used in the freetext message */ spacing_string:= " "; /* Error messages can be changed inside the quote marks. */ error_invalid_dose_basis := "Type of units in the {{{SINGLE-QUOTE}}}per{{{SINGLE-QUOTE}}} field cannot be used for dosage calculation. "; error_not_KG:= "Type of units in the {{{SINGLE-QUOTE}}}per{{{SINGLE-QUOTE}}} field is not Kg. "; error_missing_xxx_unit := "The units of measure (UOM) for the medication is missing " || "and is necessary to perform the calculation. "; error_missing_dose_basis := "The dose basis in the {{{SINGLE-QUOTE}}}per{{{SINGLE-QUOTE}}} for the medication is missing " || "and is necessary to perform the calculation. "; error_dose_calc:= "The dose amount must be entered to perform the calculation. "; error_dose_calc_invalid:= "Invalid entry in the dose field. Please enter a positive number. "; error_req_dose_calc_empty := "The requested dose is empty, please provide the value."; error_ordered_dose_calc_empty := "The ordered dose is empty, please provide the value."; error_invalid_weight:= "Weight must be entered to perform the calculation. "; error_invalid_height:= "Height must be entered to perform the calculation. "; error_missing_frequency:= "Frequency must be entered to perform the calculation. "; error_missing_lab_value := "Missing a Serum Creatinine or Creatinine Clearance " || "needed to determine AUC dose. "; error_wrong_type_lab_value := "Actual or Measured CrCl is required to determine AUC dose. "; error_ordered_dose_exceeds_four_decimals := "The {{{SINGLE-QUOTE}}}Ordered Amount Per Dose{{{SINGLE-QUOTE}}} cannot exceed four decimals. "; /***************************************************************************************/ /* Declares a C function that prevents the display of a number in scientific notation */ convert_big_num := interface {char* msvcrt:_itoa(long, char*, long)}; /* MLM to get the ideal or adjusted weight. */ func_calc_weight := MLM {{{SINGLE-QUOTE}}}SYS_CALC_WT{{{SINGLE-QUOTE}}}; /* MLM to get the ideal or adjusted BSA. */ func_calc_BSA := MLM {{{SINGLE-QUOTE}}}SYS_CALC_BSA{{{SINGLE-QUOTE}}}; /* MLM to calculate the Area Under the Curve dose */ func_calc_AUC_coef := MLM {{{SINGLE-QUOTE}}}SYS_CALC_AUC_COEF{{{SINGLE-QUOTE}}}; /* MLM to get the number of occurrences in a day for the specified frequency. */ func_calc_frequency_multiplier := MLM {{{SINGLE-QUOTE}}}SYS_CALC_FREQMULT_DAILY{{{SINGLE-QUOTE}}}; /* MLM to apply consistent rounding rules to dosages. */ func_round_dosage := MLM {{{SINGLE-QUOTE}}}SYS_ROUND_DOSAGE{{{SINGLE-QUOTE}}}; /* Declare function MLM for adding commas into numbers */ add_commas := MLM {{{SINGLE-QUOTE}}}SYS_FORMAT_NUMBER{{{SINGLE-QUOTE}}}; ;; evoke: ;; logic: /*---------------------------------------------------------------*/ /* Saves the Values of the Arguments BEFORE any code resets them */ /*---------------------------------------------------------------*/ // Only saves values that are NOT objects. ht_val_saved_arg := ht_val ; wt_val_saved_arg := wt_val ; BSA_val_saved_arg := BSA_val ; format_type_saved_arg := format_type ; calc_type_saved_arg := calc_type ; calculating_total_saved_arg := calculating_total ; dose_saved_arg := dose ; route_saved_arg := route ; frequency_saved_arg := frequency ; dose_uom_saved_arg := dose_uom ; dose_basis_saved_arg := dose_basis ; EstCrCl_equation_preference_saved_arg := EstCrCl_equation_preference ; serum_creatinine_saved_arg := serum_creatinine ; creat_clearance_saved_arg := creat_clearance ; is_actual_CrCl_saved_arg := is_actual_CrCl ; requested_dose_saved_arg := requested_dose ; weight_type_saved_arg := weight_type ; dose_cap_saved_arg := dose_cap ; previous_ordered_dose_saved_arg := previous_ordered_dose ; override_flag_saved_arg := override_flag ; override_reason_saved_arg := override_reason ; /*--------------------------------------------------------------------*/ /* Avoid errors by converting an empty list to NULL before processing */ /*--------------------------------------------------------------------*/ if not exist ht_val and ht_val is list then ht_val := null; endif; if not exist wt_val and wt_val is list then wt_val := null; endif; if not exist BSA_val and BSA_val is list then BSA_val := null; endif; if not exist format_type and format_type is list then format_type := null; endif; if not exist calc_type and calc_type is list then calc_type := null; endif; if not exist dose and dose is list then dose := null; endif; if not exist route and route is list then route := null; endif; if not exist frequency and frequency is list then frequency := null; endif; if not exist dose_uom and dose_uom is list then dose_uom := null; endif; if not exist dose_basis and dose_basis is list then dose_basis := null; endif; if not exist EstCrCl_equation_preference and EstCrCl_equation_preference is list then EstCrCl_equation_preference := null; endif; if not exist serum_creatinine and serum_creatinine is list then serum_creatinine := null; endif; if not exist serum_creatinine_uom and serum_creatinine_uom is list then serum_creatinine_uom := null; endif; if not exist creat_clearance and creat_clearance is list then creat_clearance := null; endif; if not exist is_actual_CrCl and is_actual_CrCl is list then is_actual_CrCl := null; endif; if not exist requested_dose and requested_dose is list then requested_dose := null; endif; if not exist dose_cap and dose_cap is list then dose_cap := null; endif; if not exist previous_ordered_dose and previous_ordered_dose is list then previous_ordered_dose := null; endif; if not exist override_flag and override_flag is list then override_flag := null; endif; if not exist override_reason and override_reason is list then override_reason := null; endif; /*-----------------------------------------------------------------------------*/ /* Avoid errors by converting an empty string or "0" to NULL before processing */ /*-----------------------------------------------------------------------------*/ if exist ht_val and (ht_val = "" or ht_val = "0") then ht_val := null; endif; if exist wt_val and (wt_val = "" or wt_val = "0") then wt_val := null; endif; if exist BSA_val and (BSA_val = "" or BSA_val = "0") then BSA_val := null; endif; if exist format_type and format_type = "" then format_type := null; endif; if exist calc_type and calc_type = "" then calc_type := null; endif; if exist dose and (dose = "" or dose = "0") then dose := null; endif; if exist route and route = "" then route := null; endif; if exist frequency and frequency = "" then frequency := null; endif; if exist dose_uom and dose_uom = "" then dose_uom := null; endif; if exist dose_basis and dose_basis = "" then dose_basis := null; endif; if exist EstCrCl_equation_preference and EstCrCl_equation_preference = "" then EstCrCl_equation_preference := null; endif; if exist serum_creatinine and (serum_creatinine = "" or serum_creatinine = "0") then serum_creatinine := null; endif; if exist serum_creatinine_uom and serum_creatinine_uom = "" then serum_creatinine_uom := null; endif; if exist creat_clearance and (creat_clearance = "" or creat_clearance = "0") then creat_clearance := null; endif; if exist requested_dose and requested_dose = "" then requested_dose := null; endif; //Only convert "" to null for dose_cap. The "0" is a valid entry. if exist dose_cap and dose_cap = "" then dose_cap := null; endif; if exist previous_ordered_dose and (previous_ordered_dose = "" or ((previous_ordered_dose AS Number) = 0)) then previous_ordered_dose := null; endif; if exist override_flag and override_flag = "" then override_flag := null; endif; if exist override_reason and override_reason = "" then override_reason := null; endif; /*----------------------------------------------------------------*/ /* Convert a string representation of a number to an Arden number */ /*----------------------------------------------------------------*/ ht_val := ht_val as number; wt_val := wt_val as number; BSA_val := BSA_val as number; dose := dose as number; serum_creatinine := serum_creatinine as number; creat_clearance := creat_clearance as number; dose_cap := dose_cap as number; previous_ordered_dose := previous_ordered_dose as number; requested_dose := requested_dose as number; /*----------------------------------------------*/ /* Copy data originally passed in as arguments */ /*----------------------------------------------*/ // The following data were passed as arguments to the MLM // and then converted from a string to a number. // The data can be changed by the MLM // So their values are copied to another variable. wt_val_original := wt_val; //Modified by AUC calcs dose_original := dose; //Modified by Dose Cap calcs /*----------------------*/ /* Initialize Variables */ /*----------------------*/ exceeded_dose_cap := false; /*------------------*/ /* Check for Errors */ /*------------------*/ error_message:= ""; fatal_error:= false; minor_error:= false; /* DOSE PER UNITS UOM IS NOT KG or M2 or AUC or Flat Dose */ if dose_basis is not in (kg_string, M2_string, AUC_strings, flat_dose_string ) then error_message:= error_message || error_invalid_dose_basis; fatal_error:= true; endif; /* MEDICATION UOM IS MISSING xxx (xxx/KG or xxx/M2) */ if not exist dose_uom then error_message:= error_message || error_missing_xxx_unit ; fatal_error:= true; endif; /* MEDICATION DOSE BASIS IS MISSING */ if not exist dose_basis then error_message:= error_message || error_missing_dose_basis ; fatal_error:= true; endif; /* DOSE IS REQUIRED and MUST BE GREATER THAN ZERO*/ if dose is not number then if calc_type is in ( "Actual", "TotalActual" ) then error_message:= error_message || error_ordered_dose_calc_empty; else error_message:= error_message || error_req_dose_calc_empty; endif; fatal_error:= true; elseif dose < 0 then error_message:= error_message || error_dose_calc_invalid; fatal_error:= true; endif; if dose = 0 then error_message:= error_message || error_dose_calc; fatal_error:= true; endif; /* WEIGHT IS REQUIRED - except when using ideal weights or flat dose */ if (wt_val is not number OR wt_val <= 0) AND dose_basis is not in ideal_string AND dose_basis is not in measured_string AND dose_basis <> flat_dose_string then error_message:= error_message || error_invalid_weight; fatal_error:= true; endif; /* HEIGHT IS REQUIRED--when BSA dosing is requested with M2 uom or when using ideal weights */ if (dose_basis is in M2_string OR dose_basis is in ideal_string OR dose_basis is in adjusted_string) and (ht_val is not number OR ht_val <=0 ) then error_message:= error_message || error_invalid_height; fatal_error:= true; endif; /* FREQUENCY IS REQUIRED--when calculating total daily or ordered from requested daily*/ if (calculating_total = "TRUE" OR calc_type = "TotalOrdered" OR calc_type = "TotalActual") AND not exist frequency then error_message:= error_message || error_missing_frequency; fatal_error:= true; endif; /* LAB VALUE IS REQUIRED - Serum Creatinine or Creatinine Clearance */ /* must exist for AUC dose calcs */ if dose_basis is in AUC_strings then if (((not exist serum_creatinine) or (serum_creatinine <= 0)) and ((not exist creat_clearance) or (creat_clearance <= 0))) then error_message := error_message || error_missing_lab_value; fatal_error:= true; elseif (dose_basis is in AUC_mCrCl_string) and (is_Actual_CrCl = false) then error_message := error_message || error_wrong_type_lab_value; fatal_error:= true; endif; endif; /* {{{SINGLE-QUOTE}}}ORDERED AMOUNT PER DOSE{{{SINGLE-QUOTE}}} EXCEEDED FOUR DECIMALS-- when user enters the value in this field */ if calc_type is in ("Actual", "TotalActual") and dose is number then // Format the dose to eliminate Scientific Notation result := dose formatted with "%.10f"; // Extract the digits and characters into a list chars := extract characters result; // Loop through chars, and determine if there are trailing zeros trailing_pos := 0; found_trailing := false; found_decimal := false; pos := 0; for ch in chars do if (ch = ".") then found_decimal := true; found_trailing := true; trailing_pos := pos; elseif (ch = "0") and (found_decimal = true) and (found_trailing = false) then found_trailing := true; trailing_pos := pos; elseif (ch <> "0") and (found_trailing = true) then found_trailing := false; endif; pos := pos + 1; enddo; //for ch // Remove the Trailing Zeros in the decimals if found_trailing then result := string (first trailing_pos from chars); endif; //Count the number of decimals by looping through the characters number_of_decimals := 0; located_decimal := false; character_list := extract characters result; for CCC in character_list do if (CCC = ".") then located_decimal := true; elseif located_decimal then number_of_decimals := number_of_decimals + 1; endif; enddo; //for CCC // Generate error if more than 4 decimals if located_decimal and number_of_decimals > 4 then error_message:= error_message || error_ordered_dose_exceeds_four_decimals; fatal_error:= true; endif; endif; //if calc_type is in ("Actual", "TotalActual") /* Only calculate dosage when there is no error */ if NOT fatal_error then /*-----------------------------------------------------------*/ /* Calculate Weight to use when Ideal or Adjusted weight */ /* is needed and formulate the dose basis message */ /*-----------------------------------------------------------*/ if dose_basis is in calc_wt_dose_basis_string and exist ht_val and ht_val > 0 then if dose_basis = "kg (ideal)" OR dose_basis = "AUC (Cockcroft-Gault ideal)" then (wt_val, Tooltip_formula, display_message) := call func_calc_weight with "Ideal", ht_val, wt_val, client_info_obj; if exist wt_val and wt_val > 0 then dose_basis_message := "based on kg (ideal) of "|| wt_val; else error_message := "Dosage cannot be calculated with kg (ideal) " || "unless Ideal weight has been calculated."; fatal_error := TRUE; endif; // if exist wt_val and wt_val > 0 elseif dose_basis = "kg (adjusted)" OR dose_basis = "AUC (Cockcroft-Gault adjusted)" and exist wt_val and wt_val > 0 then (wt_val, Tooltip_formula, display_message) := call func_calc_weight with "Adjusted", ht_val, wt_val, client_info_obj; if exist wt_val and wt_val > 0 then dose_basis_message := "based on kg (adjusted) of "|| wt_val; else error_message := "Dosage cannot be calculated with kg (adjusted) " || "unless Adjusted weight has been calculated."; fatal_error := TRUE; endif; // if exist wt_val and wt_val > 0 endif; // if dose_basis is kg (ideal) or kg (adjusted) /*-----------------------------------------------------------*/ /* Calculate BSA to use when Ideal or Adjusted BSA */ /* is needed and formulate the dose basis message */ /*-----------------------------------------------------------*/ elseif dose_basis is in calc_BSA_dose_basis_string and exist ht_val and ht_val > 0 then if dose_basis = "m2 (ideal)" OR dose_basis = "AUC (Jelliffe ideal)" then (BSA_val, BSA_formula, wt_used) := call func_calc_BSA with "Ideal", ht_val, wt_val, client_info_obj; if exist BSA_val and BSA_val > 0 then dose_basis_message := "based on BSA (ideal) of "|| BSA_val ||" m2"; else error_message := "Dosage cannot be calculated with m2 (ideal) " || "unless Ideal weight has been calculated."; fatal_error := TRUE; endif; // if exist BSA_val and BSA_val > 0 elseif dose_basis = "m2 (adjusted)" OR dose_basis = "AUC (Jelliffe adjusted)" and exist wt_val and wt_val > 0 then (BSA_val, BSA_formula, wt_used) := call func_calc_BSA with "Adjusted", ht_val, wt_val, client_info_obj; if exist BSA_val and BSA_val > 0 then dose_basis_message := "based on BSA (adjusted) of "|| BSA_val ||" m2"; else error_message := "Dosage cannot be calculated with m2 (adjusted) " || "unless Adjusted weight has been calculated."; fatal_error := TRUE; endif; // if exist BSA_val and BSA_val > 0 endif; // dose_basis is BSA ideal or adjusted elseif dose_basis = flat_dose_string then dose_basis_message := "based on Flat Dose"; else dose_basis_message := "based on actual measurements"; endif; //if dose_basis in calc_wt_dose_basis_string /*--------------------------------------------------*/ /* Add weight type to dose basis message, if needed */ /*--------------------------------------------------*/ if wt_val > 0 AND dose_basis is not in ideal_string AND dose_basis is not in measured_string AND dose_basis <> flat_dose_string AND (weight_type <> "Weight") then dose_basis_message := dose_basis_message || " using weight of type " || weight_type || ". "; endif; /*-----------------------------------------*/ /* Calculate Multiple to use for Frequency */ /*-----------------------------------------*/ if exist frequency then daily_dose_multiplier := call func_calc_frequency_multiplier with (frequency); endif; /*-----------------------------------------*/ /* Determine if Dose Cap should be checked */ /*-----------------------------------------*/ //Rule 1-- General Rule of Thumb if exist dose_cap and format_type = "Order" then check_dose_cap := true; else check_dose_cap := false; endif; //Rule 2 -- Override Exception if override_flag and format_type = "Order" and calc_type is in ( "Actual", "TotalActual" ) and exist dose_cap and previous_ordered_dose > dose_cap then check_dose_cap := false; endif; /*-------------------------------------*/ /* Calculate dose for AUC dose basis */ /*-------------------------------------*/ if dose_basis is in AUC_strings and ((exist serum_creatinine and serum_creatinine > 0 ) or (exist creat_clearance and creat_clearance > 0 )) then (AUC_calc_error_message, AUC_coef, AUC_dose_calc_formula) := call func_calc_AUC_coef with ht_val, wt_val_original, BSA_val, dose, dose_basis, serum_creatinine, creat_clearance, is_actual_CrCl, client_info_obj; if not (exist AUC_coef and AUC_coef > 0) // only continue if no error then error_message := AUC_calc_error_message; fatal_error := true; else if calc_type = "Ordered" then temp_dose := AUC_coef * dose; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap/AUC_coef; actual_dose := dose_cap/AUC_coef; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "Actual" then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_dose := dose_cap / AUC_coef; else actual_dose := dose / AUC_coef; endif; // check dose_cap elseif calc_type = "TotalOrdered" and exist daily_dose_multiplier then temp_dose:= (dose * AUC_coef)/daily_dose_multiplier; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := (dose_cap * daily_dose_multiplier)/ AUC_coef; actual_dose := (dose_cap * daily_dose_multiplier)/ AUC_coef; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "TotalActual" and exist daily_dose_multiplier then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_single_dose := dose_cap / AUC_coef; else actual_single_dose := dose / AUC_coef; endif; // check dose_cap actual_dose := actual_single_dose * daily_dose_multiplier; endif; //if calc_type endif; // exist AUC_coef endif; // dose_basis is in AUC_strings /*-----------------------*/ /* Calculate Dose by BSA */ /*-----------------------*/ if dose_basis is in M2_string and exist dose_uom and exist BSA_val and BSA_val > 0 and dose > 0 then if calc_type = "Ordered" then temp_dose := BSA_val * dose; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap/BSA_val; actual_dose := dose_cap/BSA_val; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "Actual" then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_dose := dose_cap / BSA_val; else actual_dose := dose / BSA_val; endif; // check dose_cap elseif calc_type = "TotalOrdered" and exist daily_dose_multiplier then temp_dose:= (dose * BSA_val)/daily_dose_multiplier; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := (dose_cap * daily_dose_multiplier)/ BSA_val; actual_dose := (dose_cap * daily_dose_multiplier)/ BSA_val; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "TotalActual" and exist daily_dose_multiplier then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_single_dose := dose_cap / BSA_val; else actual_single_dose := dose / BSA_val; endif; // check dose_cap actual_dose := actual_single_dose * daily_dose_multiplier; endif; //if calc_type endif; /* if dose_basis = M2_string */ /*--------------------------*/ /* Calculate Dose by WEIGHT */ /*--------------------------*/ if dose_basis is in kg_string and exist wt_val and exist dose_uom and exist dose and wt_val > 0 and dose > 0 then if calc_type = "Ordered" then temp_dose := wt_val * dose; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap/wt_val; actual_dose := dose_cap/wt_val; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "Actual" then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_dose := dose_cap / wt_val; else actual_dose := dose / wt_val; endif; // check dose_cap elseif calc_type = "TotalOrdered" and exist daily_dose_multiplier then temp_dose:= (dose * wt_val)/daily_dose_multiplier; actual_dose := dose; (rounding_error_message, new_dose):= call func_round_dosage with (temp_dose, route ); if new_dose is null then error_message := rounding_error_message; fatal_error := true; elseif (new_dose is not null) and (rounding_error_message is not null) then error_message := rounding_error_message; minor_error := true; else current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := (dose_cap * daily_dose_multiplier)/ wt_val; actual_dose := (dose_cap * daily_dose_multiplier)/ wt_val; endif; // check dose_cap endif; // new_dose is null elseif calc_type = "TotalActual" and exist daily_dose_multiplier then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_single_dose := dose_cap / wt_val; else actual_single_dose := dose / wt_val; endif; // check dose_cap actual_dose := actual_single_dose * daily_dose_multiplier; endif; //if calc_type endif; /* if dose_basis = kg_string */ /*-----------------------------*/ /* Calculate Dose by FLAT DOSE */ /*-----------------------------*/ if dose_basis = flat_dose_string and exist dose_uom and exist dose and dose > 0 then if calc_type = "Ordered" then new_dose := dose; current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_dose := dose_cap; else actual_dose := dose; endif; // check dose_cap elseif calc_type = "Actual" then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_dose := dose_cap; else actual_dose := dose; endif; // check dose_cap elseif calc_type = "TotalOrdered" and exist daily_dose_multiplier then new_dose := dose / daily_dose_multiplier; current_ordered_dose := new_dose ; if check_dose_cap and new_dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap * daily_dose_multiplier; actual_dose := dose_cap * daily_dose_multiplier; else actual_dose := dose; endif; // check dose_cap elseif calc_type = "TotalActual" and exist daily_dose_multiplier then current_ordered_dose := dose ; if check_dose_cap and dose > dose_cap then exceeded_dose_cap := true; new_dose := dose_cap; dose := dose_cap; actual_single_dose := dose_cap; else actual_single_dose := dose; endif; // check dose_cap actual_dose := actual_single_dose * daily_dose_multiplier; endif; //if calc_type endif; /* if dose_basis = flat_dose_string */ /*---------------------------------*/ /* Calculate the Total Daily Dose */ /*---------------------------------*/ if calculating_total = "TRUE" then if exist daily_dose_multiplier then if calc_type = "Ordered" then total_daily_dose:= new_dose * daily_dose_multiplier ; elseif calc_type = "Actual" then total_daily_dose:= dose * daily_dose_multiplier ; elseif calc_type = "TotalOrdered" then total_daily_dose:= new_dose * daily_dose_multiplier; elseif calc_type = "TotalActual" then total_daily_dose:= dose * daily_dose_multiplier ; endif; endif; endif; /* if calculating total */ /*----------------------------*/ /* Convert Numbers to Strings */ /* Convert NULL to "" */ /*----------------------------*/ // This conversion is done to: // (1) format the number for printing purposes, and // (2) convert any numeric values to strings before they are returned to the calling program. // The Sunrise application is expecting strings to be returned. // An assertion or error will occur if a number is returned. // After the string conversion, any numeric comparisons with these variables // will require an AS NUMBER conversion. if exist dose then if dose > 999999 then formatted_dose := call add_commas with (dose); dose:= call convert_big_num with (dose, "", 10); elseif dose < 1 then dose:= dose formatted with "%g"; formatted_dose := dose; else formatted_dose := call add_commas with (dose); dose := dose as string; endif; else dose := ""; endif; if exist new_dose then if new_dose > 0 and dose_basis = flat_dose_string then //Avoids exceeding 4 decimal points formatted_new_dose := call add_commas with (new_dose); new_dose := ((new_dose formatted with "%.4f") AS NUMBER) AS STRING; elseif new_dose > 999999 then formatted_new_dose := call add_commas with (new_dose); new_dose:= call convert_big_num with (new_dose, "", 10); elseif new_dose < 1 then new_dose:= new_dose formatted with "%g"; formatted_new_dose := new_dose; else formatted_new_dose := call add_commas with (new_dose); new_dose := new_dose as string; endif; else new_dose := ""; endif; if exist actual_dose then if (calc_type = "TotalOrdered" or calc_type = "Ordered") and NOT exceeded_dose_cap then actual_dose := actual_dose as string; else if actual_dose > 999999 then formatted_actual_dose := call add_commas with (actual_dose); actual_dose := actual_dose formatted with "%f"; elseif actual_dose < 0.01 then temp_actual_dose := (actual_dose formatted with "%f") AS NUMBER; formatted_actual_dose := call add_commas with (temp_actual_dose); actual_dose:= actual_dose formatted with "%f"; elseif actual_dose < 1 then temp_actual_dose := (actual_dose formatted with "%.4f") AS NUMBER; formatted_actual_dose := call add_commas with (temp_actual_dose); actual_dose:= actual_dose formatted with "%.4f"; else temp_actual_dose := (actual_dose formatted with "%.4f") AS NUMBER; formatted_actual_dose := call add_commas with (temp_actual_dose); actual_dose := actual_dose formatted with "%.4f"; endif; endif; else actual_dose := ""; endif; if exist total_daily_dose then if total_daily_dose > 999999 then formatted_total_daily_dose := call add_commas with (total_daily_dose); total_daily_dose:= call convert_big_num with (total_daily_dose, "", 10); elseif total_daily_dose < 1 then total_daily_dose:= total_daily_dose formatted with "%g"; formatted_total_daily_dose := total_daily_dose; else formatted_total_daily_dose := call add_commas with (total_daily_dose); total_daily_dose:= total_daily_dose as string ; endif; else total_daily_dose := ""; endif; if exist current_ordered_dose then if current_ordered_dose > 999999 then formatted_current_ordered_dose := call add_commas with (current_ordered_dose); current_ordered_dose:= call convert_big_num with (current_ordered_dose, "", 10); elseif current_ordered_dose < 1 then current_ordered_dose:= current_ordered_dose formatted with "%g"; formatted_current_ordered_dose:= current_ordered_dose; else formatted_current_ordered_dose := call add_commas with (current_ordered_dose); current_ordered_dose := current_ordered_dose as string; endif; else current_ordered_dose := ""; endif; formatted_requested_dose := call add_commas with (requested_dose); formatted_dose_cap := call add_commas with (dose_cap); //------------------------------------------- // Trim Trailing Zeroes from Dosage Strings //------------------------------------------- // Append the dosage strings that need zeroes trimmed into a list dosage_list := dose, new_dose, actual_dose, total_daily_dose, current_ordered_dose; // Initialize a list to append the formatted numbers formatted_number_list := (); // Process the dosage string list to trim the trailing zeroes for one_dose in dosage_list do // Convert the dosage string to a number temp_dose_number := one_dose AS NUMBER; if temp_dose_number is not number then // Append the value to the list with out processing for trailing zeroes formatted_number_list := formatted_number_list, one_dose; else // Format the dose to eliminate Scientific Notation formatted_number := temp_dose_number formatted with "%.10f"; // Extract the digits and characters into a list chars_list := extract characters formatted_number; // Loop through chars_list, and determine if there are trailing zeros trailing_position := 0; found_trailing_zero := false; found_decimal_point := false; character_index := 0; for one_char in chars_list do if (one_char = ".") then found_decimal_point := true; found_trailing_zero := true; trailing_position := character_index; elseif (one_char = "0") and (found_decimal_point = true) and (found_trailing_zero = false) then found_trailing_zero := true; trailing_position := character_index; elseif (one_char <> "0") and (found_trailing_zero = true) then found_trailing_zero := false; endif; character_index := character_index + 1; enddo; //for one_char // Remove the Trailing Zeros in the decimals if found_trailing_zero then // Trim the number and put it on the list of formatted number formatted_number := string (first trailing_position from chars_list); formatted_number_list := formatted_number_list, formatted_number ; else //Put the original untrimmed number on the list of formatted number formatted_number_list := formatted_number_list, one_dose; endif; //if found_trailing_zero endif; //if temp_dose_number is not number enddo; //for one_dose // Loop through and reset the dosage strings after trimming the trailing zeroes // Reset the values using the same variables and same index order // that was used to set the dosage_list for JJ in (1 seqto (count formatted_number_list)) do if JJ = 1 then dose := formatted_number_list[JJ]; elseif JJ = 2 then new_dose := formatted_number_list[JJ]; elseif JJ = 3 then actual_dose := formatted_number_list[JJ]; elseif JJ = 4 then total_daily_dose := formatted_number_list[JJ]; elseif JJ = 5 then current_ordered_dose := formatted_number_list[JJ]; endif; //if JJ enddo; //for JJ /*---------------------------------------*/ /* Format Dose String for CalcInfo field */ /*---------------------------------------*/ /* Initialize dose_string */ if not exist dose_string then dose_string := ""; endif; /* Set dose_basis_cut and dose_basis_final for AUC */ if dose_basis is in AUC_strings then dose_basis_cut := "AUC"; if dose_basis = "AUC (Cockcroft-Gault)" then dose_basis_final := "AUC(C-G)"; elseif dose_basis = "AUC (Cockcroft-Gault ideal)" then dose_basis_final := "AUC(C-G ideal)"; elseif dose_basis = "AUC (Cockcroft-Gault adjusted)" then dose_basis_final := "AUC(C-G adjusted)"; elseif dose_basis = "AUC (Jelliffe)" then dose_basis_final := "AUC(Jelliffe)"; elseif dose_basis = "AUC (Jelliffe ideal)" then dose_basis_final := "AUC(Jelliffe ideal)"; elseif dose_basis = "AUC (Jelliffe adjusted)" then dose_basis_final := "AUC(Jelliffe adjusted)"; elseif dose_basis = "AUC (Jelliffe no BSA)" then dose_basis_final := "AUC(Jelliffe noBSA)"; elseif dose_basis = "AUC (measured CrCl)" then dose_basis_final := "AUC(measured CrCl)"; elseif dose_basis = "AUC (St. Jude{{{SINGLE-QUOTE}}}s Modified-Peds)" then dose_basis_final := "AUC(St. Jude{{{SINGLE-QUOTE}}}s)"; endif; else dose_basis_cut := dose_basis; endif; /* format_type can be "Order" or "Additive" */ if format_type = "Additive" then dose_string:= "[Calculation: " ; else dose_string:= ""; endif; if calc_type = "Ordered" or calc_type = "TotalOrdered" then dose_string:= dose_string || formatted_dose; elseif calc_type = "Actual" or calc_type = "TotalActual" then dose_string:= dose_string || formatted_actual_dose; endif; if calc_type = "Ordered" or calc_type = "Actual" then if dose_basis = flat_dose_string then dose_string:= dose_string || " " || dose_uom || "/DOSE"|| " x "; else dose_string:= dose_string || " " || dose_uom || "/" || dose_basis_cut || "/DOSE" || " x "; endif; else /* calc_type = "TotalOrdered" or "TotalActual" */ if dose_basis = flat_dose_string then dose_string:= dose_string || " " || dose_uom || "/DAY"|| " x "; else dose_string:= dose_string || " " || dose_uom || "/" || dose_basis_cut || "/DAY"|| " x "; endif; endif; //if calc_type = "Ordered" or calc_type = "Actual" if dose_basis is in M2_string then dose_string:= dose_string || BSA_val || " " || dose_basis_cut; elseif dose_basis is in kg_string then dose_string:= dose_string || wt_val || " " || dose_basis_cut; elseif dose_basis is in AUC_strings then dose_string:= dose_string || AUC_coef || " " || dose_basis_cut; elseif dose_basis = flat_dose_string then dose_string:= dose_string || "1 " ; else dose_string:= null; endif; if calc_type = "Ordered" or calc_type = "Actual" then dose_string:= dose_string || " = "; else dose_string:= dose_string || " "|| frequency || " = "; endif; if calc_type = "Ordered" or calc_type = "TotalOrdered" then dose_string:= dose_string || formatted_new_dose; else /* calc_type = "Actual" or "TotalActual" */ dose_string:= dose_string || formatted_dose; endif; dose_string:= dose_string || " " || dose_uom || "/Dose"; if exist requested_dose then if calc_type = "Actual" then dose_string:= dose_string || spacing_string || "(Requested dose was " || formatted_requested_dose || " " || dose_uom || " per " || dose_basis_cut || ")"; endif; /* CR 4028 for totalordered type calculation, need to display requested dose in calc info string returned */ if calc_type = "Ordered" then dose_string:= dose_string || spacing_string || "(Requested dose was " || formatted_requested_dose || " " || dose_uom || " per " || dose_basis_cut || ")"; endif; if calc_type = "TotalActual" then dose_string:= dose_string || spacing_string || "(Requested Daily amount was " || formatted_requested_dose || " " || dose_uom || " per " || dose_basis_cut || ")"; endif; /* CR 4028 for totalordered type calculation, need to display requested dose in calc info string returned */ if calc_type = "TotalOrdered" then dose_string:= dose_string || spacing_string || "(Requested Daily amount was " || formatted_requested_dose || " " || dose_uom || " per " || dose_basis_cut || ")"; endif; endif; /* if exist requested_dose*/ /* Only an Order should have a Daily Total */ if total_daily_dose <> "" and format_type = "Order" then dose_string:= dose_string || spacing_string || "(Daily Total is " || formatted_total_daily_dose || " " || dose_uom || ")"; endif; /* if exist total_daily_dose */ if dose_basis is in AUC_strings then dose_string := dose_string || " " || dose_basis_final || " " || AUC_dose_calc_formula; endif; if wt_val > 0 AND dose_basis is not in ideal_string AND dose_basis is not in measured_string AND dose_basis <> flat_dose_string AND (weight_type <> "Weight") then dose_string := dose_string || " Weight type: " || weight_type; endif; if format_type = "Additive" then dose_string:= dose_string || "]" ; endif; /*-------------------------------------------------*/ /* Modify Messages When Dose Cap Has been Exceeded */ /*-------------------------------------------------*/ if exceeded_dose_cap then minor_error := true; error_message := "The " ||formatted_current_ordered_dose || " " || dose_uom || " dose you requested exceeded the DOSAGE CAP of " || formatted_dose_cap ||" " || dose_uom || ". " || "The amount of the dose was reset to the DOSAGE CAP. " || "To override from the Dose Calculation dialog, " || "reenter the dose in the {{{SINGLE-QUOTE}}}Ordered Amount Per Dose{{{SINGLE-QUOTE}}} field. " || "If necessary, enter an override reason. " || "To override from the Order Form, reenter the dose in the dosage field."; dose_basis_message := "based on Dose Cap"; dose_string:= "DOSE CAP limits dose to " || dose_string ; endif; //if exceeded_dose_cap if Not check_dose_cap and ((current_ordered_dose AS NUMBER) > dose_cap ) and format_type = "Order" then dose_string:= "DOSE CAP limit exceeded. " || dose_string ; endif; //if Not check_dose_cap endif; /* if NOT fatal_error */ /*---------------*/ /* Clinical Rule */ /*---------------*/ /* Always conclude true to return calculated values or the error message */ conclude true; ;; action: /* Returns an error message, if there is one */ /* Otherwise, the calculations are returned as STRING values */ if fatal_error then return error_message; elseif minor_error then return ( error_message, new_dose, dose_string, total_daily_dose, actual_dose, dose_basis_message, current_ordered_dose ) ; else return ( "", new_dose, dose_string, total_daily_dose, actual_dose, dose_basis_message, current_ordered_dose ) ; endif; ;; end: