ServiceContracts   F
last analyzed

Complexity

Total Complexity 119

Size/Duplication

Total Lines 601
Duplicated Lines 0 %

Test Coverage

Coverage 12.71%

Importance

Changes 0
Metric Value
wmc 119
eloc 263
dl 0
loc 601
rs 2
c 0
b 0
f 0
ccs 30
cts 236
cp 0.1271

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getSlaPolicyForServiceContracts() 0 16 5
A getDefaultBusinessHours() 0 8 2
A getSlaPolicyById() 0 8 2
A getAllBusinessHours() 0 8 2
A getBusinessHoursByIds() 0 9 2
A getSlaPolicyByModule() 0 8 2
A saveSlaPolicy() 0 11 3
A updateExpectedTimes() 0 6 4
B parseBusinessHoursToDays() 0 28 10
A getSlaPolicyForModule() 0 9 2
A optimizeBusinessHours() 0 17 4
A getNextBusinessDay() 0 25 6
A getDiffFromSlaPolicy() 0 10 3
A getDiffFromServiceContracts() 0 16 5
C getRulesForServiceContracts() 0 41 16
A deleteSlaPolicy() 0 9 2
A getDiffFromDefaultBusinessHours() 0 13 4
A getModules() 0 9 3
C getExpectedTimes() 0 53 16
A getDiff() 0 16 6
B businessTime() 0 29 10
B getSlaPolicyRulesForModule() 0 26 10

How to fix   Complexity   

Complex Class

Complex classes like ServiceContracts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ServiceContracts, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Service contracts utils file.
4
 *
5
 * @package App
6
 *
7
 * @copyright YetiForce S.A.
8
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author    Mariusz Krzaczkowski <[email protected]>
10
 */
11
12
namespace App\Utils;
13
14
/**
15
 * Service contracts utils class.
16
 */
