forked from Combodo/combodo-sla-computation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.combodo-sla-computation.php
309 lines (280 loc) · 10.1 KB
/
main.combodo-sla-computation.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
/**
* Module combodo-sla-computation
*
* @author Erwan Taloc <[email protected]>
* @author Romain Quetiez <[email protected]>
* @author Denis Flaven <[email protected]>
*/
/**
* Extension to the SLA computation mechanism
* This class implements a behavior based on:
* - Open hours for each day of the week
* - An explicit list of holidays
*/
class EnhancedSLAComputation extends SLAComputationAddOnAPI
{
/**
* Called when the module is loaded, used for one time initialization (if needed)
*/
public function Init()
{
}
/**
* @param Ticket $oTicket The ticket for which to compute the deadline
*
* @return string
* @since 2.3.0 N°2042 Deadline / OpenDuration extensibility
*/
protected static function GetCoverageOql($oTicket)
{
return MetaModel::GetModuleSetting('combodo-sla-computation', 'coverage_oql', '');
}
/**
* @param Ticket $oTicket The ticket for which to compute the deadline
* @param string $sOql default OQL query
*
* @return \DBObjectSet
* @throws \OQLException
* @since 2.3.0 N°2042 Deadline / OpenDuration extensibility
*/
protected static function GetCoverageSet($oTicket, $sOql)
{
$sCoverageOQL = $sOql ?: static::GetCoverageOql($oTicket);
if ($sCoverageOQL !== '')
{
return new DBObjectSet(DBObjectSearch::FromOQL($sCoverageOQL), array(), array('this' => $oTicket));
}
return DBObjectSet::FromScratch('CoverageWindow');
}
/**
* @param Ticket $oTicket The ticket for which to compute the deadline
*
* @return string
* @since 2.3.0 N°2042 Deadline / OpenDuration extensibility
*/
protected static function GetHolidaysOql($oTicket)
{
return MetaModel::GetModuleSetting('combodo-sla-computation', 'holidays_oql', '');
}
/**
* @param Ticket $oTicket The ticket for which to compute the deadline
* @param string $sOql default OQL query
*
* @return \DBObjectSet
* @throws \OQLException
* @since 2.3.0 N°2042 Deadline / OpenDuration extensibility
*/
protected static function GetHolidaysSet($oTicket, $sOql)
{
$sHolidaysOQL = $sOql ?: static::GetHolidaysOql($oTicket);
if ($sHolidaysOQL !== '')
{
return new DBObjectSet(DBObjectSearch::FromOQL($sHolidaysOQL), array(), array('this' => $oTicket));
}
return DBObjectSet::FromScratch('Holiday');
}
/**
* @param Ticket $oTicket The ticket for which to compute the deadline
* @param integer $iDuration The duration (in seconds) in the future
* @param DateTime $oStartDate The starting point for the computation
* @param string $sCoverageOql if provided, use this OQL
* @param string $sHolidaysOql if provided, use this OQL
*
* @return DateTime date/time corresponding to a given delay in the future from the present,
* considering only the valid (open) hours for a specified ticket
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public static function GetDeadline($oTicket, $iDuration, DateTime $oStartDate, $sCoverageOql = '', $sHolidaysOql = '')
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
$oCoverageSet = static::GetCoverageSet($oTicket, $sCoverageOql);
$oHolidaysSet = static::GetHolidaysSet($oTicket, $sHolidaysOql);
$oCoverage = null;
switch ($oCoverageSet->Count())
{
case 0:
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_INFO, 'No coverage window');
}
// No coverage window: 24x7 computation
$oDeadline = clone $oStartDate;
$oDeadline->modify($iDuration.' seconds');
break;
case 1:
/** @var \CoverageWindow $oCoverage */
$oCoverage = $oCoverageSet->Fetch();
$oDeadline = static::GetDeadlineFromCoverage($oCoverage, $oHolidaysSet, $iDuration, $oStartDate);
break;
default:
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_INFO,
'Several coverage windows: use the one that gives the stricter deadline');
}
$oDeadline = null;
// Several coverage windows found, use the one that gives the stricter deadline
/** @var \CoverageWindow $oCoverage */
while ($oCoverage = $oCoverageSet->Fetch())
{
$oTmpDeadline = static::GetDeadlineFromCoverage($oCoverage, $oHolidaysSet, $iDuration, $oStartDate);
// Retain the nearer deadline
// According to the PHP documentation, the plain comparison operator between DateTime objects
// (i.e $oTmpDeadline < $oDeadline) is only implemented in PHP 5.2.2
if (($oDeadline == null) || ($oTmpDeadline->format('U') < $oDeadline->format('U')))
{
$oDeadline = $oTmpDeadline;
}
}
}
return $oDeadline;
}
/**
* @param Ticket $oTicket The ticket for which to compute the duration
* @param DateTime $oStartDate The starting point for the computation (default = now)
* @param DateTime $oEndDate The ending point for the computation (default = now)
* @param string $sCoverageOql if provided, use this OQL
* @param string $sHolidaysOql if provided, use this OQL
*
* @return integer duration (number of seconds), considering only open hours, elapsed between two given DateTimes
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public static function GetOpenDuration($oTicket, DateTime $oStartDate, DateTime $oEndDate, $sCoverageOql = '', $sHolidaysOql = '')
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
$oCoverageSet = static::GetCoverageSet($oTicket, $sCoverageOql);
$oHolidaysSet = static::GetHolidaysSet($oTicket, $sHolidaysOql);
$oCoverage = null;
switch ($oCoverageSet->Count())
{
case 0:
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_INFO, 'No coverage window');
}
// No coverage window: 24x7 computation.. what about holidays ??
$iDuration = parent::GetOpenDuration($oTicket, $oStartDate, $oEndDate);
break;
case 1:
/** @var \CoverageWindow $oCoverage */
$oCoverage = $oCoverageSet->Fetch();
$iDuration = static::GetOpenDurationFromCoverage($oCoverage, $oHolidaysSet, $oStartDate, $oEndDate);
break;
default:
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_INFO,
'Several coverage windows: use the one that gives the stricter deadline, thus the longer elapsed duration');
}
$iDuration = null;
// Several coverage windows found, use the one that gives the stricter deadline, thus the longer elasped duration
/** @var \CoverageWindow $oCoverage */
while ($oCoverage = $oCoverageSet->Fetch())
{
$iTmpDuration = static::GetOpenDurationFromCoverage($oCoverage, $oHolidaysSet, $oStartDate, $oEndDate);
// Retain the longer duration
if (($iDuration == null) || ($iTmpDuration > $iDuration))
{
$iDuration = $iTmpDuration;
}
}
}
return $iDuration;
}
/**
* Helper function to get the date/time corresponding to a given delay in the future from the present,
* considering only the valid (open) hours as specified by the supplied CoverageWindow object and the given
* set of Holiday objects.
*
* @param CoverageWindow $oCoverage The coverage window defining the open hours
* @param DBObjectSet $oHolidaysSet The list of holidays to take into account
* @param integer $iDuration The duration (in seconds) in the future
* @param DateTime $oStartDate The starting point for the computation
*
* @return DateTime The date/time for the deadline
*/
public static function GetDeadlineFromCoverage(CoverageWindow $oCoverage, DBObjectSet $oHolidaysSet, $iDuration, DateTime $oStartDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
if (is_null($oCoverage))
{
// 24x7
$oDeadline = clone $oStartDate;
$oDeadline->modify($iDuration.' seconds');
}
else
{
$oDeadline = $oCoverage->GetDeadline($oHolidaysSet, $iDuration, $oStartDate);
}
return $oDeadline;
}
/**
* Helper function to get the date/time corresponding to a given delay in the future from the present,
* considering only the valid (open) hours as specified by the supplied CoverageWindow object and the given
* set of Holiday objects.
*
* @param CoverageWindow $oCoverage The coverage window defining the open hours
* @param DBObjectSet $oHolidaysSet The list of holidays to take into account
* @param DateTime $oStartDate The starting point for the computation (default = now)
* @param DateTime $oEndDate The ending point for the computation (default = now)
*
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public static function GetOpenDurationFromCoverage($oCoverage, $oHolidaysSet, $oStartDate, $oEndDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
if (is_null($oCoverage))
{
// 24x7
return abs($oEndDate->format('U') - $oStartDate->format('U'));
}
else
{
return $oCoverage->GetOpenDuration($oHolidaysSet, $oStartDate, $oEndDate);
}
}
public static function IsInsideCoverage($oCurDate, $oCoverage, $oHolidaysSet = null)
{
if (is_null($oCoverage))
{
// 24x7
return true;
}
else
{
return $oCoverage->IsInsideCoverage($oCurDate, $oHolidaysSet);
}
}
protected static function DumpInterval($oStart, $oEnd)
{
$iDuration = $oEnd->format('U') - $oStart->format('U');
echo "<p>Interval: [ ".$oStart->format('Y-m-d H:i:s (D - w)')." ; ".$oEnd->format('Y-m-d H:i:s')." ], duration $iDuration s</p>";
}
}
// By default, since this extension is present, let's use it !
SLAComputation::SelectModule('EnhancedSLAComputation');