maintenance: title: Calculates the stop date/time for an order;; mlmname: STD_FUNC_DOSAGE_CALC_STOPDTM;; arden: version 2.5;; version: 18.4;; institution: Allscripts, Standard MLM;; author: Allscripts Healthcare Solutions, Inc.;; specialist: ;; date: 2018-10-26;; validation: testing;; /* P r o p r i e t a r y N o t i c e */ /* Unpublished (c) 2013 - 2018 Allscripts Healthcare, LLC. and/or its affiliates. All Rights Reserved. P r o p r i e t a r y N o t i c e: This software has been provided pursuant to a License Agreement, with Allscripts Healthcare, LLC. and/or its affiliates, containing restrictions on its use. This software contains valuable trade secrets and proprietary information of Allscripts Healthcare, LLC. and/or its affiliates and is protected by trade secret and copyright law. This software may not be copied or distributed in any form or medium, disclosed to any third parties, or used in any manner not provided for in said License Agreement except with prior written authorization from Allscripts Healthcare, LLC. and/or its affiliates. Notice to U.S. Government Users: This software is {{{SINGLE-QUOTE}}}Commercial Computer Software{{{SINGLE-QUOTE}}}. All product names are the trademarks or registered trademarks of Allscripts Healthcare, LLC. and/or its affiliates. */ /* P r o p r i e t a r y N o t i c e */ library: purpose: Calculates the stop date for an order that does not have one. ;; explanation: This MLM will calculate the StopDtm for an order based on information in the orders{{{SINGLE-QUOTE}}}s frequency. Stop After (except for Stop after X Times) Daily, Weekly, Irregular Every M to N UNITS QnH and QnM templates Standard Frequencies without a stop after Every N UNITS Every M to N UNITS N Times per UNIT Does not work for orders that are or when there is no Stop After or Frequency configured. ;; keywords: single dose; average daily dose; total daily dose; dosage range ;; knowledge: type: data-driven;; data: // Set to true if logging is needed. log_execution_info := false; // Declare C functions to parse the frequency string func_get_token := interface {char* msvcrt:strtok(char*, char*)}; func_get_str := interface {char* msvcrt:strstr(char*, char*)}; // The facility must map its Dictionary Codes to the Core UOM in the // Units of Measure Dictionary. The MLM converts the facility-defined units of measure // to the system-defined values in the Unit of Measure Dictionary called CoreUOM. DAY_STRING := "day"; HOUR_STRING := "hr"; MINUTE_STRING := "min"; MONTH_STRING := "month"; SECOND_STRING := "s"; WEEK_STRING := "week"; YEAR_STRING := "year"; // Frequency Types NONE := 0; N_TIMES_PER_UNIT := 1; EVERY_N_UNITS := 2; EVERY_X_TO_Y_UNITS := 3; STOP_AFTER_DAYS := 1; STOP_AFTER_HOURS := 2; STOP_AFTER_MINUTES := 3; STOP_AFTER_TIMES := 4; // Parameter list ( FrequencyCode, StartDtm, FreqUOM, FreqFromTime, FreqToTime, StopAfterValue, StopAfterOption, TaskSchedObj ) := ARGUMENT; //---------------------------------------------------------- // Load some data first based on the freqency type //---------------------------------------------------------- // If Irregular, need to retrieve and sort the list of Scheduled Times. if FrequencyCode = "" then if FreqUom is NULL // = "Irregular" then ScheduledDtmList := read { TaskScheduleDefinition: ScheduledDtm referencing TaskSchedObj }; ScheduledDtmList := sort data ScheduledDtmList; endif; elseif FrequencyCode = "" then frequency_type := EVERY_X_TO_Y_UNITS; time_core_uom := read last {"SELECT CoreUOM " || " FROM CV3UnitOfMeasure" || " WHERE Code = " || SQL (FreqUom) || " AND Active = 1 " }; else // Gets the Frequency information from the Enterprise data // Only gets the Active Frequencies and Active Units of Measures (frequency_type, FreqFromTime, FreqToTime, time_core_uom):= read last {"SELECT f.DefinitionType, f.TimeFromValue, f.TimeToValue, u.CoreUOM " || " FROM CV3Frequency AS f " || " LEFT OUTER JOIN CV3UnitOfMeasure AS u" || " ON (f.TimeUom = u.Code and u.Active=1) " || " WHERE f.Code = " || SQL (FrequencyCode) || " AND f.Active = 1 " }; endif; // If there is a TO value use it for any calculations if FreqToTime > 0 then freq_time := FreqToTime; else freq_time := FreqFromTime; endif; ;; priority: 50 ;; evoke: ;; logic: dateOffset := 0 minutes; //-------------------------------------------------- // Calculate Stop After Days/Hours/Minutes. // Does not handle times // This calculation overrides any other calculation //-------------------------------------------------- if StopAfterOption > 0 then if StopAfterOption = STOP_AFTER_DAYS then dateOffset := StopAfterValue DAYS; elseif StopAfterOption = STOP_AFTER_HOURS then dateOffset := StopAfterValue HOURS; elseif StopAfterOption = STOP_AFTER_MINUTES then dateOffset := StopAftervalue MINUTES; elseif StopAfterOption = STOP_AFTER_TIMES // Do not calculate then dateOffset := 0 DAYS; endif; else // For user scheduled orders if ( FrequencyCode = "" ) then //------------------------------------- // Calculate Every X UNITS based on // Frequence of //------------------------------------- if FreqUOM = "day" then dateOffset := freq_time DAYS; // Every X days elseif FreqUOM = "week" then dateOffset := freq_time WEEKS; // Every X weeks else calculated_stopDtm := last of ScheduledDtmList; // Irregular endif; elseif FrequencyCode = "" then ; // Do nothing for Multiple else // All other Frequency Codes //------------------------------------------------------- // Frequency and Template // Handle frequency templates and by // parsing the frequency string // Set the frequency_type, time_core_uom and freq_time // values to be passed on to the next calculation If NOT Exist frequency_type AND dateOffset <= 0 minutes then frequency_type := EVERY_N_UNITS ; // Declare characters used for delimiting the string // Delimiters are Case Sensitive q_delim:= "Q"; h_delim:= "H"; m_delim:= "M"; // Determine if the letter in at the back of the string is H or M get_H:= call func_get_str with (FrequencyCode, h_delim); get_M:= call func_get_str with (FrequencyCode, m_delim); // Remove the front Q, so xH or xM is left trim_Q:= call func_get_token with (FrequencyCode, q_delim); // Set the time_core_uom // Remove the H or the M, leaving a string representation of a number if exist get_H then time_core_uom := HOUR_STRING; freq_num_str := call func_get_token with (trim_Q, h_delim); elseif exist get_M then time_core_uom := MINUTE_STRING; freq_num_str := call func_get_token with (trim_Q, m_delim); endif; // if exist get_H // Convert string to number freq_time := freq_num_str as number; endif; // If NOT Exist frequency_type //----------------------------------------------- // Convert Frequency to Durations // frequency_type of 1 = N times per UNIT // 2 = Every N UNITS // 3 = Every X to Y UNITS (Use Y in calculations) //----------------------------------------------- if frequency_type = N_TIMES_PER_UNIT then // Assume only a single day if time_core_uom is in ( DAY_STRING, HOUR_STRING, MINUTE_STRING, SECOND_STRING ) then dateOffset := 1 DAY; endif; elseif frequency_type = NONE then // If frequency type is NONE then assume a single day. dateOffset := 1 DAY; else // Type 2 and 3 // Rounds up to the next whole day if time_core_uom = DAY_STRING then dateOffset := ceiling (freq_time DAY / 1 DAY) DAYS; elseif time_core_uom = HOUR_STRING then dateOffset := ceiling (freq_time HOUR / 1 DAY) DAYS; elseif time_core_uom = MINUTE_STRING then dateOffset := ceiling (freq_time MINUTE / 1 DAY) DAYS; elseif time_core_uom = SECOND_STRING then dateOffset := ceiling (freq_time SECOND / 1 DAY) DAYS; endif; endif; // Frequency Type endif; // Frequency Code endif; // StopAfterOption //----------------------------------------------------------- // Calculate the stop date by adding the calculated offset //----------------------------------------------------------- if calculated_stopDtm is null AND dateOffset > 0 minutes then calculated_stopDtm := (startDtm + dateOffset) - 1 MINUTE; endif; conclude true; ;; action: return calculated_stopDtm; ;; Urgency: 50;; end: