Name

global.WorkflowDuration

Description

This class handles calculating the duration (number of seconds) based on the variables of a workflow activity. It is an interface between Workflow Timer() and DurationCalculator() Usage var wd = new WorkflowDuration(); // Set up // (optional specify the starting time) wd.setStartDateTime(/* GlideDateTime or Time String / startDateTime); // (optional specify the workflow s schedule and timezone. // Only used when schedule_type == workflow_schedule or timezone_type == workflow_timezone , respectively) wd.setWorkflow(/ cmn_schedule.sys_id / schedule, / String / timezone); // (optional specify number of seconds to be consumed , for a retroactive or future start. // -ve values indicate future start.) wd.setUsedSecs(n); // Calculate number of seconds, and the due date // based upon the duration specified in the record wd.calculate(/ Workflow activity variable GlideRecord / record); // Calculate the time remaining, until the due date wd.setEndDateTime(/ GlideDateTime or Time String / endDateTime); wd.setWorkflow(context.schedule, context.timezone); wd.calculateTimeLeft(/ Workflow activity variable GlideRecord / record); // add a number of seconds, using the required schedule, to the specified start date wd.setStartDateTime(startDateTime); wd.setWorkflow(context.schedule, context.timezone); wd.addSeconds(/ Workflow activity variable GlideRecord */ record, seconds); // Retrieve results wd.getSeconds(); wd.getTotalSeconds(); wd.getEndDateTime(); // specify the Workflow activity handler object (used to execute script duration calculations with WFActivityHandler.runScript) wd.setActivity(WFActivityHandler);

Script