17
class ServiceContracts
18
{
19
	/**
20
	 * Fields map.
21
	 *
22
	 * @var string[]
23
	 */
24
	private static $fieldsMap = [
25
		'reaction_time' => 'response',
26
		'resolve_time' => 'solution',
27
		'idle_time' => 'idle',
28
	];
29
30
	/**
31
	 * Get the amount of business time between two dates in minutes.
32
	 *
33
	 * @param string $start
34
	 * @param string $end
35
	 * @param array  $days
36
	 * @param string $startHour
37
	 * @param string $endHour
38
	 * @param bool   $holidays
39
	 *
40
	 * @return int
41
	 */
42
	public static function businessTime(string $start, string $end, string $startHour, string $endHour, array $days, bool $holidays): int
43
	{
44
		$start = new \DateTime($start);
45
		$end = new \DateTime($end);
46
		$holidaysDates = $dates = [];
47
		$date = clone $start;
48
		$days = array_flip($days);
49
		if ($holidays) {
50
			$holidaysDates = array_flip(array_keys(\App\Fields\Date::getHolidays($start->format('Y-m-d'), $end->format('Y-m-d'))));
51
		}
52
		while ($date <= $end) {
53
			$datesEnd = (clone $date)->setTime(23, 59, 59);
54
			if (isset($days[$date->format('N')]) && (!$holidays || ($holidays && !isset($holidaysDates[$date->format('Y-m-d')])))) {
55
				$dates[] = [
56
					'start' => clone $date,
57
					'end' => clone ($end < $datesEnd ? $end : $datesEnd),
58
				];
59
			}
60
			$date->modify('+1 day')->setTime(0, 0, 0);
61
		}
62
		[$sh,$sm,$ss] = explode(':', $startHour);
63
		[$eh,$em,$es] = explode(':', $endHour);
64
		return array_reduce($dates, function ($carry, $item) use ($sh, $sm, $ss, $eh, $em, $es) {
65
			$businessStart = (clone $item['start'])->setTime($sh, $sm, $ss);
66
			$businessEnd = (clone $item['end'])->setTime($eh, $em, $es);
67
			$start = ($item['start'] < $businessStart) ? $businessStart : $item['start'];
68
			$end = ($item['end'] > $businessEnd) ? $businessEnd : $item['end'];
69
			return $carry += max(0, $end->getTimestamp() - $start->getTimestamp());
70
		}, 0) / 60;
71
	}
72
73
	/**
74
	 * Get default business hours.
75
	 *
76
	 * @return array
77
	 */
78 1
	public static function getDefaultBusinessHours(): array
79
	{
80 1
		if (\App\Cache::has('UtilsServiceContracts::getDefaultBusinessHours', '')) {
81 1
			return \App\Cache::get('UtilsServiceContracts::getDefaultBusinessHours', '');
82
		}
83 1
		$rows = (new \App\Db\Query())->from('s_#__business_hours')->where(['default' => 1])->all(\App\Db::getInstance('admin'));
84 1
		\App\Cache::save('UtilsServiceContracts::getDefaultBusinessHours', '', $rows);
85 1
		return $rows;
86
	}
87
88
	/**
89
	 * Get all business hours.
90
	 *
91
	 * @return array
92
	 */
93
	public static function getAllBusinessHours(): array
94
	{
95
		if (\App\Cache::has('UtilsServiceContracts::getAllBusinessHours', '')) {
96
			return \App\Cache::get('UtilsServiceContracts::getAllBusinessHours', '');
97
		}
98
		$rows = (new \App\Db\Query())->from('s_#__business_hours')->all(\App\Db::getInstance('admin'));
99
		\App\Cache::save('UtilsServiceContracts::getAllBusinessHours', '', $rows);
100
		return $rows;
101
	}
102
103
	/**
104
	 * Get business hours by ids .
105
	 *
106
	 * @param string $ids ex. '1,2'
107
	 *
108
	 * @return array
109
	 */
110
	public static function getBusinessHoursByIds(array $ids): array
111
	{
112
		$cacheKey = implode(',', $ids);
113
		if (\App\Cache::has('UtilsServiceContracts::getBusinessHoursById', $cacheKey)) {
114
			return \App\Cache::get('UtilsServiceContracts::getBusinessHoursById', $cacheKey);
115
		}
116
		$rows = (new \App\Db\Query())->from('s_#__business_hours')->where(['id' => $ids])->all(\App\Db::getInstance('admin'));
117
		\App\Cache::save('UtilsServiceContracts::getBusinessHoursById', $cacheKey, $rows);
118
		return $rows;
119
	}
120
121
	/**
122
	 * Get sla policy by id.
123
	 *
124
	 * @param int $id
125
	 *
126
	 * @return array
127
	 */
128
	private static function getSlaPolicyById(int $id): array
129
	{
130
		if (\App\Cache::has('UtilsServiceContracts::getSlaPolicyById', $id)) {
131
			return \App\Cache::get('UtilsServiceContracts::getSlaPolicyById', $id);
132
		}
133
		$row = (new \App\Db\Query())->from('s_#__sla_policy')->where(['id' => $id])->one(\App\Db::getInstance('admin'));
134
		\App\Cache::save('UtilsServiceContracts::getSlaPolicyById', $id, $row);
135
		return $row;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $row could return the type false which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
136
	}
137
138
	/**
139
	 * Get sla policy by module id.
140
	 *
141
	 * @param int $moduleId
142
	 *
143
	 * @return array
144
	 */
145
	public static function getSlaPolicyByModule(int $moduleId): array
146
	{
147
		if (\App\Cache::has('UtilsServiceContracts::getSlaPolicyByModule', $moduleId)) {
148
			return \App\Cache::get('UtilsServiceContracts::getSlaPolicyByModule', $moduleId);
149
		}
150
		$rows = (new \App\Db\Query())->from('s_#__sla_policy')->where(['tabid' => $moduleId])->all(\App\Db::getInstance('admin'));
151
		\App\Cache::save('UtilsServiceContracts::getSlaPolicyByModule', $moduleId, $rows);
152
		return $rows;
153
	}
154
155
	/**
156
	 * Get sla policy from service contracts by crm id.
157
	 *
158
	 * @param int      $serviceContractId Service contracts id
159
	 * @param int|null $sourceModuleId
160
	 *
161
	 * @return array
162
	 */
163 1
	public static function getSlaPolicyForServiceContracts(int $serviceContractId, ?int $sourceModuleId = null): array
164
	{
165 1
		if (\App\Cache::has('UtilsServiceContracts::getSlaPolicyForServiceContracts', $serviceContractId)) {
166 1
			$rows = \App\Cache::get('UtilsServiceContracts::getSlaPolicyForServiceContracts', $serviceContractId);
167
		} else {
168 1
			$rows = (new \App\Db\Query())->from('u_#__servicecontracts_sla_policy')->where(['crmid' => $serviceContractId])->all();
169 1
			\App\Cache::save('UtilsServiceContracts::getSlaPolicyForServiceContracts', $serviceContractId, $rows);
170
		}
171 1
		if ($sourceModuleId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sourceModuleId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
172 1
			foreach ($rows as $key => $value) {
173
				if ($sourceModuleId !== $value['tabid']) {
174
					unset($rows[$key]);
175
				}
176
			}
177
		}
178 1
		return $rows;
179
	}
180
181
	/**
182
	 * Delete sla policy for service contracts.
183
	 *
184
	 * @param int      $crmId
185
	 * @param int      $sourceModuleId
186
	 * @param int|null $rowId
187
	 *
188
	 * @return void
189
	 */
190
	public static function deleteSlaPolicy(int $crmId, int $sourceModuleId, ?int $rowId = null)
191
	{
192
		$where = ['crmid' => $crmId, 'tabid' => $sourceModuleId];
193
		if ($rowId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rowId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
194
			$where['id'] = $rowId;
195
		}
196
		\App\Db::getInstance()->createCommand()
197
			->delete('u_#__servicecontracts_sla_policy', $where)->execute();
198
		\App\Cache::delete('UtilsServiceContracts::getSlaPolicyForServiceContracts', $crmId);
199
	}
200
201
	/**
202
	 * Save sla policy for service contracts.
203
	 *
204
	 * @param array $data
205
	 * @param bool  $delete
206
	 *
207
	 * @return void
208
	 */
209
	public static function saveSlaPolicy(array $data, bool $delete = true)
210
	{
211
		$db = \App\Db::getInstance();
212
		if ($delete) {
213
			self::deleteSlaPolicy($data['crmid'], $data['tabid']);
214
		}
215
		if ($data['policy_type']) {
216
			$db->createCommand()->insert('u_#__servicecontracts_sla_policy', $data)->execute();
217
			return $db->getLastInsertID();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $db->getLastInsertID() returns the type string which is incompatible with the documented return type void.
Loading history...
218
		}
219
		return 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 returns the type integer which is incompatible with the documented return type void.
Loading history...
220
	}
221
222
	/**
223
	 * Get rules for service contracts.
224
	 *
225 1
	 * @param int                  $serviceContractId Service contracts id
226
	 * @param \Vtiger_Record_Model $recordModel       Record the model that will be updated
227 1
	 *
228 1
	 * @return array
229
	 */
230
	public static function getRulesForServiceContracts(int $serviceContractId, \Vtiger_Record_Model $recordModel): array
231
	{
232
		$times = $businessHours = [];
233
		foreach (self::getSlaPolicyForServiceContracts($serviceContractId, $recordModel->getModule()->getId()) as $row) {
234
			switch ($row['policy_type']) {
235
				case 1:
236
					$slaPolicy = self::getSlaPolicyById($row['sla_policy_id']);
237
					$conditions = \App\Json::decode($slaPolicy['conditions']);
238
					if ($conditions && \App\Condition::checkConditions($conditions, $recordModel)) {
239
						if (empty($slaPolicy['operational_hours'])) {
240
							return $slaPolicy;
241
						}
242
						if ($slaPolicy['business_hours']) {
243
							return self::optimizeBusinessHours(explode(',', $slaPolicy['business_hours']));
244
						}
245
					}
246
					break;
247
				case 2:
248
					$conditions = \App\Json::decode($row['conditions']);
249
					if ($conditions && $row['business_hours'] && \App\Condition::checkConditions($conditions, $recordModel)) {
250
						$businessHours = \array_merge($businessHours, explode(',', $row['business_hours']));
251
						if ((isset($times['reaction_time']) && \App\Fields\TimePeriod::convertToMinutes($row['reaction_time']) < \App\Fields\TimePeriod::convertToMinutes($times['reaction_time']))
252
						|| !isset($times['reaction_time'])) {
253
							$times = [
254
								'reaction_time' => $row['reaction_time'],
255
								'idle_time' => $row['idle_time'],
256
								'resolve_time' => $row['resolve_time'],
257
							];
258 1
						}
259
					}
260
					break;
261
			}
262
		}
263
		if ($businessHours) {
264
			$result = [];
265 1
			foreach (self::optimizeBusinessHours(\array_unique($businessHours)) as $value) {
266
				$result[] = array_merge($value, $times);
267
			}
268
			return $result;
269
		}
270
		return [];
271
	}
272
273
	/**
274
	 * Get rules for record model which will be updated.
275
	 *
276
	 * @param \Vtiger_Record_Model $recordModel Record the model that will be updated
277
	 *
278
	 * @return array
279
	 */
280
	public static function getSlaPolicyRulesForModule(\Vtiger_Record_Model $recordModel): array
281
	{
282
		$times = $businessHours = [];
283
		foreach (self::getSlaPolicyForModule($recordModel->getModule()->getId()) as $row) {
284
			$conditions = \App\Json::decode($row['conditions']);
285
			if ($conditions && $row['business_hours'] && \App\Condition::checkConditions($conditions, $recordModel)) {
286
				$businessHours = \array_merge($businessHours, explode(',', $row['business_hours']));
287
				if ((isset($times['reaction_time']) && \App\Fields\TimePeriod::convertToMinutes($row['reaction_time']) < \App\Fields\TimePeriod::convertToMinutes($times['reaction_time']))
288
						|| !isset($times['reaction_time'])) {
289
					$times = [
290
						'reaction_time' => $row['reaction_time'],
291
						'idle_time' => $row['idle_time'],
292
						'resolve_time' => $row['resolve_time'],
293
					];
294
				}
295
				break;
296
			}
297
		}
298
		if ($businessHours) {
299
			$result = [];
300
			foreach (self::optimizeBusinessHours(\array_unique($businessHours)) as $value) {
301
				$result[] = array_merge($value, $times);
302
			}
303
			return $result;
304
		}
305
		return [];
306
	}
307
308
	/**
309
	 * Get sla policy by crm id.
310
	 *
311
	 * @param int $moduleId
312
	 *
313
	 * @return array
314
	 */
315
	public static function getSlaPolicyForModule(int $moduleId): array
316
	{
317
		if (\App\Cache::has('UtilsServiceContracts::getSlaPolicyForModule', $moduleId)) {
318
			$rows = \App\Cache::get('UtilsServiceContracts::getSlaPolicyForModule', $moduleId);
319
		} else {
320
			$rows = (new \App\Db\Query())->from('s_#__sla_policy')->where(['tabid' => $moduleId, 'available_for_record_time_count' => 1])->all(\App\Db::getInstance('admin'));
321
			\App\Cache::save('UtilsServiceContracts::getSlaPolicyForModule', $moduleId, $rows);
322
		}
323
		return $rows;
324
	}
325
326
	/**
327
	 * Parse business hours to days.
328
	 *
329
	 * @param array $rows
330
	 *
331
	 * @return array
332
	 */
333
	private static function parseBusinessHoursToDays(array $rows): array
334
	{
335
		$days = $holidays = [];
336
		foreach ($rows as $row) {
337
			foreach (explode(',', $row['working_days']) as $day) {
338
				if ((isset($days[$day]['working_hours_from']) && (int) $row['working_hours_from'] < (int) $days[$day]['working_hours_from'])
339
					|| empty($days[$day]['working_hours_from'])) {
340
					$days[$day] = [
341
						'working_hours_from' => $row['working_hours_from'],
342
						'working_hours_to' => $row['working_hours_to'],
343
						'reaction_time' => $row['reaction_time'],
344
						'idle_time' => $row['idle_time'],
345
						'resolve_time' => $row['resolve_time'],
346
					];
347
				}
348
			}
349
			if (!empty($row['holidays']) && ((isset($holidays['working_hours_from']) && (int) $row['working_hours_from'] < (int) $holidays['working_hours_from'])
350
				|| empty($holidays['working_hours_from']))) {
351
				$holidays = [
352
					'working_hours_from' => $row['working_hours_from'],
353
					'working_hours_to' => $row['working_hours_to'],
354
					'reaction_time' => $row['reaction_time'],
355
					'idle_time' => $row['idle_time'],
356
					'resolve_time' => $row['resolve_time'],
357
				];
358
			}
359
		}
360
		return ['days' => $days, 'holidays' => $holidays];
361
	}
362
363
	/**
364
	 * Undocumented function.
365
	 *
366
	 * @param array $businessHours
367
	 *
368
	 * @return array
369
	 */
370
	private static function optimizeBusinessHours(array $businessHours): array
371
	{
372
		$result = [];
373
		['days' => $days, 'holidays' => $holidays] = self::parseBusinessHoursToDays(self::getBusinessHoursByIds($businessHours));
374
		foreach ($days as $day => $value) {
375
			$key = "{$value['working_hours_from']}|{$value['working_hours_to']}";
376
			if (isset($result[$key])) {
377
				$result[$key] = ['working_days' => $result[$key]['working_days'] . ',' . $day] + $value;
378
			} else {
379
				$result[$key] = ['working_days' => $day] + $value;
380
			}
381
		}
382
		if ($holidays) {
383
			$key = "{$holidays['working_hours_from']}|{$holidays['working_hours_to']}";
384
			$result[$key] = $result[$key] + ['holidays' => 1];
385
		}
386
		return $result;
387
	}
388
389
	/**
390
	 * Function returning difference in format between date times.
391
	 *
392
	 * @param string               $start
393
	 * @param string               $end
394
	 * @param \Vtiger_Record_Model $recordModel Record the model that will be updated
395
	 *
396
	 * @return int
397
	 */
398
	public static function getDiff(string $start, \Vtiger_Record_Model $recordModel, string $end = ''): int
399
	{
400
		if (!$end) {
401
			$end = date('Y-m-d H:i:s');
402
		}
403
		$fieldModel = current($recordModel->getModule()->getReferenceFieldsForModule('ServiceContracts'));
404
		if ($fieldModel && ($value = $recordModel->get($fieldModel->getName()))) {
405
			return self::getDiffFromServiceContracts($start, $end, $value, $recordModel);
406
		}
407
		if (\is_int($diff = self::getDiffFromSlaPolicy($start, $end, $recordModel))) {
408
			return $diff;
409
		}
410
		if (!($diff = self::getDiffFromDefaultBusinessHours($start, $end))) {
411
			$diff = \App\Fields\DateTime::getDiff($start, $end, 'minutes');
412
		}
413
		return $diff;
414 1
	}
415
416 1
	/**
417 1
	 * Get the amount of business time between the two dates in minutes based on the service contracts.
418 1
	 *
419
	 * @param string               $start
420
	 * @param string               $end
421 1
	 * @param int                  $serviceContractId Service contracts id
422
	 * @param \Vtiger_Record_Model $recordModel       Record the model that will be updated
423
	 *
424
	 * @return int
425
	 */
426
	public static function getDiffFromServiceContracts(string $start, string $end, int $serviceContractId, \Vtiger_Record_Model $recordModel): int
427
	{
428
		if ($rules = self::getRulesForServiceContracts($serviceContractId, $recordModel)) {
429
			if (isset($rules['id'])) {
430
				return round(\App\Fields\DateTime::getDiff($start, $end, 'minutes'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return round(App\Fields\...tart, $end, 'minutes')) returns the type double which is incompatible with the type-hinted return integer.
Loading history...
431
			}
432 1
			$time = 0;
433
			foreach ($rules as $row) {
434 1
				$time += self::businessTime($start, $end, $row['working_hours_from'], $row['working_hours_to'], explode(',', $row['working_days']), !empty($row['holidays']));
435 1
			}
436 1
			return $time;
437
		}
438
		if (!($diff = self::getDiffFromDefaultBusinessHours($start, $end))) {
439
			$diff = round(\App\Fields\DateTime::getDiff($start, $end, 'minutes'));
440
		}
441
		return $diff;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $diff could return the type double which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
442
	}
443
444
	/**
445
	 * Get the amount of business time between the two dates in minutes based on the global sla policy.
446
	 *
447 1
	 * @param string               $start
448
	 * @param string               $end
449
	 * @param \Vtiger_Record_Model $recordModel Record the model that will be updated
450 1
	 *
451
	 * @return int|null
452
	 */
453
	public static function getDiffFromSlaPolicy(string $start, string $end, \Vtiger_Record_Model $recordModel): ?int
454
	{
455
		if ($rules = self::getSlaPolicyRulesForModule($recordModel)) {
456
			$time = 0;
457
			foreach ($rules as $row) {
458
				$time += self::businessTime($start, $end, $row['working_hours_from'], $row['working_hours_to'], explode(',', $row['working_days']), !empty($row['holidays']));
459
			}
460
			return $time;
461
		}
462
		return null;
463
	}
464
465
	/**
466
	 * Get the amount of default business time between two dates in minutes.
467
	 *
468
	 * @param string $start
469
	 * @param string $end
470
	 *
471
	 * @return int
472
	 */
473
	public static function getDiffFromDefaultBusinessHours(string $start, string $end): int
474
	{
475
		$businessHours = self::getDefaultBusinessHours();
476
		if (!$businessHours) {
477
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the type-hinted return integer.
Loading history...
478
		}
479
		$time = 0;
480
		foreach ($businessHours as $row) {
481
			if ($row['working_days']) {
482
				$time += self::businessTime($start, $end, $row['working_hours_from'], $row['working_hours_to'], explode(',', $row['working_days']), (bool) $row['holidays']);
483
			}
484
		}
485
		return $time;
486
	}
487
488
	/**
489
	 * Update expected times.
490
	 *
491
	 * @param \Vtiger_Record_Model $recordModel
492
	 * @param array                $type
493
	 *
494
	 * @return void
495
	 */
496
	public static function updateExpectedTimes(\Vtiger_Record_Model $recordModel, array $type)
497
	{
498
		$field = \App\Field::getRelatedFieldForModule($recordModel->getModuleName(), 'ServiceContracts');
499
		$serviceContract = ($field && !empty($recordModel->get($field['fieldname']))) ? $recordModel->get($field['fieldname']) : 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression $field of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
500
		foreach (self::getExpectedTimes($serviceContract, $recordModel, $type) as $key => $time) {
501
			$recordModel->set($key . '_expected', $time);
502
		}
503
	}
504
505
	/**
506
	 * Get expected times from ServiceContracts.
507
	 *
508
	 * @param int                  $id          Service contract id
509
	 * @param \Vtiger_Record_Model $recordModel
510
	 * @param array                $type
511
	 *
512
	 * @return array
513
	 */
514
	private static function getExpectedTimes(int $id, \Vtiger_Record_Model $recordModel, array $type): array
515
	{
516
		$return = [];
517
		$date = new \DateTime();
518
		if ($id && ($rules = self::getRulesForServiceContracts($id, $recordModel)) || ($rules = self::getSlaPolicyRulesForModule($recordModel))) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($id && $rules = self::g...ForModule($recordModel), Probably Intended Meaning: $id && ($rules = self::g...orModule($recordModel))
Loading history...
519
			if (isset($rules['id'])) {
520
				foreach (self::$fieldsMap as $key => $fieldKey) {
521
					if (\in_array($fieldKey, $type)) {
522
						$minutes = \App\Fields\TimePeriod::convertToMinutes($rules[$key]);
523
						$return[$fieldKey] = (clone $date)->modify("+$minutes minute")->format('Y-m-d H:i:s');
524
					}
525
				}
526
				return $return;
527
			}
528
			$days = self::parseBusinessHoursToDays($rules);
529
		} elseif ($businessHours = self::getDefaultBusinessHours()) {
530
			$days = self::parseBusinessHoursToDays($businessHours);
531
		} else {
532
			return [];
533
		}
534
		$day = $date->format('N');
535
		$daySetting = null;
536
		if (\App\Fields\Date::getHolidays($date->format('Y-m-d'), $date->format('Y-m-d'))) {
537
			$daySetting = $days['holidays'];
538
		} elseif (empty($days['days'][$day])) {
539
			$daySetting = self::getNextBusinessDay($date, $days);
540
		} else {
541
			$daySetting = $days['days'][$day];
542
		}
543
		if ($daySetting) {
544
			$interval = \App\Fields\DateTime::getDiff($date->format('Y-m-d') . ' ' . $daySetting['working_hours_to'], $date->format('Y-m-d H:i:s'), 'minutes');
545
			foreach (self::$fieldsMap as $key => $fieldKey) {
546
				if (\in_array($fieldKey, $type)) {
547
					$minutes = \App\Fields\TimePeriod::convertToMinutes($daySetting[$key]);
548
					if ($minutes < $interval) {
549
						$return[$fieldKey] = (clone $date)->modify("+$minutes minute")->format('Y-m-d H:i:s');
550
					} else {
551
						$tmpDate = clone $date;
552
						$tmpInterval = $interval;
553
						while ($minutes > $tmpInterval) {
554
							$minutes -= $tmpInterval;
555
							$tmpDaySetting = self::getNextBusinessDay($tmpDate, $days);
556
							$tmpInterval = \App\Fields\DateTime::getDiff($tmpDate->format('Y-m-d') . ' ' . $tmpDaySetting['working_hours_to'], $tmpDate->format('Y-m-d H:i:s'), 'minutes');
557
							if ($minutes < $tmpInterval) {
558
								$return[$fieldKey] = (clone $tmpDate)->modify("+$minutes minute")->format('Y-m-d H:i:s');
559
							}
560
						}
561
					}
562
				}
563
			}
564
			return $return;
565
		}
566
		return [];
567
	}
568
569
	/**
570
	 * Get next business day.
571
	 *
572
	 * @param \DateTime $date
573
	 * @param array     $days
574
	 *
575
	 * @return array|null
576
	 */
577
	private static function getNextBusinessDay(\DateTime &$date, array $days): ?array
578
	{
579
		$tempDay = (int) $date->format('N') + 1;
580
		$counter = 1;
581
		$result = null;
582
		while ($counter < 14) {
583
			$date->modify('+1 day');
584
			if (\App\Fields\Date::getHolidays($date->format('Y-m-d'), $date->format('Y-m-d'))) {
585
				$result = $days['holidays'];
586
				break;
587
			}
588
			if (isset($days['days'][$tempDay])) {
589
				$result = $days['days'][$tempDay];
590
				break;
591
			}
592
			++$tempDay;
593
			if (8 === $tempDay) {
594
				$tempDay = 1;
595
			}
596
			++$counter;
597
		}
598
		if ($result) {
599
			\call_user_func_array([$date, 'setTime'], explode(':', $result['working_hours_from']));
600
		}
601
		return $result;
602
	}
603
604
	/**
605
	 * Get modules name related to ServiceContracts.
606
	 *
607
	 * @return string[]
608
	 */
609
	public static function getModules(): array
610
	{
611
		$modules = [];
612
		foreach (\App\Field::getRelatedFieldForModule(false, 'ServiceContracts') as $moduleName => $value) {
613
			if (\App\RecordStatus::getFieldName($moduleName)) {
614
				$modules[] = $moduleName;
615
			}
616
		}
617
		return $modules;
618
	}
619
}
620