Helpdesk da PluGzOne, baseado no osTicket
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

195 lines
7.1 KiB

<?php
/*********************************************************************
class.businesshours.php
Peter Rotich <peter@osticket.com>
Copyright (c) 2019 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
include_once INCLUDE_DIR.'class.schedule.php';
/*
* BusinessHours utility class
*
*/
class BusinessHours {
// Schedule
protected $schedule;
// Options
protected $options;
// Occurrence buckets
protected $workhours;
protected $holidays;
// Timeline log
protected $timeline;
function __construct(BusinessHoursSchedule $schedule,
$options=array()) {
$this->schedule = $schedule;
$this->options = $options;
}
function __onload() {
$this->workhours = array();
$this->holidays = array();
$this->timeline = array();
}
public function getSchedule() {
return $this->schedule;
}
// Intitialize occurrenses buckets
private function initOccurrences(Datetime $date, $grace_period_hrs=72) {
$dt = clone $date;
// Start from next day if current date is already processed
if (isset($this->workhours[$dt->format('Y-m-d')]))
$dt->modify('+1 day');
// Apply grace period
$period = clone $dt;
$period->modify("+$grace_period_hrs hour");
// Reset occurrense buckets
$this->workhours = $this->holidays = array();
// Init workhours
foreach ($this->getSchedule()->getEntries() as $entry)
$this->workhours += $entry->getOccurrences($dt,
$period->format('Y-m-d'));
ksort($this->workhours);
// Init holidays taking into account end date of the workhours in
// the current scope.
$enddate = array_pop(array_keys($this->workhours));
foreach ($this->getSchedule()->getHolidaysSchedules() as $schedule) {
foreach ($schedule->getEntries() as $entry)
$this->holidays += $entry->getOccurrences($dt, $enddate);
}
ksort($this->holidays);
// Return number of work hours occurrences
return count($this->workhours);
}
// Add requesed Working Hours to a given date in accordance to schedule
public function addWorkingHours(Datetime $date, $hours, &$auditlog=array()) {
// We ain't doing shit without hours
if (!$hours || !is_numeric($hours))
return $date;
// If the schedule has no entries then return false - indicating an
// error to the caller
if (!$this->getSchedule()->getNumEntries())
return false;
// Set timezone to schedule's one
$date->setTimezone($this->getSchedule()->getDatetimeZone());
$this->timeline(sprintf('*** Add %d Working Hours to %s ***',
$hours, $date->format('Y-m-d H:i:s')));
$seconds = $hours*3600; // Requested hours in seconds
$_seconds = 0; // Bucker to collect working hours in seconds
while ($_seconds < $seconds) {
// Initialize occurrences of schedule entries from this date.
if (!$this->initOccurrences($date))
break;
// Loop thro' business hours while accounting for requested
// working hours
foreach ($this->workhours as $d => $e) {
$partial = false;
// Handle edge case where we're starting with a date that
// might or not be within Schedule Entry hours.
if ($d == $date->format('Y-m-d')) {
// If it's after hours then continue to the next working
// day
if ($e->isAfterHours($date))
continue;
// If we're already into the day then we need to do
// partial / remaining hours
if (!$e->isBeforeHours($date))
$partial = true;
} elseif (strtotime("$d ".$e->getEndsTime()) <
$date->getTimestamp()) {
// Entry is out of scope
continue;
}
// Handle holidays - if within scope of current work day
$leadtime =0;
if (($holiday=$this->holidays[$d])) {
$this->timeline(sprintf('%s -> Skip %f Holiday Hours from %s [%s]',
$d,
$holiday->getHours(),
$holiday->getSchedule()->getName(),
$holiday->getDesc()));
//Move the date to end of the day of the holiday
$date->modify("$d ".$holiday->getEndsTime());
// If the holiday is a full day then assume the day is a goner
if ($holiday->isFullDay()) continue;
$partial = true;
// See if we need to recover any time prior to start of
// holiday e.g if the day starts at 8am but the holiday
// starts at 10am. Not typical but I foresee people
// using holiday concept to account for lunch hours.
$hstarts = strtotime($holiday->getStartsTime());
$dstarts = strtotime($e->getStartsTime());
if ($hstarts > $dstarts)
$leadtime = $hstarts-$dstarts;
}
// Add time to the bucket.
$time = $partial ? ($e->diffTime($date) + $leadtime) : $e->diff();
$_seconds += $time;
// Advance the date to end of this business day
$date->modify("$d ".$e->getEndsTime());
$this->timeline(sprintf('%s -> Apply %f Working Hours from %s
- %s (%d)',
$d, $time/3600, $e->getName(),
$date->format('Y-m-d H:i:s'),
($_seconds/3600)));
// Back track if the quota is met and break out of the loop.
if ($_seconds > $seconds) {
// TODO: Guard aganist backtracking to non working
// hours.
$time = intval(round(($_seconds-$seconds)));
$interval = new DateInterval('PT'.$time.'S');
$date->sub($interval);
$this->timeline(sprintf('%s -> Backtrack %f Hours %s (%s)',
$d, ($time)/3600,
$date->format('Y-m-d H:i:s'), ($seconds/3600)));
break;
}
}
}
$this->timeline(sprintf('*** Final Datetime %s ***',
$date->format('Y-m-d H:i:s')));
return $date;
}
// Log of the timeline for audit purposes
private function timeline($log) {
$this->timeline[] = $log;
}
public function getTimeline() {
return $this->timeline;
}
}
?>