3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 class CRM_Report_Form_Case_Detail
extends CRM_Report_Form
{
21 protected $_relField = FALSE;
23 protected $_addressField = TRUE;
25 protected $_activityLast = FALSE;
27 protected $_activityLastCompleted = FALSE;
29 protected $_includeCaseDetailExtra = FALSE;
31 protected $_caseDetailExtra = [];
33 protected $_customGroupExtends = ['Case'];
35 protected $_caseTypeNameOrderBy = FALSE;
39 public function __construct() {
40 $this->case_statuses
= CRM_Core_OptionGroup
::values('case_status');
41 $this->case_types
= CRM_Case_PseudoConstant
::caseType();
42 $rels = CRM_Core_PseudoConstant
::relationshipType();
43 foreach ($rels as $relid => $v) {
44 $this->rel_types
[$relid] = $v['label_b_a'];
47 $this->caseActivityTypes
= [];
48 foreach (CRM_Case_PseudoConstant
::caseActivityType() as $typeDetail) {
49 $this->caseActivityTypes
[$typeDetail['id']] = $typeDetail['label'];
54 'dao' => 'CRM_Case_DAO_Case',
57 'title' => ts('Case ID'),
62 'title' => ts('Subject'),
66 'title' => ts('Start Date'),
67 'type' => CRM_Utils_Type
::T_DATE
,
70 'title' => ts('End Date'),
71 'type' => CRM_Utils_Type
::T_DATE
,
73 'status_id' => ['title' => ts('Case Status')],
74 'case_type_id' => ['title' => ts('Case Type')],
76 'title' => ts('Deleted?'),
78 'type' => CRM_Utils_Type
::T_BOOLEAN
,
83 'title' => ts('Start Date'),
84 'operatorType' => CRM_Report_Form
::OP_DATE
,
85 'type' => CRM_Utils_Type
::T_DATE
,
88 'title' => ts('End Date'),
89 'operatorType' => CRM_Report_Form
::OP_DATE
,
90 'type' => CRM_Utils_Type
::T_DATE
,
93 'title' => ts('Case Status'),
94 'type' => CRM_Utils_Type
::T_INT
,
95 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
96 'options' => CRM_Case_BAO_Case
::buildOptions('status_id', 'search'),
99 'title' => ts('Case Type'),
100 'type' => CRM_Utils_Type
::T_INT
,
101 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
102 'options' => CRM_Case_BAO_Case
::buildOptions('case_type_id', 'search'),
105 'title' => ts('Deleted?'),
106 'type' => CRM_Utils_Type
::T_BOOLEAN
,
112 'title' => ts('Start Date'),
113 'default_weight' => 1,
116 'title' => ts('End Date'),
119 'title' => ts('Status'),
123 'civicrm_case_type' => [
124 'dao' => 'CRM_Case_DAO_Case',
126 'case_type_title' => [
127 'title' => 'Case Type',
132 'civicrm_contact' => [
133 'dao' => 'CRM_Contact_DAO_Contact',
135 'client_sort_name' => [
136 'name' => 'sort_name',
137 'title' => ts('Client Name'),
141 'no_display' => TRUE,
146 'sort_name' => ['title' => ts('Client Name')],
149 'civicrm_relationship' => [
150 'dao' => 'CRM_Contact_DAO_Relationship',
153 'name' => 'relationship_type_id',
154 'title' => ts('Case Role(s)'),
159 'name' => 'relationship_type_id',
160 'title' => ts('Case Role(s)'),
161 'type' => CRM_Utils_Type
::T_INT
,
162 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
163 'options' => $this->rel_types
,
166 'title' => ts('Active Role?'),
167 'type' => CRM_Utils_Type
::T_BOOLEAN
,
172 'dao' => 'CRM_Core_DAO_Email',
175 'title' => ts('Email'),
179 'grouping' => 'contact-fields',
182 'dao' => 'CRM_Core_DAO_Phone',
185 'title' => ts('Phone'),
189 'grouping' => 'contact-fields',
191 'civicrm_address' => [
192 'dao' => 'CRM_Core_DAO_Address',
194 'street_address' => NULL,
195 'state_province_id' => [
196 'title' => ts('State/Province'),
198 'country_id' => ['title' => ts('Country')],
200 'grouping' => 'contact-fields',
203 'title' => ts('Country'),
204 'type' => CRM_Utils_Type
::T_INT
,
205 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
206 'options' => CRM_Core_PseudoConstant
::country(),
208 'state_province_id' => [
209 'title' => ts('State/Province'),
210 'type' => CRM_Utils_Type
::T_INT
,
211 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
212 'options' => CRM_Core_PseudoConstant
::stateProvince(),
216 'civicrm_worldregion' => [
217 'dao' => 'CRM_Core_DAO_Worldregion',
219 'worldregion_id' => [
221 'title' => ts('World Region'),
222 'type' => CRM_Utils_Type
::T_INT
,
223 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
224 'options' => CRM_Core_PseudoConstant
::worldRegion(),
228 'civicrm_country' => [
229 'dao' => 'CRM_Core_DAO_Country',
231 'civicrm_activity_last' => [
232 'dao' => 'CRM_Activity_DAO_Activity',
234 'last_activity_activity_subject' => [
236 'title' => ts('Subject of the last activity in the case'),
238 'last_activity_activity_type' => [
239 'name' => 'activity_type_id',
240 'title' => ts('Activity type of the last activity'),
242 'last_activity_date_time' => [
243 'name' => 'activity_date_time',
244 'title' => ts('Last Action Date'),
245 'operatorType' => CRM_Report_Form
::OP_DATE
,
249 'last_activity_date_time' => [
250 'name' => 'activity_date_time',
251 'title' => ts('Last Action Date'),
252 'operatorType' => CRM_Report_Form
::OP_DATE
,
255 'alias' => 'civireport_activity_last',
257 'civicrm_activity_last_completed' => [
258 'dao' => 'CRM_Activity_DAO_Activity',
260 'last_completed_activity_subject' => [
262 'title' => ts('Subject of the last completed activity in the case'),
264 'last_completed_activity_type' => [
265 'name' => 'activity_type_id',
266 'title' => ts('Activity type of the last completed activity'),
268 'last_completed_date_time' => [
269 'name' => 'activity_date_time',
270 'title' => ts('Last Completed Action Date'),
271 'operatorType' => CRM_Report_Form
::OP_DATE
,
275 'last_completed_date_time' => [
276 'name' => 'activity_date_time',
277 'title' => ts('Last Completed Action Date'),
278 'operatorType' => CRM_Report_Form
::OP_DATE
,
286 'title' => ts('My Cases'),
287 'type' => 'checkbox',
290 parent
::__construct();
293 public function preProcess() {
294 parent
::preProcess();
297 public function buildQuickForm() {
298 parent
::buildQuickForm();
299 $this->caseDetailSpecialColumnsAdd();
302 public function caseDetailSpecialColumnsAdd() {
304 $elements[] = &$this->createElement('select', 'case_activity_all_dates', NULL,
306 '' => ts('- select -'),
307 ] +
$this->caseActivityTypes
309 $this->addGroup($elements, 'case_detail_extra');
311 $this->_caseDetailExtra
= [
312 'case_activity_all_dates' => [
313 'title' => ts('List of all dates of activities of Type'),
314 'name' => 'activity_date_time',
318 $this->assign('caseDetailExtra', $this->_caseDetailExtra
);
321 public function select() {
322 // @todo - get rid of this function & use parent. Use selectWhere to setthe clause for the
323 // few fields that need custom handling.
325 $this->_columnHeaders
= [];
326 foreach ($this->_columns
as $tableName => $table) {
327 if (array_key_exists('fields', $table)) {
328 foreach ($table['fields'] as $fieldName => $field) {
329 if (!empty($field['required']) ||
330 !empty($this->_params
['fields'][$fieldName])
332 if ($tableName == 'civicrm_relationship') {
333 $this->_relField
= TRUE;
335 if ($fieldName == 'sort_name') {
336 $select[] = "GROUP_CONCAT({$field['dbAlias']} ORDER BY {$field['dbAlias']} )
337 as {$tableName}_{$fieldName}";
339 if ($tableName == 'civicrm_activity_last') {
340 $this->_activityLast
= TRUE;
342 if ($tableName == 'civicrm_activity_last_completed') {
343 $this->_activityLastCompleted
= TRUE;
346 if ($fieldName == 'case_role') {
347 $select[] = "GROUP_CONCAT(DISTINCT({$field['dbAlias']}) ORDER BY {$field['dbAlias']}) as {$tableName}_{$fieldName}";
350 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
353 $this->_columnHeaders
["{$tableName}_{$fieldName}"]['type'] = $field['type'] ??
NULL;
354 $this->_columnHeaders
["{$tableName}_{$fieldName}"]['title'] = $field['title'];
360 $this->_selectClauses
= $select;
362 $this->_select
= 'SELECT ' . implode(', ', $select) . ' ';
365 public function from() {
367 $case = $this->_aliases
['civicrm_case'];
368 $conact = $this->_aliases
['civicrm_contact'];
371 FROM civicrm_case $case
372 LEFT JOIN civicrm_case_contact civireport_case_contact on civireport_case_contact.case_id = {$case}.id
373 LEFT JOIN civicrm_contact $conact ON {$conact}.id = civireport_case_contact.contact_id
375 if ($this->_relField
) {
377 LEFT JOIN civicrm_relationship {$this->_aliases['civicrm_relationship']} ON {$this->_aliases['civicrm_relationship']}.case_id = {$case}.id
381 $this->joinAddressFromContact();
382 $this->joinPhoneFromContact();
383 $this->joinEmailFromContact();
385 if ($this->isTableSelected('civicrm_worldregion')) {
387 LEFT JOIN civicrm_country {$this->_aliases['civicrm_country']}
388 ON {$this->_aliases['civicrm_country']}.id ={$this->_aliases['civicrm_address']}.country_id
389 LEFT JOIN civicrm_worldregion {$this->_aliases['civicrm_worldregion']}
390 ON {$this->_aliases['civicrm_country']}.region_id = {$this->_aliases['civicrm_worldregion']}.id ";
393 // Include clause for last activity of the case
394 if ($this->_activityLast
) {
395 $this->_from
.= " LEFT JOIN civicrm_activity {$this->_aliases['civicrm_activity_last']} ON ( {$this->_aliases['civicrm_activity_last']}.id = ( SELECT max(activity_id) FROM civicrm_case_activity WHERE case_id = {$case}.id) )";
398 // Include clause for last completed activity of the case
399 if ($this->_activityLastCompleted
) {
400 $this->_from
.= " LEFT JOIN civicrm_activity {$this->_aliases['civicrm_activity_last_completed']} ON ( {$this->_aliases['civicrm_activity_last_completed']}.id = ( SELECT max(activity_id) FROM civicrm_case_activity cca, civicrm_activity ca WHERE ca.id = cca.activity_id AND cca.case_id = {$case}.id AND ca.status_id = 2 ) )";
403 if ($this->isTableSelected('civicrm_case_type')) {
405 LEFT JOIN civicrm_case_type {$this->_aliases['civicrm_case_type']}
406 ON {$this->_aliases['civicrm_case']}.case_type_id = {$this->_aliases['civicrm_case_type']}.id
411 public function where() {
414 foreach ($this->_columns
as $tableName => $table) {
415 if (array_key_exists('filters', $table)) {
416 foreach ($table['filters'] as $fieldName => $field) {
419 if (CRM_Utils_Array
::value('type', $field) & CRM_Utils_Type
::T_DATE
) {
420 $relative = $this->_params
["{$fieldName}_relative"] ??
NULL;
421 $from = $this->_params
["{$fieldName}_from"] ??
NULL;
422 $to = $this->_params
["{$fieldName}_to"] ??
NULL;
424 $clause = $this->dateClause($field['dbAlias'], $relative, $from, $to, $field['type']);
428 $op = $this->_params
["{$fieldName}_op"] ??
NULL;
429 if ($fieldName == 'case_type_id' &&
430 !empty($this->_params
['case_type_id_value'])
432 foreach ($this->_params
['case_type_id_value'] as $key => $value) {
433 $this->_params
['case_type_id_value'][$key] = $value;
438 $clause = $this->whereClause($field,
440 CRM_Utils_Array
::value("{$fieldName}_value", $this->_params
),
441 CRM_Utils_Array
::value("{$fieldName}_min", $this->_params
),
442 CRM_Utils_Array
::value("{$fieldName}_max", $this->_params
)
447 if (!empty($clause)) {
448 $clauses[] = $clause;
454 if (isset($this->_params
['options']['my_cases'])) {
455 $session = CRM_Core_Session
::singleton();
456 $userID = $session->get('userID');
457 $clauses[] = "{$this->_aliases['civicrm_contact']}.id = {$userID}";
460 if (empty($clauses)) {
461 $this->_where
= 'WHERE ( 1 ) ';
464 $this->_where
= 'WHERE ' . implode(' AND ', $clauses);
468 public function groupBy() {
469 $this->_groupBy
= CRM_Contact_BAO_Query
::getGroupByFromSelectColumns($this->_selectClauses
, "{$this->_aliases['civicrm_case']}.id");
477 public function statistics(&$rows) {
478 $statistics = parent
::statistics($rows);
480 $select = "select COUNT( DISTINCT( {$this->_aliases['civicrm_address']}.country_id))";
481 $sql = "{$select} {$this->_from} {$this->_where}";
482 $countryCount = CRM_Core_DAO
::singleValueQuery($sql);
484 $statistics['counts']['case'] = [
485 'title' => ts('Total Number of Cases '),
486 'value' => isset($statistics['counts']['rowsFound']) ?
$statistics['counts']['rowsFound']['value'] : count($rows),
488 $statistics['counts']['country'] = [
489 'title' => ts('Total Number of Countries '),
490 'value' => $countryCount,
496 public function caseDetailSpecialColumnProcess() {
497 if (!$this->_includeCaseDetailExtra
) {
501 $from = $select = [];
502 $case = $this->_aliases
['civicrm_case'];
504 if ($activityType = CRM_Utils_Array
::value('case_activity_all_dates', $this->_params
['case_detail_extra'])) {
505 $select[] = "GROUP_CONCAT(DISTINCT(civireport_activity_all_{$activityType}.{$this->_caseDetailExtra['case_activity_all_dates']['name']}) ORDER BY civireport_activity_all_{$activityType}.{$this->_caseDetailExtra['case_activity_all_dates']['name']}) as case_activity_all_dates";
507 $from[] = " LEFT JOIN civicrm_case_activity civireport_case_activity_all_{$activityType} ON ( civireport_case_activity_all_{$activityType}.case_id = {$case}.id)
508 LEFT JOIN civicrm_activity civireport_activity_all_{$activityType} ON ( civireport_activity_all_{$activityType}.id = civireport_case_activity_all_{$activityType}.activity_id AND civireport_activity_all_{$activityType}.activity_type_id = {$activityType})";
510 $this->_columnHeaders
['case_activity_all_dates'] = [
511 'title' => $this->_caseDetailExtra
['case_activity_all_dates']['title'] . ": {$this->caseActivityTypes[$activityType]}",
512 'type' => $this->_caseDetailExtra
['case_activity_all_dates']['type'] ??
NULL,
516 $this->_select
.= ', ' . implode(', ', $select) . ' ';
517 $this->_from
.= ' ' . implode(' ', $from) . ' ';
520 public function postProcess() {
522 $this->beginPostProcess();
524 $this->checkEnabledFields();
526 $this->buildQuery(TRUE);
528 $this->caseDetailSpecialColumnProcess();
530 $sql = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}";
532 $rows = $graphRows = [];
533 $this->buildRows($sql, $rows);
535 $this->formatDisplay($rows);
537 $this->doTemplateAssignment($rows);
538 $this->endPostProcess($rows);
541 public function checkEnabledFields() {
542 if ((isset($this->_params
['case_role_value'])
543 && !empty($this->_params
['case_role_value'])) ||
544 (isset($this->_params
['is_active_value']))
546 $this->_relField
= TRUE;
549 if (!empty($this->_params
['last_completed_date_time_relative']) ||
550 !empty($this->_params
['last_completed_date_time_from']) ||
551 !empty($this->_params
['last_completed_date_time_to'])
553 $this->_activityLastCompleted
= TRUE;
556 if (!empty($this->_params
['last_activity_date_time_relative']) ||
557 !empty($this->_params
['last_activity_date_time_from']) ||
558 !empty($this->_params
['last_activity_date_time_to'])
560 $this->_activityLast
= TRUE;
563 foreach (array_keys($this->_caseDetailExtra
) as $field) {
564 if (!empty($this->_params
['case_detail_extra'][$field])) {
565 $this->_includeCaseDetailExtra
= TRUE;
572 * Alter display of rows.
574 * Iterate through the rows retrieved via SQL and make changes for display purposes,
575 * such as rendering contacts as links.
578 * Rows generated by SQL, with an array for each row.
580 public function alterDisplay(&$rows) {
582 $activityTypes = CRM_Core_PseudoConstant
::activityType(TRUE, TRUE);
584 foreach ($rows as $rowNum => $row) {
585 if (array_key_exists('civicrm_case_status_id', $row)) {
586 if ($value = $row['civicrm_case_status_id']) {
587 $rows[$rowNum]['civicrm_case_status_id'] = $this->case_statuses
[$value];
592 if (array_key_exists('civicrm_case_case_type_id', $row)) {
593 if ($value = str_replace(CRM_Core_DAO
::VALUE_SEPARATOR
, '', $row['civicrm_case_case_type_id'])) {
594 $rows[$rowNum]['civicrm_case_case_type_id'] = $this->case_types
[$value];
599 if (array_key_exists('civicrm_case_subject', $row)) {
600 if ($value = $row['civicrm_case_subject']) {
601 $url = CRM_Utils_System
::url("civicrm/case/ajax/details",
602 "caseId={$row['civicrm_case_id']}&contactId={$row['civicrm_contact_id']}",
605 $rows[$rowNum]['civicrm_case_subject'] = "<a class=\"crm-popup\" href=\"$url\">$value</a>";
606 $rows[$rowNum]['civicrm_case_subject_hover'] = ts('View Details of Case.');
611 if (array_key_exists('civicrm_relationship_case_role', $row)) {
612 if ($value = $row['civicrm_relationship_case_role']) {
613 $caseRoles = explode(',', $value);
614 foreach ($caseRoles as $num => $caseRole) {
615 $caseRoles[$num] = $this->rel_types
[$caseRole];
617 $rows[$rowNum]['civicrm_relationship_case_role'] = implode('; ', $caseRoles);
621 if (array_key_exists('civicrm_activity_last_last_activity_activity_subject', $row) &&
622 empty($row['civicrm_activity_last_last_activity_activity_subject'])
624 $rows[$rowNum]['civicrm_activity_last_last_activity_activity_subject'] = ts('(no subject)');
627 if (array_key_exists('civicrm_activity_last_completed_last_completed_activity_subject', $row) &&
628 empty($row['civicrm_activity_last_completed_last_completed_activity_subject'])
630 $rows[$rowNum]['civicrm_activity_last_completed_last_completed_activity_subject'] = ts('(no subject)');
633 if (array_key_exists('civicrm_contact_client_sort_name', $row) &&
634 array_key_exists('civicrm_contact_id', $row)
636 $url = CRM_Utils_System
::url("civicrm/contact/view",
637 'reset=1&cid=' . $row['civicrm_contact_id'],
640 $rows[$rowNum]['civicrm_contact_client_sort_name_link'] = $url;
641 $rows[$rowNum]['civicrm_contact_client_sort_name_hover'] = ts("View Contact Summary for this Contact");
644 if (array_key_exists('civicrm_activity_last_last_activity_activity_type', $row)) {
645 if ($value = $row['civicrm_activity_last_last_activity_activity_type']) {
646 $rows[$rowNum]['civicrm_activity_last_last_activity_activity_type'] = $activityTypes[$value];
650 if (array_key_exists('civicrm_activity_last_completed_last_completed_activity_type', $row)) {
651 if ($value = $row['civicrm_activity_last_completed_last_completed_activity_type']) {
652 $rows[$rowNum]['civicrm_activity_last_completed_last_completed_activity_type'] = $activityTypes[$value];
657 if (array_key_exists('case_activity_all_dates', $row)) {
658 if ($value = $row['case_activity_all_dates']) {
659 $activityDates = explode(',', $value);
660 foreach ($activityDates as $num => $activityDate) {
661 $activityDates[$num] = CRM_Utils_Date
::customFormat($activityDate);
663 $rows[$rowNum]['case_activity_all_dates'] = implode('; ', $activityDates);
668 $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, NULL, NULL) ?
TRUE : $entryFound;