Update copyright date for 2020
[civicrm-core.git] / CRM / Report / Form / Case / TimeSpent.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2020 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2020
32 */
33 class CRM_Report_Form_Case_TimeSpent extends CRM_Report_Form {
34
35 /**
36 * Class constructor.
37 */
38 public function __construct() {
39
40 $this->activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE);
41 asort($this->activityTypes);
42 $this->activityStatuses = CRM_Core_PseudoConstant::activityStatus();
43
44 $this->_columns = [
45 'civicrm_contact' => [
46 'dao' => 'CRM_Contact_DAO_Contact',
47 'fields' => [
48 'id' => [
49 'title' => ts('Contact ID'),
50 'no_display' => TRUE,
51 'required' => TRUE,
52 ],
53 'sort_name' => [
54 'title' => ts('Contact Name'),
55 'required' => TRUE,
56 'no_repeat' => TRUE,
57 ],
58 ],
59 'filters' => [
60 'sort_name' => [
61 'title' => ts('Contact Name'),
62 'operator' => 'like',
63 'type' => CRM_Report_Form::OP_STRING,
64 ],
65 ],
66 'order_bys' => [
67 'sort_name' => [
68 'title' => ts('Contact Name'),
69 'default_weight' => '1',
70 ],
71 ],
72 ],
73 'civicrm_activity' => [
74 'dao' => 'CRM_Activity_DAO_Activity',
75 'fields' => [
76 'activity_type_id' => [
77 'title' => ts('Activity Type'),
78 'default' => TRUE,
79 'type' => CRM_Utils_Type::T_STRING,
80 ],
81 'activity_date_time' => [
82 'title' => ts('Activity Date'),
83 'default' => TRUE,
84 ],
85 'status_id' => [
86 'title' => ts('Activity Status'),
87 'default' => FALSE,
88 'type' => CRM_Utils_Type::T_STRING,
89 ],
90 'id' => [
91 'title' => ts('Activity ID'),
92 'default' => TRUE,
93 ],
94 'duration' => [
95 'title' => ts('Duration'),
96 'default' => TRUE,
97 'type' => CRM_Utils_Type::T_INT,
98 ],
99 'subject' => [
100 'title' => ts('Activity Subject'),
101 'default' => FALSE,
102 ],
103 ],
104 'filters' => [
105 'activity_date_time' => [
106 'operatorType' => CRM_Report_Form::OP_DATE,
107 ],
108 'subject' => [
109 'title' => ts('Activity Subject'),
110 'type' => CRM_Utils_Type::T_STRING,
111 'operator' => 'like',
112 ],
113 'activity_type_id' => [
114 'title' => ts('Activity Type'),
115 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
116 'options' => $this->activityTypes,
117 ],
118 'status_id' => [
119 'title' => ts('Activity Status'),
120 'type' => CRM_Utils_Type::T_INT,
121 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
122 'options' => $this->activityStatuses,
123 ],
124 ],
125 'order_bys' => [
126 'subject' => [
127 'title' => ts('Activity Subject'),
128 ],
129 'activity_type_id' => [
130 'title' => ts('Activity Type'),
131 ],
132 'activity_date_time' => [
133 'title' => ts('Activity Date'),
134 ],
135 'status_id' => [
136 'title' => ts('Activity Status'),
137 ],
138 ],
139 'grouping' => 'case-fields',
140 ],
141 'civicrm_activity_source' => [
142 'dao' => 'CRM_Activity_DAO_ActivityContact',
143 'fields' => [
144 'contact_id' => [
145 'title' => ts('Contact ID'),
146 'default' => TRUE,
147 'no_display' => TRUE,
148 ],
149 ],
150 'group_bys' => [
151 'contact_id' => [
152 'title' => ts('Totals Only'),
153 'default' => TRUE,
154 ],
155 ],
156 'grouping' => 'activity-fields',
157 ],
158 'civicrm_case_activity' => [
159 'dao' => 'CRM_Case_DAO_CaseActivity',
160 'fields' => [
161 'case_id' => [
162 'title' => ts('Case ID'),
163 'default' => FALSE,
164 ],
165 ],
166 'filters' => [
167 'case_id_filter' => [
168 'name' => 'case_id',
169 'title' => ts('Cases?'),
170 'operatorType' => CRM_Report_Form::OP_SELECT,
171 'options' => [
172 1 => ts('Exclude non-case'),
173 2 => ts('Exclude cases'),
174 3 => ts('Include Both'),
175 ],
176 'default' => 3,
177 ],
178 ],
179 ],
180 ];
181
182 parent::__construct();
183 }
184
185 public function select() {
186 $select = [];
187 $this->_columnHeaders = [];
188
189 $this->has_grouping = !empty($this->_params['group_bys']);
190 $this->has_activity_type = FALSE;
191
192 foreach ($this->_columns as $tableName => $table) {
193 if (array_key_exists('fields', $table)) {
194 foreach ($table['fields'] as $fieldName => $field) {
195 if (!empty($field['required']) ||
196 (!empty($this->_params['fields'][$fieldName]) &&
197 ((!$this->has_grouping) ||
198 !in_array($fieldName, ['case_id', 'subject', 'status_id']))
199 )
200 ) {
201
202 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = CRM_Utils_Array::value('type', $field);
203 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = CRM_Utils_Array::value('title', $field);
204 $this->_columnHeaders["{$tableName}_{$fieldName}"]['no_display'] = CRM_Utils_Array::value('no_display', $field);
205
206 if ($fieldName == 'activity_type_id') {
207 $this->has_activity_type = TRUE;
208 }
209
210 if ($fieldName == 'duration' && $this->has_grouping) {
211 $select[] = "SUM({$field['dbAlias']}) as {$tableName}_{$fieldName}";
212 }
213 elseif ($fieldName == 'activity_date_time' && $this->has_grouping) {
214 $select[] = "EXTRACT(YEAR_MONTH FROM {$field['dbAlias']}) AS {$tableName}_{$fieldName}";
215 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = ts('Month/Year');
216 }
217 elseif ($tableName == 'civicrm_activity' && $fieldName == 'id' &&
218 $this->has_grouping
219 ) {
220 $select[] = "COUNT({$field['dbAlias']}) AS {$tableName}_{$fieldName}";
221 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = ts('# Activities');
222 }
223 else {
224 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
225 }
226 }
227 }
228 }
229 }
230 $this->_selectClauses = $select;
231
232 $this->_select = "SELECT " . implode(', ', $select) . " ";
233 }
234
235 public function from() {
236
237 $this->_from = "
238 FROM civicrm_activity {$this->_aliases['civicrm_activity']}
239 LEFT JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_source']}
240 ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_source']}.activity_id
241 LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
242 ON {$this->_aliases['civicrm_activity_source']}.contact_id = {$this->_aliases['civicrm_contact']}.id
243 LEFT JOIN civicrm_case_activity {$this->_aliases['civicrm_case_activity']}
244 ON {$this->_aliases['civicrm_case_activity']}.activity_id = {$this->_aliases['civicrm_activity']}.id
245 ";
246 }
247
248 public function where() {
249 $this->_where = " WHERE {$this->_aliases['civicrm_activity']}.is_current_revision = 1 AND
250 {$this->_aliases['civicrm_activity']}.is_deleted = 0 AND
251 {$this->_aliases['civicrm_activity']}.is_test = 0";
252 $clauses = [];
253 foreach ($this->_columns as $tableName => $table) {
254 if (array_key_exists('filters', $table)) {
255
256 foreach ($table['filters'] as $fieldName => $field) {
257 $clause = NULL;
258 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
259 $relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
260 $from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
261 $to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
262
263 $clause = $this->dateClause($field['dbAlias'], $relative, $from, $to);
264 }
265 else {
266 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
267 if ($op) {
268 // handle special case
269 if ($fieldName == 'case_id_filter') {
270 $choice = CRM_Utils_Array::value("{$fieldName}_value", $this->_params);
271 if ($choice == 1) {
272 $clause = "({$this->_aliases['civicrm_case_activity']}.id Is Not Null)";
273 }
274 elseif ($choice == 2) {
275 $clause = "({$this->_aliases['civicrm_case_activity']}.id Is Null)";
276 }
277 }
278 else {
279 $clause = $this->whereClause($field,
280 $op,
281 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
282 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
283 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
284 );
285 }
286 }
287 }
288
289 if (!empty($clause)) {
290 $clauses[] = $clause;
291 }
292 }
293 }
294 }
295
296 if (empty($clauses)) {
297 $this->_where .= " ";
298 }
299 else {
300 $this->_where .= " AND " . implode(' AND ', $clauses);
301 }
302 }
303
304 public function groupBy() {
305 $this->_groupBy = '';
306 if ($this->has_grouping) {
307 $groupBy = [
308 "{$this->_aliases['civicrm_contact']}.id",
309 "civicrm_activity_activity_date_time",
310 ];
311 if ($this->has_activity_type) {
312 $groupBy[] = "{$this->_aliases['civicrm_activity']}.activity_type_id";
313 }
314
315 $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, $groupBy);
316 }
317 }
318
319 public function postProcess() {
320 parent::postProcess();
321 }
322
323 /**
324 * @param $fields
325 * @param $files
326 * @param $self
327 *
328 * @return array
329 */
330 public static function formRule($fields, $files, $self) {
331 $errors = [];
332 if (!empty($fields['group_bys']) &&
333 (!array_key_exists('id', $fields['fields']) ||
334 !array_key_exists('activity_date_time', $fields['fields']) ||
335 !array_key_exists('duration', $fields['fields']))
336 ) {
337 $errors['fields'] = ts('To view totals please select all of activity id, date and duration.');
338 }
339 return $errors;
340 }
341
342 /**
343 * Alter display of rows.
344 *
345 * Iterate through the rows retrieved via SQL and make changes for display purposes,
346 * such as rendering contacts as links.
347 *
348 * @param array $rows
349 * Rows generated by SQL, with an array for each row.
350 */
351 public function alterDisplay(&$rows) {
352
353 $entryFound = FALSE;
354 foreach ($rows as $rowNum => $row) {
355
356 if (isset($row['civicrm_activity_activity_type_id'])) {
357 $entryFound = TRUE;
358 $val = $row['civicrm_activity_activity_type_id'];
359 $rows[$rowNum]['civicrm_activity_activity_type_id'] = isset($this->activityTypes[$val]) ? $this->activityTypes[$val] : '';
360 }
361
362 if (isset($row['civicrm_activity_status_id'])) {
363 $entryFound = TRUE;
364 $val = $row['civicrm_activity_status_id'];
365 $rows[$rowNum]['civicrm_activity_status_id'] = isset($this->activityStatuses[$val]) ? $this->activityStatuses[$val] : '';
366 }
367
368 // The next two make it easier to make pivot tables after exporting to Excel
369 if (isset($row['civicrm_activity_duration'])) {
370 $entryFound = TRUE;
371 $rows[$rowNum]['civicrm_activity_duration'] = (int) $row['civicrm_activity_duration'];
372 }
373
374 if (isset($row['civicrm_case_activity_case_id'])) {
375 $entryFound = TRUE;
376 $rows[$rowNum]['civicrm_case_activity_case_id'] = (int) $row['civicrm_case_activity_case_id'];
377 }
378
379 if (!$entryFound) {
380 break;
381 }
382 }
383 }
384
385 }