/**
* This class handles calculating the duration (number of seconds)
* based on the variables of a workflow activity.
*
* The activity variables should include:
*         timer_type
*             '' -> user specified duration
*             'relative_duration'
*             'field'
*             'script'
*
*         duration
*         relative_duration
*         field
*         script
*
*         schedule_type
*             'user_specified_schedule'
*             'from_field_schedule'
*             'workflow_schedule'
*
*         user_specified_schedule
*         field_schedule
*
*         timezone_type
*             'user_specified_timezone'
*             'from_field_timezone'
*             'workflow_timezone'
*
*         user_specified_timezone
*         timezone_field
*
*         modifier
*         percentage
*         time_before
*         time_after
*/
var WorkflowDuration = Class.create();
WorkflowDuration.prototype = {
 
 initialize: function() {
    this.schedule = "";
    this.timezone = "";
    this.usedSecs = 0;
    this.startDateTime = new GlideDateTime();
    this.endDateTime = "";
    this.seconds = 0;
    this.totalSeconds = 0;
    this.workflowSchedule = "";
    this.workflowTimezone = "";

    this.activityDef = undefined;

    this._useScheduleForScript = (gs.getProperty('com.glideapp.workflow.duration.script_uses_schedule', 'false') == 'true');
    this._useScheduleForRelative = (gs.getProperty('com.glideapp.workflow.duration.relative_uses_schedule', 'false') == 'true');
     
    // Uncomment this line to turn on logging, otherwise empty logDebug is defined, which does nothing but prevents from throwing exception
    //this.lu = {logDebug: function(msg) {gs.log("SNC-WorkflowDuration: " + msg);}};
    this.lu = { logDebug: function(msg) {} };
 },
 
 /**
  * Get the seconds value that was set by a call to 'calculate'
  */
 getSeconds: function() {
    return this.seconds;
 },
 
 /**
  * Get the totalSeconds value that was set by a call to 'calculate'
  */
 getTotalSeconds: function() {
    return this.totalSeconds;
 },
 
 /**
  * Get the end date/time set by a call to 'calculate'
  * (returns a GlideDateTime object)
  */
 getEndDateTime: function() {
    return this.endDateTime;
 },
 
 /**
  * Set the start date/time to use in the calculations
  * (expects to be in GlideDateTime, or GMT
  * internal format - that is from GlideDateTime.getValue())
  */
 setStartDateTime: function(dt) {
    if (!dt)
       this.startDateTime = new GlideDateTime();
    else
       this.startDateTime = new GlideDateTime(dt);
 },
 
 /**
  * Set the end date/time, to use when calculating remaining time left
  * (GlideDateTime, or GMT internal format, from GlideDateTime.getValue())
  */
 setEndDateTime: function(dt) {
    if (dt)
       this.endDateTime = new GlideDateTime(dt);
 },
 
 /**
  * Set the workflow schedule/timezone
  * (used for schedule_type == 'workflow_schedule'
  *  and timezone_type == 'workflow_timezone')
  */
 setWorkflow: function(schedule, timezone) {
    this.workflowSchedule = schedule;
    this.workflowTimezone = timezone;
 },
 
 /*
  * Specify the calling Activity Handler object
  *
  * Used to execute runScript() in the original activity, which references the current context's scratchpad etc. 
  * This protects both formats of returning a value
  *  either by setting a value to the global answer or by returning a value on the last line of the script. 
  */ 
 setActivity: function(/* a WFActivityHandler object */ inActivityDef) {
    this.activityDef = inActivityDef;
 },

 
 /**
  * Set the "used seconds" compensation,
  *  where the number of seconds is the number of seconds inside of any schedule
  *  (can be a -ve number, which extends the duration)
  */
 setUsedSecs: function(secs) {
    this.usedSecs = secs;
 },
 
 /**
  * calculate the number of seconds, and the due date
  *
  * record - the record that contains the fields specified in the class comment above
  */
 calculate: function(/*GlideRecord*/record) {
    this.record = record;
    this._getSchedule();
    this._getTimeZone();
    this.endDateTime = "";
    
    this.lu.logDebug('calculate: timer_type=' + this._getValue('timer_type') + '; modifier=' + this._getValue('modifier'));
    
    var secs = 0;
    switch (this._getValue('timer_type')) {
       case 'relative_duration':
       secs = this._getSecondsFromRelativeDuration();
       
       // if timer duration needs modification
       if (this._getValue('modifier')) {
          secs = this._modifySeconds(secs);
          this.endDateTime = "";
       }
       break;
       
       case 'field':
       secs = this._getSecondsFromField();
       break;
       
       case 'script':
       secs = this._getSecondsFromScript();
       break;
       
       default:
       secs = this._getSecondsFromDuration();
    }
    
    this.seconds = secs;
    if (!this.endDateTime) {
       this.endDateTime = new GlideDateTime(this.startDateTime);
       this.endDateTime.addSeconds(this.seconds);
    }
    // if not already set by _getSecondsFrom*()
    this.lu.logDebug('calculate: this.endDateTime=' + this.endDateTime.getDisplayValueInternal() + ' (start: ' + this.startDateTime.getDisplayValueInternal() + '); ' + this.seconds);
    if (!this.totalSeconds)
       this.totalSeconds = this._totalSeconds(this.startDateTime, this.endDateTime);

 },
 
 /**
  * calculate the number of seconds remaining to the specified end date/time
  *
  * record - as per calculate()
  * retrieve values with getSeconds() and getTotalSeconds(), as required
  * returns 0 if specified end date/time is in the past.
  */
 calculateTimeLeft: function(/*GlideRecord*/ record) {
    this.record = record;
    this._getSchedule();
    this._getTimeZone();

    this.lu.logDebug('calculateTimeLeft: this.endDateTime=' + this.endDateTime.getDisplayValueInternal() + ' (start: ' + this.startDateTime.getDisplayValueInternal() + '); ' + this.totalSeconds);
    var dc = new DurationCalculator();
    if (this.schedule)
       dc.setSchedule(this.schedule, this.timezone);
    dc.calcScheduleDuration(this.startDateTime, this.endDateTime);
    this.seconds = dc.getSeconds();
    this.totalSeconds = dc.getTotalSeconds();
    if (this._getValue('timer_type') == 'relative_duration' || !this.schedule)
       this.seconds = this.totalSeconds;
 
    this.lu.logDebug('calculateTimeLeft: with schedule [' + this.schedule + ']; this.seconds=' + this.seconds);
 },
 
 /**
  * add the number of seconds to the specified start date/time
  *  potentially using the workflow-specified schedule
  *  (NB. relative duration uses a schedule to determine business days, but doesn't use it for duration
  *    unless property 'com.glideapp.workflow.duration.relative_uses_schedule' is set to "true")
  *
  * record - as per calculate()
  * retrieve end time with getEndDateTime();
  */
 addSeconds: function(/* GlideRecord */ record, seconds) {
    this.record = record;
    this._getSchedule();
    this._getTimeZone();
    
    var dc = new DurationCalculator();
    if (this.schedule && this._getValue('timer_type') != 'relative_duration' || this._useScheduleForRelative)
       dc.setSchedule(this.schedule, this.timezone);
    dc.setStartDateTime(this.startDateTime);
    dc.calcDuration(seconds);
    this.seconds = seconds;
    this.totalSeconds = dc.getTotalSeconds();
    this.endDateTime = dc.getEndDateTime();
 },
 
 /**
  * Get the seconds based on a relative duration calculation
  */
 _getSecondsFromRelativeDuration: function() {
    var dur = new DurationCalculator();
    dur.setSchedule(this.schedule, this.timezone);
    dur.setStartDateTime(this.startDateTime);
    dur.calcRelativeDuration(this._getValue('relative_duration'));
    this.endDateTime = dur.getEndDateTime();
    this.lu.logDebug('_getSecondsFromRelativeDuration: start=' + this.startDateTime.getValue() + '; end=' + this.endDateTime.getValue() + '; totalSeconds=' + dur.getTotalSeconds() + '; seconds=' + dur.getSeconds() + ' [' + this._useScheduleForRelative + ']');
    if (this._useScheduleForRelative)
       return dur.getSeconds();
    return dur.getTotalSeconds();
 },
 
 /**
  * Get the seconds based on the value of a field
  */
 _getSecondsFromField: function() {
    var secs = 0;
    var fieldName = this._getValue('field');
    this.lu.logDebug('_getSecondsFromField: fieldname (' + !fieldName + ') = ' + fieldName);
    if (!fieldName)
       return 0;
    var e = current.getElement(fieldName);
    this.lu.logDebug('_getSecondsFromField: element (' + !e + ') = ' + e.getName());
    if (!e) {
       return 0;
    }
    var fieldType = e.getED().getInternalType() + '';
    if (fieldType == 'glide_duration') {
       secs = e.getGlideObject().getNumericValue();
       secs = secs / 1000;

       // if timer duration needs modification
       if (this._getValue('modifier')) {
          secs = this._modifySeconds(secs);
       }
       
       this.lu.logDebug('_getSecondsFromField: schedule=' + this.schedule + '; timezone=' + this.timezone);
       this.lu.logDebug('_getSecondsFromField: startDateTime=' + this.startDateTime.getDisplayValueInternal() + '; secs=' + secs);
       // change time with schedule and timezone
       secs = this._getSeconds(secs);
    } else if (fieldType == 'glide_date' || fieldType == 'glide_date_time') {
       var start = new GlideDateTime(this.startDateTime);
       this.endDateTime = new GlideDateTime();
       if (fieldType == 'glide_date')
           this.endDateTime.setDisplayValue(e.getGlideObject());
       else
           this.endDateTime.setValue(e.getGlideObject());
            
       // secs = this._totalSeconds(start, this.endDateTime);
       var dc = new DurationCalculator();
       if (this.schedule)
          dc.setSchedule(this.schedule, this.timezone);
       
       if (this.startDateTime.getNumericValue() < this.endDateTime.getNumericValue()) {
           dc.calcScheduleDuration(this.startDateTime, this.endDateTime);
           secs = dc.getSeconds();
       } else {
           dc.calcScheduleDuration(this.endDateTime, this.startDateTime);
           secs = -dc.getSeconds();
       }
       
       // if timer duration needs modification
       if (this._getValue('modifier')) {
          secs = this._modifySeconds(secs);
       }
       this.lu.logDebug('_getSecondsFromField: schedule=' + this.schedule + '; timezone=' + this.timezone);
       this.lu.logDebug('_getSecondsFromField: startDateTime=' + this.startDateTime.getDisplayValueInternal() + '; endDateTime=' + this.endDateTime.getDisplayValueInternal() + '; secs=' + secs);
       secs = this._getSeconds(secs);
    }
    this.lu.logDebug('_getSecondsFromField: ('+ fieldName +') ' + secs + '; this.endDateTime=' + this.endDateTime.getDisplayValueInternal());
    return secs;
 },
 
 /**
  * Get seconds from a script
  */
 _getSecondsFromScript: function() {
    var script = this._getValue('script');
    var seconds;
    this.lu.logDebug('_getSecondsFromScript: [' + script + ']');
    if (this.activityDef !== undefined && typeof this.activityDef.runScript == 'function') {
       // run the script with the activity runScript method
       seconds = this.activityDef.runScript(script);
       this.lu.logDebug('_getSecondsFromScript: activity handler ' + this.activityDef.type + '.runScript() -> ' + seconds);
    }
    else
       seconds = GlideController.evaluateString(script);
    
    // ensure secs is always a valid number
    // (it may not be if a script returned an invalid value)
    if (JSUtil.nil(seconds) || isNaN(seconds))
       seconds = 0;
    if (this._useScheduleForScript)
       return this._getSeconds(seconds);
    return seconds;
 },
 
 /**
  * Get seconds from a user specified duration
  */
 _getSecondsFromDuration: function() {
    return this._getSeconds(this.record.duration.getGlideObject().getNumericValue() / 1000);
 },
 
 _getSeconds: function(durSeconds) {
    var dur = new DurationCalculator();
    dur.setSchedule(this.schedule, this.timezone);
    dur.setStartDateTime(this.startDateTime);
    dur.calcDuration(durSeconds);
    this.endDateTime = dur.getEndDateTime();
    return dur.getSeconds();
 },
 
 /**
  * Determine if there is a schedule specified
  */
 _getSchedule: function() {
    this.schedule = "";
    switch (this._getValue('schedule_type')) {
       case 'user_specified_schedule':
       this.schedule = this._getValue('user_specified_schedule');
       break;
       
       case 'from_field_schedule':
       var fieldName = this._getValue('schedule_field');
       if (fieldName)
          this.schedule = current.getElement(fieldName);
       break;
       
       case 'workflow_schedule':
       if (this.workflowSchedule)
          this.schedule = this.workflowSchedule;
       break;
    }
    this.lu.logDebug('_getSchedule: ' + this._getValue('schedule_type') + ': ' + this.schedule);
    
    if (!this.schedule)
       this.schedule = "";
 },
 
 _getTimeZone: function() {
    this.timezone = "";
    switch (this._getValue('timezone_type')) {
       case 'user_specified_timezone':
       this.timezone = this._getValue('user_specified_timezone');
       break;
       
       case 'from_field_timezone':
       var fieldName = this._getValue('timezone_field');
       if (fieldName)
          this.timezone = current.getElement(fieldName);
       break;
       
       case 'workflow_timezone':
       if (this.workflowTimezone)
          this.timezone = this.workflowTimezone;
       break;
    }
    this.lu.logDebug('_getTimeZone: ' + this._getValue('timezone_type') + ' in ' + fieldName + ' -> ' + this.timezone);
    if (!this.timezone)
       this.timezone = "";
 },
 
 _totalSeconds: function(/* GlideDateTime */ startTime, /* GlideDateTime */ endTime) {
    return Math.floor((endTime.getNumericValue() - startTime.getNumericValue()) / 1000);
 },
 
 /**
  * See if a modifier is specified and modify the total seconds accordingly
  * Also apply any specified time to be "used up"
  */
 _modifySeconds: function(secs) {
    var secsModified = parseInt(secs, 10);
    switch (this._getValue('modifier')) {
       case 'percentage':
       var perc = this._getValue('percentage');
       if (!perc)
          break;
       
       secsModified = secs * (perc / 100);
       break;
       
       case 'before':
       var beforeSecs = this.record.time_before.getGlideObject().getNumericValue() / 1000;
       secsModified -= beforeSecs;
       break;
       
       case 'after':
       var afterSecs = this.record.time_after.getGlideObject().getNumericValue() / 1000;
       secsModified += afterSecs;
       break;
    }
    // (for retroactive re-calculation)
    this.lu.logDebug('_modifySeconds: this.usedSecs=' + this.usedSecs);
    if (this.usedSecs !== 0)
       secsModified -= this.usedSecs;
    this.lu.logDebug('_modifySeconds: secsModified=' + secsModified);
    
    return secsModified;
 },
 
 _getValue: function(name) {
    var v = this.record.getValue(name);
    if (!v)
       v = "";
    
    return v;
 },
 
 type: 'WorkflowDuration'
};

Sys ID

8eb21271c0a8006666a23d675ebb20bb

Offical Documentation

Official Docs: