Passed
Pull Request — developer (#16533)
by Arkadiusz
23:27
created

Calendar_Module_Model::postponeTimeValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
dl 0
loc 8
rs 10
c 1
b 0
f 0
ccs 0
cts 6
cp 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
 /* +***********************************************************************************
4
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
5
 * ("License"); You may not use this file except in compliance with the License
6
 * The Original Code is:  vtiger CRM Open Source
7
 * The Initial Developer of the Original Code is vtiger.
8
 * Portions created by vtiger are Copyright (C) vtiger.
9
 * All Rights Reserved.
10
 * Contributor(s): YetiForce S.A.
11
 * *********************************************************************************** */
12
13
/**
14
 * Calendar Module Model Class.
15
 */
16
class Calendar_Module_Model extends Vtiger_Module_Model
17
{
18
	/** {@inheritdoc} */
19
	public $allowTypeChange = false;
20
21
	/**
22 2
	 * Function returns the default view for the Calendar module.
23
	 *
24 2
	 * @return string
25
	 */
26
	public function getDefaultViewName()
27
	{
28
		return 'Calendar';
29
	}
30
31
	/**
32 2
	 *  Function returns the url for Calendar view.
33
	 *
34 2
	 * @return string
35 2
	 */
36 2
	public function getCalendarViewUrl()
37
	{
38 2
		return 'index.php?module=' . $this->get('name') . '&view=' . $this->getDefaultViewName();
39
	}
40
41
	/**
42
	 * Function to check whether the module is summary view supported.
43
	 *
44
	 * @return bool
45
	 */
46
	public function isSummaryViewSupported()
47
	{
48
		return false;
49
	}
50
51
	/** {@inheritdoc} */
52
	public function getSideBarLinks($linkParams)
53
	{
54
		$links = Vtiger_Link_Model::getAllByType($this->getId(), ['SIDEBARLINK', 'SIDEBARWIDGET'], $linkParams);
55
		$links['SIDEBARLINK'][] = Vtiger_Link_Model::getInstanceFromValues([
56
			'linktype' => 'SIDEBARLINK',
57
			'linklabel' => 'LBL_CALENDAR_VIEW',
58
			'linkurl' => $this->getCalendarViewUrl(),
59
			'linkicon' => 'fas fa-calendar-alt',
60
		]);
61
		$links['SIDEBARLINK'][] = Vtiger_Link_Model::getInstanceFromValues([
62
			'linktype' => 'SIDEBARLINK',
63
			'linklabel' => 'LBL_RECORDS_LIST',
64
			'linkurl' => $this->getListViewUrl(),
65
			'linkicon' => 'fas fa-list',
66
		]);
67
		if (isset($linkParams['ACTION']) && 'Calendar' === $linkParams['ACTION'] && App\Config::module('Calendar', 'SHOW_LIST_BUTTON')) {
68
			$links['SIDEBARLINK'][] = Vtiger_Link_Model::getInstanceFromValues([
69
				'linktype' => 'SIDEBARLINK',
70
				'linklabel' => 'LBL_CALENDAR_LIST',
71
				'linkurl' => 'javascript:Calendar_Calendar_Js.goToRecordsList("' . $this->getListViewUrl() . '");',
72
				'linkicon' => 'far fa-calendar-minus',
73
			]);
74
		}
75
		if ($this->isPermitted('Kanban') && \App\Utils\Kanban::getBoards($this->getName(), true)) {
0 ignored issues
show
Bug introduced by
$this->getName() of type boolean is incompatible with the type string expected by parameter $moduleName of App\Utils\Kanban::getBoards(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

75
		if ($this->isPermitted('Kanban') && \App\Utils\Kanban::getBoards(/** @scrutinizer ignore-type */ $this->getName(), true)) {
Loading history...
76
			$links['SIDEBARLINK'][] = Vtiger_Link_Model::getInstanceFromValues([
77
				'linktype' => 'SIDEBARLINK',
78
				'linklabel' => 'LBL_VIEW_KANBAN',
79
				'linkurl' => 'index.php?module=' . $this->getName() . '&view=Kanban',
80
				'linkicon' => 'yfi yfi-kanban',
81
			]);
82
		}
83
		return $links;
84
	}
85
86
	/**
87
	 * Function returns the url that shows Calendar Import result.
88
	 *
89
	 * @return string url
90
	 */
91
	public function getImportResultUrl()
92
	{
93
		return 'index.php?module=' . $this->getName() . '&view=ImportResult';
94
	}
95
96
	/**
97
	 * Function to get export query.
98
	 *
99
	 * @param mixed $focus
100
	 * @param mixed $where
101
	 *
102
	 * @return string query;
103
	 */
104
	public function getExportQuery($focus = '', $where = '')
0 ignored issues
show
Unused Code introduced by
The parameter $where is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

104
	public function getExportQuery($focus = '', /** @scrutinizer ignore-unused */ $where = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $focus is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

104
	public function getExportQuery(/** @scrutinizer ignore-unused */ $focus = '', $where = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
105
	{
106
		return (new App\Db\Query())->select(['vtiger_activity.*', 'vtiger_crmentity.description', 'assigned_user_id' => 'vtiger_crmentity.smownerid', 'vtiger_activity_reminder.reminder_time'])
107
			->from('vtiger_activity')
108
			->innerJoin('vtiger_crmentity', 'vtiger_activity.activityid = vtiger_crmentity.crmid')
109
			->leftJoin('vtiger_activity_reminder', 'vtiger_activity_reminder.activity_id = vtiger_activity.activityid')
110
			->where(['vtiger_crmentity.deleted' => 0, 'vtiger_crmentity.smownerid' => App\User::getCurrentUserId()]);
111
	}
112
113
	/**
114
	 * Function to set event fields for export.
115
	 */
116
	public function setEventFieldsForExport()
117
	{
118
		$keysToReplace = ['taskpriority'];
119
		$keysValuesToReplace = ['taskpriority' => 'priority'];
120
		foreach ($this->getFields() as $fieldName => $fieldModel) {
121
			if ($fieldModel->getPermissions()) {
122
				if (!\in_array($fieldName, $keysToReplace)) {
123
					$eventFields[$fieldName] = 'yes';
124
				} else {
125
					$eventFields[$keysValuesToReplace[$fieldName]] = 'yes';
126
				}
127
			}
128
		}
129
		$this->set('eventFields', $eventFields);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $eventFields does not seem to be defined for all execution paths leading up to this point.
Loading history...
130
	}
131
132
	/**
133
	 * Function to set todo fields for export.
134
	 */
135
	public function setTodoFieldsForExport()
136
	{
137
		$keysToReplace = ['taskpriority', 'activitystatus'];
138
		$keysValuesToReplace = ['taskpriority' => 'priority', 'activitystatus' => 'status'];
139
		foreach ($this->getFields() as $fieldName => $fieldModel) {
140
			if ($fieldModel->getPermissions()) {
141
				if (!\in_array($fieldName, $keysToReplace)) {
142
					$todoFields[$fieldName] = 'yes';
143
				} else {
144
					$todoFields[$keysValuesToReplace[$fieldName]] = 'yes';
145
				}
146
			}
147
		}
148
		$this->set('todoFields', $todoFields);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $todoFields does not seem to be defined for all execution paths leading up to this point.
Loading history...
149
	}
150
151
	/**
152
	 * Function to get the url to view Details for the module.
153
	 *
154
	 * @param mixed $id
155
	 *
156
	 * @return string - url
157
	 */
158
	public function getDetailViewUrl($id)
159
	{
160
		return 'index.php?module=Calendar&view=' . $this->getDetailViewName() . '&record=' . $id;
161
	}
162
163
	/**
164
	 * Function to get Alphabet Search Field.
165
	 */
166
	public function getAlphabetSearchField()
167
	{
168
		return 'subject';
169
	}
170
171
	/**
172
	 * Function returns Calendar Reminder record models.
173
	 *
174
	 * @return \Calendar_Record_Model[]
175
	 */
176
	public static function getCalendarReminder()
177
	{
178
		$currentUserModel = Users_Record_Model::getCurrentUserModel();
179
		$activityReminder = $currentUserModel->getCurrentUserActivityReminderInSeconds();
180
		$recordModels = [];
181
		if (!empty($activityReminder)) {
182
			$time = date('Y-m-d H:i:s', strtotime("+$activityReminder seconds"));
183
			$query = (new \App\Db\Query())
184
				->select(['recordid', 'vtiger_activity_reminder_popup.datetime'])
185
				->from('vtiger_activity_reminder_popup')
186
				->innerJoin('vtiger_activity', 'vtiger_activity_reminder_popup.recordid = vtiger_activity.activityid')
187
				->innerJoin('vtiger_crmentity', 'vtiger_activity_reminder_popup.recordid = vtiger_crmentity.crmid')
188
				->where(['vtiger_crmentity.smownerid' => $currentUserModel->getId(), 'vtiger_crmentity.deleted' => 0, 'vtiger_activity.status' => self::getComponentActivityStateLabel('current')])
189
				->andWhere(['or', ['and', ['vtiger_activity_reminder_popup.status' => Calendar_Record_Model::REMNDER_POPUP_ACTIVE], ['<=', 'vtiger_activity_reminder_popup.datetime', $time]], ['and', ['vtiger_activity_reminder_popup.status' => Calendar_Record_Model::REMNDER_POPUP_WAIT], ['<=', 'vtiger_activity_reminder_popup.datetime', date('Y-m-d H:i:s')]]])
190
				->orderBy(['vtiger_activity_reminder_popup.datetime' => SORT_DESC])
191
				->distinct()
192
				->limit(\App\Config::module('Calendar', 'maxNumberCalendarNotifications', 20));
193
			$dataReader = $query->createCommand()->query();
194
			while ($recordId = $dataReader->readColumn(0)) {
195
				$recordModels[] = Vtiger_Record_Model::getInstanceById($recordId, 'Calendar');
196
			}
197
		}
198
		return $recordModels;
199
	}
200
201
	/** {@inheritdoc} */
202
	public function getFieldsByType($type, bool $active = false): array
203
	{
204
		$restrictedField = ['picklist' => ['activitystatus', 'visibility', 'duration_minutes']];
205
		if (!\is_array($type)) {
206
			$type = [$type];
207
		}
208
		$fields = $this->getFields();
209
		$fieldList = [];
210
		foreach ($fields as $field) {
211
			$fieldType = $field->getFieldDataType();
212
			if (\in_array($fieldType, $type)) {
213
				$fieldName = $field->getName();
214
				if ('picklist' == $fieldType && \in_array($fieldName, $restrictedField[$fieldType])) {
215
				} else {
216
					$fieldList[$fieldName] = $field;
217
				}
218
			}
219
		}
220
		return $fieldList;
221
	}
222
223
	/** {@inheritdoc} */
224
	public function getSettingLinks(): array
225
	{
226
		$currentUserModel = Users_Record_Model::getCurrentUserModel();
227
		$settingLinks = [];
228
		if ($currentUserModel->isAdminUser()) {
229
			$settingLinks[] = [
230
				'linktype' => 'LISTVIEWSETTING',
231
				'linklabel' => 'LBL_EDIT_FIELDS',
232
				'linkurl' => 'index.php?parent=Settings&module=LayoutEditor&sourceModule=' . $this->getName(),
233
				'linkicon' => 'adminIcon-modules-fields',
234
			];
235
			$settingLinks[] = [
236
				'linktype' => 'LISTVIEWSETTING',
237
				'linklabel' => 'LBL_EDIT_PICKLIST_VALUES',
238
				'linkurl' => 'index.php?parent=Settings&module=Picklist&view=Index&source_module=' . $this->getName(),
239
				'linkicon' => 'adminIcon-fields-picklists',
240
			];
241
		}
242
		return $settingLinks;
0 ignored issues
show
introduced by
The expression return $settingLinks returns an array which contains values of type array<string,string> which are incompatible with the return type string mandated by Vtiger_Module_Model::getSettingLinks().
Loading history...
243
	}
244
245
	/**
246
	 * Function to get orderby sql from orderby field.
247
	 *
248
	 * @param mixed $orderBy
249
	 */
250
	public function getOrderBySql($orderBy)
251
	{
252
		if ('status' == $orderBy) {
253
			return $orderBy;
254
		}
255
		return parent::getOrderBySql($orderBy);
256
	}
257
258
	public static function getCalendarTypes()
259
	{
260
		return App\Fields\Picklist::getValuesName('activitytype');
261
	}
262
263
	/** {@inheritdoc} */
264
	public function getValuesFromSource(App\Request $request, $moduleName = false): array
265
	{
266
		$data = parent::getValuesFromSource($request);
267
268
		if (($postponeTime = $request->getInteger('postponeTime')) && $sourceRecordId = $request->getInteger('sourceRecord')) {
269
			$data = array_merge($data, $this->postponeTimeValue($sourceRecordId, $postponeTime));
270
		}
271
		return $data;
272
	}
273
274
	/**
275
	 * Load field  postpone values.
276
	 *
277
	 * @param int $sourceRecordId
278
	 * @param int $postponeTime
279
	 *
280
	 * @return array
281
	 */
282
	public function postponeTimeValue(int $sourceRecordId, int $postponeTime): array
283
	{
284
		$sourceRecordModel = Vtiger_Record_Model::getInstanceById($sourceRecordId);
285
		$dateStart = $sourceRecordModel->get('date_start') . ' ' . $sourceRecordModel->get('time_start');
286
		$dateEnd = $sourceRecordModel->get('due_date') . ' ' . $sourceRecordModel->get('time_end');
287
		$data['date_start'] = (new DateTime($dateStart))->modify("+ {$postponeTime} minutes")->format('Y-m-d H:i:s');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
288
		$data['due_date'] = (new DateTime($dateEnd))->modify("+ {$postponeTime} minutes")->format('Y-m-d H:i:s');
289
		return $data;
290
	}
291
292
	public static function getCalendarState($data = [])
293
	{
294
		if ($data) {
295
			$activityStatus = $data['activitystatus'];
296
			if (\in_array($activityStatus, self::getComponentActivityStateLabel('history'))) {
297
				return false;
298
			}
299
			$dueDateTime = $data['due_date'] . ' ' . $data['time_end'];
300
			$startDateTime = $data['date_start'] . ' ' . $data['time_start'];
301
			$dates = ['start' => $startDateTime, 'end' => $dueDateTime, 'current' => null];
302
			foreach ($dates as $key => $date) {
303
				$date = new DateTimeField($date);
304
				$userFormatedString = $date->getDisplayDate();
305
				$timeFormatedString = $date->getDisplayTime();
306
				$dBFomatedDate = DateTimeField::convertToDBFormat($userFormatedString);
307
				$dates[$key] = strtotime($dBFomatedDate . ' ' . $timeFormatedString);
308
			}
309
			$activityStatusLabels = self::getComponentActivityStateLabel();
310 1
			if (!empty($data['activitystatus']) && isset($activityStatusLabels[$data['activitystatus']])) {
311
				$state = $activityStatusLabels[$data['activitystatus']];
312 1
			} else {
313 1
				$state = $activityStatusLabels['not_started'];
314 1
				if ($dates['end'] > $dates['current'] && $dates['start'] < $dates['current']) {
315 1
					$state = $activityStatusLabels['in_realization'];
316
				} elseif ($dates['end'] > $dates['current']) {
317 1
					$state = $activityStatusLabels['not_started'];
318 1
				} elseif ($dates['end'] < $dates['current']) {
319 1
					$state = $activityStatusLabels['overdue'];
320 1
				}
321 1
			}
322 1
			return $state;
323 1
		}
324 1
		return false;
325 1
	}
326
327 1
	/**
328 1
	 * The function gets the labels for a given status field.
329
	 *
330
	 * @param string $key
331 1
	 *
332 1
	 * @return <Array>
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array>.
Loading history...
333
	 */
334 1
	public static function getComponentActivityStateLabel($key = '')
335 1
	{
336
		$pickListValues = App\Fields\Picklist::getValuesName('activitystatus');
337
		if (!\is_array($pickListValues)) {
0 ignored issues
show
introduced by
The condition is_array($pickListValues) is always true.
Loading history...
338
			return [];
339
		}
340 1
		$componentsActivityState = [];
341
		foreach ($pickListValues as $value) {
342
			switch ($value) {
343
				case 'PLL_PLANNED':
344
					$componentsActivityState['not_started'] = $value;
345
					break;
346
				case 'PLL_IN_REALIZATION':
347
					$componentsActivityState['in_realization'] = $value;
348
					break;
349
				case 'PLL_COMPLETED':
350
					$componentsActivityState['completed'] = $value;
351
					break;
352 1
				case 'PLL_POSTPONED':
353
					$componentsActivityState['postponed'] = $value;
354 1
					break;
355 1
				case 'PLL_OVERDUE':
356
					$componentsActivityState['overdue'] = $value;
357
					break;
358 1
				case 'PLL_CANCELLED':
359 1
					$componentsActivityState['cancelled'] = $value;
360 1
					break;
361 1
				default:
362 1
					break;
363 1
			}
364 1
		}
365 1
		if ('current' == $key) {
366 1
			$componentsActivityState = ['PLL_PLANNED', 'PLL_IN_REALIZATION', 'PLL_OVERDUE'];
367 1
		} elseif ('history' == $key) {
368 1
			$componentsActivityState = ['PLL_COMPLETED', 'PLL_POSTPONED', 'PLL_CANCELLED'];
369 1
		} elseif ($key) {
370 1
			return $componentsActivityState[$key];
371 1
		}
372 1
		return $componentsActivityState;
373 1
	}
374 1
375 1
	/**
376 1
	 * Import calendar rekords from ICS.
377 1
	 *
378 1
	 * @param string $filePath
379
	 *
380
	 * @throws \Exception
381
	 *
382
	 * @return array
383 1
	 */
384 1
	public function importICS(string $filePath)
385 1
	{
386 1
		$userId = \App\User::getCurrentUserRealId();
387 1
		$lastImport = new ICalLastImport();
388
		$lastImport->clearRecords($userId);
389
		$eventModule = 'Events';
390 1
		$todoModule = 'Calendar';
391
		$totalCount = $skipCount = [$eventModule => 0, $todoModule => 0];
392
		$calendar = \App\Integrations\Dav\Calendar::loadFromContent(file_get_contents($filePath));
393
		foreach ($calendar->getRecordInstance() as $recordModel) {
394
			$recordModel->set('assigned_user_id', $userId);
395
			$recordModel->save();
396
			$calendar->recordSaveAttendee($recordModel);
397
			if ('VEVENT' === (string) $calendar->getComponent()->name) {
398
				$module = $eventModule;
399
			} else {
400
				$module = $todoModule;
401
			}
402
			if ($recordModel->getId()) {
403
				++$totalCount[$module];
404
				$lastImport = new ICalLastImport();
405
				$lastImport->setFields(['userid' => $userId, 'entitytype' => $this->getName(), 'crmid' => $recordModel->getId()]);
406
				$lastImport->save();
407
			} else {
408
				++$skipCount[$module];
409
			}
410
		}
411
		return ['events' => $totalCount[$eventModule] - $skipCount[$eventModule], 'skipped_events' => $skipCount[$eventModule], 'task' => $totalCount[$todoModule] - $skipCount[$todoModule], 'skipped_task' => $skipCount[$todoModule]];
412
	}
413
414
	/** {@inheritdoc} */
415
	public function getLayoutTypeForQuickCreate(): string
416
	{
417
		return 'standard';
418
	}
419
}
420