Files
St.Clair/MLMStripper/bin/Debug/STD/STD_FUNC_DOSAGE_ADMIN_TIMES.mlm

551 lines
20 KiB
Plaintext

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