Merge pull request #5967 from colemanw/CRM-16632
[civicrm-core.git] / CRM / Report / Form / ActivitySummary.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Report_Form_ActivitySummary extends CRM_Report_Form {
36
37 protected $_emailField = FALSE;
430ae6dd
TO
38 protected $_phoneField = FALSE;
39
74cf4551 40 /**
74cf4551
EM
41 */
42 /**
74cf4551 43 */
00be9182 44 public function __construct() {
6a488035 45 $this->_columns = array(
a8c87952 46 'civicrm_contact' => array(
6a488035 47 'dao' => 'CRM_Contact_DAO_Contact',
a8c87952
EM
48 'fields' => array(
49 'id' => array(
6a488035
TO
50 'required' => TRUE,
51 'no_display' => TRUE,
52 ),
a8c87952
EM
53 'sort_name' => array(
54 'title' => ts('Contact Name'),
6a488035
TO
55 'default' => TRUE,
56 'no_repeat' => TRUE,
57 ),
58 ),
a8c87952
EM
59 'filters' => array(
60 'sort_name' => array(
61 'title' => ts('Contact Name'),
6a488035
TO
62 ),
63 ),
a8c87952
EM
64 'group_bys' => array(
65 'sort_name' => array(
6a488035
TO
66 'name' => 'id',
67 'title' => ts('Contact'),
68 'default' => TRUE,
69 ),
70 ),
a8c87952
EM
71 'order_bys' => array(
72 'sort_name' => array(
21dfd5f5 73 'title' => ts('Contact Name'),
a8c87952 74 ),
6a488035
TO
75 ),
76 'grouping' => 'contact-fields',
77 ),
a8c87952 78 'civicrm_email' => array(
6a488035 79 'dao' => 'CRM_Core_DAO_Email',
a8c87952
EM
80 'fields' => array(
81 'email' => array(
6a488035
TO
82 'title' => 'Email',
83 'default' => TRUE,
84 ),
85 ),
a8c87952
EM
86 'order_bys' => array(
87 'email' => array(
21dfd5f5 88 'title' => ts('Email'),
a8c87952 89 ),
6a488035
TO
90 ),
91 'grouping' => 'contact-fields',
92 ),
a8c87952 93 'civicrm_phone' => array(
6a488035 94 'dao' => 'CRM_Core_DAO_Email',
a8c87952
EM
95 'fields' => array(
96 'phone' => array(
21dfd5f5 97 'title' => 'Phone',
a8c87952 98 ),
6a488035
TO
99 ),
100 'grouping' => 'contact-fields',
101 ),
a8c87952 102 'civicrm_activity' => array(
6a488035 103 'dao' => 'CRM_Activity_DAO_Activity',
a8c87952
EM
104 'fields' => array(
105 'activity_type_id' => array(
106 'title' => ts('Activity Type'),
6a488035
TO
107 'default' => TRUE,
108 'type' => CRM_Utils_Type::T_STRING,
109 ),
a8c87952 110 'duration' => array(
6a488035 111 'title' => 'Duration',
a8c87952 112 'statistics' => array(
6a488035
TO
113 'sum' => ts('Total Duration'),
114 ),
115 ),
a8c87952 116 'id' => array(
6a488035
TO
117 'title' => 'Total Activities',
118 'required' => TRUE,
a8c87952 119 'statistics' => array(
6a488035
TO
120 'count' => ts('Activity Count'),
121 ),
122 ),
123 ),
a8c87952
EM
124 'filters' => array(
125 'activity_date_time' => array(
21dfd5f5 126 'operatorType' => CRM_Report_Form::OP_DATE,
a8c87952
EM
127 ),
128 'activity_type_id' => array(
129 'title' => ts('Activity Type'),
6a488035
TO
130 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
131 'options' => CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE),
132 ),
a8c87952
EM
133 'status_id' => array(
134 'title' => ts('Activity Status'),
6a488035
TO
135 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
136 'options' => CRM_Core_PseudoConstant::activityStatus(),
137 ),
a8c87952
EM
138 'priority_id' => array(
139 'title' => ts('Priority'),
6a488035 140 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
cbf48754 141 'options' => CRM_Core_PseudoConstant::get('CRM_Activity_DAO_Activity', 'priority_id'),
6a488035
TO
142 ),
143 ),
a8c87952 144 'group_bys' => array(
9d72cede 145 'activity_date_time' => array(
353ffa53
TO
146 'title' => ts('Activity Date'),
147 'frequency' => TRUE,
148 ),
a8c87952
EM
149 'activity_type_id' => array(
150 'title' => ts('Activity Type'),
6a488035
TO
151 'default' => TRUE,
152 ),
153 ),
a8c87952
EM
154 'order_bys' => array(
155 'activity_date_time' => array(
21dfd5f5 156 'title' => ts('Activity Date'),
a8c87952
EM
157 ),
158 'activity_type_id' => array(
21dfd5f5 159 'title' => ts('Activity Type'),
a8c87952 160 ),
6a488035
TO
161 ),
162 'grouping' => 'activity-fields',
163 'alias' => 'activity',
164 ),
165 );
166
167 parent::__construct();
168 }
169
00be9182 170 public function select() {
6a488035
TO
171 $select = array();
172 $this->_columnHeaders = array();
173 foreach ($this->_columns as $tableName => $table) {
174 if (array_key_exists('group_bys', $table)) {
175 foreach ($table['group_bys'] as $fieldName => $field) {
a7488080 176 if (!empty($this->_params['group_bys'][$fieldName])) {
6221462f 177 if (isset($this->_params['group_bys_freq']) && !empty($this->_params['group_bys_freq'][$fieldName])) {
a8c87952
EM
178 switch ($this->_params['group_bys_freq'][$fieldName]) {
179 case 'YEARWEEK':
180 $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL WEEKDAY({$field['dbAlias']}) DAY) AS {$tableName}_{$fieldName}_start";
181
182 $select[] = "YEARWEEK({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
183 $select[] = "WEEKOFYEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
184 $field['title'] = 'Week';
185 break;
186
187 case 'YEAR':
188 $select[] = "MAKEDATE(YEAR({$field['dbAlias']}), 1) AS {$tableName}_{$fieldName}_start";
189 $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
190 $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
191 $field['title'] = 'Year';
192 break;
193
194 case 'MONTH':
195 $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL (DAYOFMONTH({$field['dbAlias']})-1) DAY) as {$tableName}_{$fieldName}_start";
196 $select[] = "MONTH({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
197 $select[] = "MONTHNAME({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
198 $field['title'] = 'Month';
199 break;
200
201 case 'QUARTER':
202 $select[] = "STR_TO_DATE(CONCAT( 3 * QUARTER( {$field['dbAlias']} ) -2 , '/', '1', '/', YEAR( {$field['dbAlias']} ) ), '%m/%d/%Y') AS {$tableName}_{$fieldName}_start";
203 $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
204 $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
205 $field['title'] = 'Quarter';
206 break;
207 }
6a488035
TO
208 $this->_interval = $field['title'];
209 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['title'] = $field['title'] . ' Beginning';
210 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['type'] = $field['type'];
211 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['group_by'] = $this->_params['group_bys_freq'][$fieldName];
212
213 // just to make sure these values are transfered to rows.
214 // since we need that for calculation purpose,
215 // e.g making subtotals look nicer or graphs
216 $this->_columnHeaders["{$tableName}_{$fieldName}_interval"] = array('no_display' => TRUE);
217 $this->_columnHeaders["{$tableName}_{$fieldName}_subtotal"] = array('no_display' => TRUE);
218 }
219 }
220 }
221 }
222 if (array_key_exists('fields', $table)) {
223 foreach ($table['fields'] as $fieldName => $field) {
8cc574cf 224 if (!empty($field['required']) || !empty($this->_params['fields'][$fieldName])) {
6a488035
TO
225 if ($tableName == 'civicrm_email') {
226 $this->_emailField = TRUE;
227 }
228 if ($tableName == 'civicrm_phone') {
229 $this->_phoneField = TRUE;
230 }
a7488080 231 if (!empty($field['statistics'])) {
6a488035
TO
232 foreach ($field['statistics'] as $stat => $label) {
233 switch (strtolower($stat)) {
234 case 'count':
235 $select[] = "COUNT(DISTINCT({$field['dbAlias']})) as {$tableName}_{$fieldName}_{$stat}";
236 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = CRM_Utils_Type::T_INT;
237 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
238 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
239 break;
240
241 case 'sum':
242 $select[] = "SUM({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}";
243 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = CRM_Utils_Type::T_INT;
244 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
245 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
246 break;
247 }
248 }
249 }
250 elseif ($fieldName == 'activity_type_id') {
a7488080 251 if (empty($this->_params['group_bys']['activity_type_id'])) {
6a488035
TO
252 $select[] = "GROUP_CONCAT(DISTINCT {$field['dbAlias']} ORDER BY {$field['dbAlias']} ) as {$tableName}_{$fieldName}";
253 }
254 else {
255 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
256 }
257 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = CRM_Utils_Array::value('type', $field);
258 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = CRM_Utils_Array::value('title', $field);
259 $this->_columnHeaders["{$tableName}_{$fieldName}"]['no_display'] = CRM_Utils_Array::value('no_display', $field);
260 }
261 else {
262 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
263 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = CRM_Utils_Array::value('type', $field);
264 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = CRM_Utils_Array::value('title', $field);
265 $this->_columnHeaders["{$tableName}_{$fieldName}"]['no_display'] = CRM_Utils_Array::value('no_display', $field);
266 }
267 }
268 }
269 }
270 }
271
272 $this->_select = "SELECT " . implode(', ', $select) . " ";
273 }
274
00be9182 275 public function from() {
ecaec004
RN
276 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
277 $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
278 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
279 $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
6a488035
TO
280
281 $this->_from = "
282 FROM civicrm_activity {$this->_aliases['civicrm_activity']}
2f4c2f5d 283
ecaec004
RN
284 LEFT JOIN civicrm_activity_contact target_activity
285 ON {$this->_aliases['civicrm_activity']}.id = target_activity.activity_id AND
286 target_activity.record_type_id = {$targetID}
287 LEFT JOIN civicrm_activity_contact assignment_activity
288 ON {$this->_aliases['civicrm_activity']}.id = assignment_activity.activity_id AND
289 assignment_activity.record_type_id = {$assigneeID}
290 LEFT JOIN civicrm_activity_contact source_activity
291 ON {$this->_aliases['civicrm_activity']}.id = source_activity.activity_id AND
292 source_activity.record_type_id = {$sourceID}
293 LEFT JOIN civicrm_contact contact_civireport
294 ON target_activity.contact_id = contact_civireport.id
295 LEFT JOIN civicrm_contact civicrm_contact_assignee
296 ON assignment_activity.contact_id = civicrm_contact_assignee.id
297 LEFT JOIN civicrm_contact civicrm_contact_source
298 ON source_activity.contact_id = civicrm_contact_source.id
6a488035 299 {$this->_aclFrom}
2f4c2f5d 300 LEFT JOIN civicrm_option_value
6a488035 301 ON ( {$this->_aliases['civicrm_activity']}.activity_type_id = civicrm_option_value.value )
2f4c2f5d 302 LEFT JOIN civicrm_option_group
6a488035 303 ON civicrm_option_group.id = civicrm_option_value.option_group_id
2f4c2f5d 304 LEFT JOIN civicrm_case_activity
6a488035 305 ON civicrm_case_activity.activity_id = {$this->_aliases['civicrm_activity']}.id
2f4c2f5d 306 LEFT JOIN civicrm_case
6a488035 307 ON civicrm_case_activity.case_id = civicrm_case.id
2f4c2f5d 308 LEFT JOIN civicrm_case_contact
6a488035
TO
309 ON civicrm_case_contact.case_id = civicrm_case.id ";
310
311 if ($this->_emailField) {
312 $this->_from .= "
313 LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
314 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_email']}.contact_id AND
315 {$this->_aliases['civicrm_email']}.is_primary = 1 ";
316 }
317
318 if ($this->_phoneField) {
319 $this->_from .= "
320 LEFT JOIN civicrm_phone {$this->_aliases['civicrm_phone']}
321 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_phone']}.contact_id AND
322 {$this->_aliases['civicrm_phone']}.is_primary = 1 ";
323 }
324 }
325
00be9182 326 public function where() {
2f4c2f5d 327 $this->_where = " WHERE civicrm_option_group.name = 'activity_type' AND
6a488035
TO
328 {$this->_aliases['civicrm_activity']}.is_test = 0 AND
329 {$this->_aliases['civicrm_activity']}.is_deleted = 0 AND
330 {$this->_aliases['civicrm_activity']}.is_current_revision = 1";
331
332 $clauses = array();
333 foreach ($this->_columns as $tableName => $table) {
334 if (array_key_exists('filters', $table)) {
335
336 foreach ($table['filters'] as $fieldName => $field) {
337 $clause = NULL;
338 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
339 $relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
a8c87952
EM
340 $from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
341 $to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
6a488035
TO
342
343 $clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
344 }
345 else {
346 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
347 if ($op) {
348 $clause = $this->whereClause($field,
349 $op,
350 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
351 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
352 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
353 );
354 }
355 }
356
357 if (!empty($clause)) {
358 $clauses[] = $clause;
359 }
360 }
361 }
362 }
363
364 if (empty($clauses)) {
365 $this->_where .= " ";
366 }
367 else {
368 $this->_where .= " AND " . implode(' AND ', $clauses);
369 }
370
371 if ($this->_aclWhere) {
372 $this->_where .= " AND {$this->_aclWhere} ";
373 }
374 }
375
00be9182 376 public function groupBy() {
6a488035
TO
377 $this->_groupBy = array();
378 if (is_array($this->_params['group_bys']) &&
379 !empty($this->_params['group_bys'])
380 ) {
381 foreach ($this->_columns as $tableName => $table) {
382 if (array_key_exists('group_bys', $table)) {
383 foreach ($table['group_bys'] as $fieldName => $field) {
a7488080
CW
384 if (!empty($this->_params['group_bys'][$fieldName])) {
385 if (!empty($field['chart'])) {
6a488035
TO
386 $this->assign('chartSupported', TRUE);
387 }
a8c87952
EM
388 if (!empty($table['group_bys'][$fieldName]['frequency']) &&
389 !empty($this->_params['group_bys_freq'][$fieldName])
390 ) {
6a488035
TO
391
392 $append = "YEAR({$field['dbAlias']}),";
393 if (in_array(strtolower($this->_params['group_bys_freq'][$fieldName]),
a8c87952
EM
394 array('year')
395 )) {
6a488035
TO
396 $append = '';
397 }
398 $this->_groupBy[] = "$append {$this->_params['group_bys_freq'][$fieldName]}({$field['dbAlias']})";
399 $append = TRUE;
400 }
401 else {
402 $this->_groupBy[] = $field['dbAlias'];
403 }
404 }
405 }
406 }
407 }
408
409 $this->_groupBy = "GROUP BY " . implode(', ', $this->_groupBy);
410 }
411 else {
412 $this->_groupBy = "GROUP BY {$this->_aliases['civicrm_contact']}.id ";
413 }
414 }
415
74cf4551
EM
416 /**
417 * @param $fields
418 * @param $files
419 * @param $self
420 *
421 * @return array
422 */
00be9182 423 public function formRule($fields, $files, $self) {
6a488035
TO
424 $errors = array();
425 $contactFields = array('sort_name', 'email', 'phone');
a7488080 426 if (!empty($fields['group_bys'])) {
6a488035 427
8cc574cf 428 if (!empty($fields['group_bys']['activity_type_id']) && empty($fields['group_bys']['sort_name'])) {
6a488035
TO
429 foreach ($fields['fields'] as $fieldName => $val) {
430 if (in_array($fieldName, $contactFields)) {
431 $errors['fields'] = ts("Please select GroupBy 'Contact' to display Contact Fields");
432 break;
433 }
434 }
435 }
436
a7488080
CW
437 if (!empty($fields['group_bys']['activity_date_time'])) {
438 if (!empty($fields['group_bys']['sort_name'])) {
6a488035
TO
439 $errors['fields'] = ts("Please do not select GroupBy 'Activity Date' with GroupBy 'Contact'");
440 }
441 else {
442 foreach ($fields['fields'] as $fieldName => $val) {
443 if (in_array($fieldName, $contactFields)) {
444 $errors['fields'] = ts("Please do not select any Contact Fields with GroupBy 'Activity Date'");
445 break;
446 }
447 }
448 }
449 }
450 }
451 return $errors;
452 }
453
00be9182 454 public function postProcess() {
6a488035
TO
455 // get the acl clauses built before we assemble the query
456 $this->buildACLClause($this->_aliases['civicrm_contact']);
457 parent::postProcess();
458 }
459
74cf4551 460 /**
4b62bc4f
EM
461 * Alter display of rows.
462 *
463 * Iterate through the rows retrieved via SQL and make changes for display purposes,
464 * such as rendering contacts as links.
465 *
466 * @param array $rows
467 * Rows generated by SQL, with an array for each row.
74cf4551 468 */
00be9182 469 public function alterDisplay(&$rows) {
6a488035 470
a8c87952 471 $entryFound = FALSE;
6a488035 472 $activityType = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE);
a8c87952 473 $flagContact = 0;
6a488035
TO
474
475 $onHover = ts('View Contact Summary for this Contact');
476 foreach ($rows as $rowNum => $row) {
477
478 if (array_key_exists('civicrm_contact_sort_name', $row) && $this->_outputMode != 'csv') {
479 if ($value = $row['civicrm_contact_id']) {
480
481 if ($rowNum == 0) {
482 $priviousContact = $value;
483 }
484 else {
485 if ($priviousContact == $value) {
486 $flagContact = 1;
487 $priviousContact = $value;
488 }
489 else {
490 $flagContact = 0;
491 $priviousContact = $value;
492 }
493 }
494
495 if ($flagContact == 1) {
496 $rows[$rowNum]['civicrm_contact_sort_name'] = "";
497
498 if (array_key_exists('civicrm_email_email', $row)) {
499 $rows[$rowNum]['civicrm_email_email'] = "";
500 }
501 if (array_key_exists('civicrm_phone_phone', $row)) {
502 $rows[$rowNum]['civicrm_phone_phone'] = "";
503 }
504 }
505 else {
506 $url = CRM_Utils_System::url('civicrm/contact/view',
507 'reset=1&cid=' . $value,
508 $this->_absoluteUrl
509 );
510
a8c87952
EM
511 $rows[$rowNum]['civicrm_contact_sort_name'] = "<a href='$url'>" . $row['civicrm_contact_sort_name'] .
512 '</a>';
6a488035
TO
513 }
514 $entryFound = TRUE;
515 }
516 }
517
518 if (array_key_exists('civicrm_activity_activity_type_id', $row)) {
519 if ($value = $row['civicrm_activity_activity_type_id']) {
520
521 $value = explode(',', $value);
522 foreach ($value as $key => $id) {
523 $value[$key] = $activityType[$id];
524 }
525
526 $rows[$rowNum]['civicrm_activity_activity_type_id'] = implode(' , ', $value);
527 $entryFound = TRUE;
528 }
529 }
530
531 if (!$entryFound) {
532 break;
533 }
534 }
535 }
96025800 536
6a488035 537}