Merge pull request #14021 from seamuslee001/contribute_new_coder
[civicrm-core.git] / CRM / Case / BAO / Case.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
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
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
cde2037d 35 * This class contains the functions for Case Management.
6a488035
TO
36 */
37class CRM_Case_BAO_Case extends CRM_Case_DAO_Case {
38
39 /**
cde2037d 40 * Static field for all the case information that we can potentially export.
6a488035
TO
41 *
42 * @var array
6a488035 43 */
f157740d 44 public static $_exportableFields = NULL;
e96f025a 45
4c6ce474 46 /**
cde2037d 47 * Class constructor.
4c6ce474 48 */
00be9182 49 public function __construct() {
6a488035
TO
50 parent::__construct();
51 }
52
53 /**
077dbf5e
CW
54 * Is CiviCase enabled?
55 *
56 * @return bool
57 */
00be9182 58 public static function enabled() {
077dbf5e
CW
59 $config = CRM_Core_Config::singleton();
60 return in_array('CiviCase', $config->enableComponents);
61 }
62
6a488035 63 /**
cde2037d 64 * Create a case object.
6a488035 65 *
cde2037d 66 * The function extracts all the params it needs to initialize the create a
6a488035
TO
67 * case object. the params array could contain additional unused name/value
68 * pairs
69 *
64bd5a0e
TO
70 * @param array $params
71 * (reference ) an assoc array of name/value pairs.
77b97be7 72 *
16b10e64 73 * @return CRM_Case_BAO_Case
6a488035 74 */
00be9182 75 public static function add(&$params) {
6a488035
TO
76 $caseDAO = new CRM_Case_DAO_Case();
77 $caseDAO->copyValues($params);
da4d8910 78 $result = $caseDAO->save();
5d4fcf54
TO
79 // Get other case values (required by XML processor), this adds to $result array
80 $caseDAO->find(TRUE);
da4d8910 81 return $result;
6a488035
TO
82 }
83
6a488035 84 /**
cde2037d 85 * Takes an associative array and creates a case object.
6a488035 86 *
64bd5a0e 87 * @param array $params
cde2037d 88 * (reference) an assoc array of name/value pairs.
77b97be7 89 *
16b10e64 90 * @return CRM_Case_BAO_Case
6a488035 91 */
00be9182 92 public static function &create(&$params) {
ea6a17a9
TO
93 // CRM-20958 - These fields are managed by MySQL triggers. Watch out for clients resaving stale timestamps.
94 unset($params['created_date']);
95 unset($params['modified_date']);
3717c347
JP
96 $caseStatus = CRM_Case_PseudoConstant::caseStatus('name');
97 // for resolved case the end date should set to now
98 if (!empty($params['status_id']) && $params['status_id'] == array_search('Closed', $caseStatus)) {
99 $params['end_date'] = date("Ymd");
100 }
ea6a17a9 101
6a488035
TO
102 $transaction = new CRM_Core_Transaction();
103
a7488080 104 if (!empty($params['id'])) {
6a488035
TO
105 CRM_Utils_Hook::pre('edit', 'Case', $params['id'], $params);
106 }
107 else {
108 CRM_Utils_Hook::pre('create', 'Case', NULL, $params);
109 }
110
111 $case = self::add($params);
112
a7488080 113 if (!empty($params['custom']) &&
6a488035
TO
114 is_array($params['custom'])
115 ) {
116 CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_case', $case->id);
117 }
118
119 if (is_a($case, 'CRM_Core_Error')) {
120 $transaction->rollback();
121 return $case;
122 }
123
a7488080 124 if (!empty($params['id'])) {
6a488035
TO
125 CRM_Utils_Hook::post('edit', 'Case', $case->id, $case);
126 }
127 else {
128 CRM_Utils_Hook::post('create', 'Case', $case->id, $case);
129 }
130 $transaction->commit();
131
132 //we are not creating log for case
133 //since case log can be tracked using log for activity.
134 return $case;
135 }
136
6a488035 137 /**
100fef9d 138 * Process case activity add/delete
6a488035
TO
139 * takes an associative array and
140 *
64bd5a0e
TO
141 * @param array $params
142 * (reference ) an assoc array of name/value pairs.
6a488035 143 *
6a488035 144 */
00be9182 145 public static function processCaseActivity(&$params) {
6a488035
TO
146 $caseActivityDAO = new CRM_Case_DAO_CaseActivity();
147 $caseActivityDAO->activity_id = $params['activity_id'];
148 $caseActivityDAO->case_id = $params['case_id'];
149
150 $caseActivityDAO->find(TRUE);
151 $caseActivityDAO->save();
152 }
153
154 /**
cde2037d 155 * Get the case subject for Activity.
6a488035 156 *
64bd5a0e
TO
157 * @param int $activityId
158 * Activity id.
6a488035 159 *
2b37475d 160 * @return string|null
6a488035 161 */
00be9182 162 public static function getCaseSubject($activityId) {
6a488035
TO
163 $caseActivity = new CRM_Case_DAO_CaseActivity();
164 $caseActivity->activity_id = $activityId;
165 if ($caseActivity->find(TRUE)) {
166 return CRM_Core_DAO::getFieldValue('CRM_Case_BAO_Case', $caseActivity->case_id, 'subject');
167 }
168 return NULL;
169 }
170
171 /**
100fef9d 172 * Get the case type.
6a488035
TO
173 *
174 * @param int $caseId
77b97be7
EM
175 * @param string $colName
176 *
a6c01b45
CW
177 * @return string
178 * case type
6a488035 179 */
00be9182 180 public static function getCaseType($caseId, $colName = 'title') {
8ffdec17
ARW
181 $query = "
182SELECT civicrm_case_type.{$colName} FROM civicrm_case
183LEFT JOIN civicrm_case_type ON
184 civicrm_case.case_type_id = civicrm_case_type.id
185WHERE civicrm_case.id = %1";
6a488035 186
8ffdec17 187 $queryParams = array(1 => array($caseId, 'Integer'));
6a488035 188
8ffdec17 189 return CRM_Core_DAO::singleValueQuery($query, $queryParams);
6a488035
TO
190 }
191
192 /**
d2e5d2ce 193 * Delete the record that are associated with this case.
6a488035
TO
194 * record are deleted from case
195 *
64bd5a0e
TO
196 * @param int $caseId
197 * Id of the case to delete.
6a488035 198 *
77b97be7
EM
199 * @param bool $moveToTrash
200 *
a6c01b45
CW
201 * @return bool
202 * is successful
6a488035 203 */
00be9182 204 public static function deleteCase($caseId, $moveToTrash = FALSE) {
6a488035
TO
205 CRM_Utils_Hook::pre('delete', 'Case', $caseId, CRM_Core_DAO::$_nullArray);
206
207 //delete activities
208 $activities = self::getCaseActivityDates($caseId);
209 if ($activities) {
210 foreach ($activities as $value) {
211 CRM_Activity_BAO_Activity::deleteActivity($value, $moveToTrash);
212 }
213 }
214
215 if (!$moveToTrash) {
216 $transaction = new CRM_Core_Transaction();
217 }
218 $case = new CRM_Case_DAO_Case();
219 $case->id = $caseId;
220 if (!$moveToTrash) {
221 $result = $case->delete();
222 $transaction->commit();
223 }
224 else {
225 $result = $case->is_deleted = 1;
226 $case->save();
227 }
228
229 if ($result) {
230 // CRM-7364, disable relationships
231 self::enableDisableCaseRelationships($caseId, FALSE);
232
233 CRM_Utils_Hook::post('delete', 'Case', $caseId, $case);
234
235 // remove case from recent items.
236 $caseRecent = array(
237 'id' => $caseId,
238 'type' => 'Case',
239 );
240 CRM_Utils_Recent::del($caseRecent);
241 return TRUE;
242 }
243
244 return FALSE;
245 }
246
247 /**
cde2037d 248 * Enable disable case related relationships.
6a488035 249 *
64bd5a0e
TO
250 * @param int $caseId
251 * Case id.
252 * @param bool $enable
253 * Action.
6a488035 254 */
00be9182 255 public static function enableDisableCaseRelationships($caseId, $enable) {
6a488035
TO
256 $contactIds = self::retrieveContactIdsByCaseId($caseId);
257 if (!empty($contactIds)) {
258 foreach ($contactIds as $cid) {
259 $roles = self::getCaseRoles($cid, $caseId);
260 if (!empty($roles)) {
261 $relationshipIds = implode(',', array_keys($roles));
e96f025a 262 $enable = (int) $enable;
263 $query = "UPDATE civicrm_relationship SET is_active = {$enable}
6a488035
TO
264 WHERE id IN ( {$relationshipIds} )";
265 CRM_Core_DAO::executeQuery($query);
266 }
267 }
268 }
269 }
270
6a488035 271 /**
fe482240 272 * Retrieve contact_id by case_id.
6a488035 273 *
64bd5a0e
TO
274 * @param int $caseId
275 * ID of the case.
77b97be7 276 *
100fef9d 277 * @param int $contactID
ea2aa8ff 278 * @param int $startArrayAt This is to support legacy calls to Case.Get API which may rely on the first array index being set to 1
6a488035
TO
279 *
280 * @return array
6a488035 281 */
ea2aa8ff 282 public static function retrieveContactIdsByCaseId($caseId, $contactID = NULL, $startArrayAt = 0) {
6a488035
TO
283 $caseContact = new CRM_Case_DAO_CaseContact();
284 $caseContact->case_id = $caseId;
285 $caseContact->find();
286 $contactArray = array();
ea2aa8ff 287 $count = $startArrayAt;
6a488035
TO
288 while ($caseContact->fetch()) {
289 if ($contactID != $caseContact->contact_id) {
290 $contactArray[$count] = $caseContact->contact_id;
291 $count++;
292 }
293 }
294
295 return $contactArray;
296 }
297
298 /**
cde2037d 299 * Look up a case using an activity ID.
6a488035 300 *
100fef9d 301 * @param int $activityId
77b97be7 302 *
6a488035
TO
303 * @return int, case ID
304 */
00be9182 305 public static function getCaseIdByActivityId($activityId) {
6a488035
TO
306 $originalId = CRM_Core_DAO::singleValueQuery(
307 'SELECT original_id FROM civicrm_activity WHERE id = %1',
308 array('1' => array($activityId, 'Integer'))
309 );
310 $caseId = CRM_Core_DAO::singleValueQuery(
311 'SELECT case_id FROM civicrm_case_activity WHERE activity_id in (%1,%2)',
312 array(
313 '1' => array($activityId, 'Integer'),
314 '2' => array($originalId ? $originalId : $activityId, 'Integer'),
315 )
316 );
317 return $caseId;
318 }
319
320 /**
d2e5d2ce 321 * Retrieve contact names by caseId.
6a488035 322 *
64bd5a0e
TO
323 * @param int $caseId
324 * ID of the case.
6a488035
TO
325 *
326 * @return array
6a488035 327 */
00be9182 328 public static function getContactNames($caseId) {
6a488035
TO
329 $contactNames = array();
330 if (!$caseId) {
331 return $contactNames;
332 }
333
334 $query = "
335 SELECT contact_a.sort_name name,
336 contact_a.display_name as display_name,
337 contact_a.id cid,
338 contact_a.birth_date as birth_date,
339 ce.email as email,
340 cp.phone as phone
341 FROM civicrm_contact contact_a
342 LEFT JOIN civicrm_case_contact ON civicrm_case_contact.contact_id = contact_a.id
343 LEFT JOIN civicrm_email ce ON ( ce.contact_id = contact_a.id AND ce.is_primary = 1)
344 LEFT JOIN civicrm_phone cp ON ( cp.contact_id = contact_a.id AND cp.is_primary = 1)
6b576a7c 345 WHERE contact_a.is_deleted = 0 AND civicrm_case_contact.case_id = %1
78762324 346 ORDER BY civicrm_case_contact.id";
6a488035
TO
347
348 $dao = CRM_Core_DAO::executeQuery($query,
349 array(1 => array($caseId, 'Integer'))
350 );
351 while ($dao->fetch()) {
352 $contactNames[$dao->cid]['contact_id'] = $dao->cid;
353 $contactNames[$dao->cid]['sort_name'] = $dao->name;
354 $contactNames[$dao->cid]['display_name'] = $dao->display_name;
355 $contactNames[$dao->cid]['email'] = $dao->email;
356 $contactNames[$dao->cid]['phone'] = $dao->phone;
357 $contactNames[$dao->cid]['birth_date'] = $dao->birth_date;
358 $contactNames[$dao->cid]['role'] = ts('Client');
359 }
360
361 return $contactNames;
362 }
363
364 /**
cde2037d 365 * Retrieve case_id by contact_id.
6a488035 366 *
100fef9d 367 * @param int $contactID
64bd5a0e
TO
368 * @param bool $includeDeleted
369 * Include the deleted cases in result.
77b97be7
EM
370 * @param null $caseType
371 *
6a488035 372 * @return array
6a488035 373 */
00be9182 374 public static function retrieveCaseIdsByContactId($contactID, $includeDeleted = FALSE, $caseType = NULL) {
6a488035
TO
375 $query = "
376SELECT ca.id as id
377FROM civicrm_case_contact cc
378INNER JOIN civicrm_case ca ON cc.case_id = ca.id
6a488035 379";
1d8da9d9
DJ
380 if (isset($caseType)) {
381 $query .=
76304e2f 382 "INNER JOIN civicrm_case_type ON civicrm_case_type.id = ca.case_type_id
8ffdec17 383WHERE cc.contact_id = %1 AND civicrm_case_type.name = '{$caseType}'";
1d8da9d9 384 }
a2da6067
DJ
385 if (!isset($caseType)) {
386 $query .= "WHERE cc.contact_id = %1";
387 }
6a488035
TO
388 if (!$includeDeleted) {
389 $query .= " AND ca.is_deleted = 0";
390 }
391
392 $params = array(1 => array($contactID, 'Integer'));
393 $dao = CRM_Core_DAO::executeQuery($query, $params);
394
395 $caseArray = array();
396 while ($dao->fetch()) {
397 $caseArray[] = $dao->id;
398 }
399
6a488035
TO
400 return $caseArray;
401 }
402
4c6ce474
EM
403 /**
404 * @param string $type
100fef9d 405 * @param int $userID
d6eb0c11 406 * @param string $condition
4c6ce474
EM
407 *
408 * @return string
409 */
5f1c8c57 410 public static function getCaseActivityCountQuery($type = 'upcoming', $userID, $condition = NULL) {
411 return sprintf(" SELECT COUNT(*) FROM (%s) temp ", self::getCaseActivityQuery($type, $userID, $condition));
412 }
6a488035 413
5f1c8c57 414 /**
415 * @param string $type
416 * @param int $userID
417 * @param string $condition
418 * @param string $limit
f157740d 419 * @param string $order
5f1c8c57 420 *
421 * @return string
422 */
423 public static function getCaseActivityQuery($type = 'upcoming', $userID, $condition = NULL, $limit = NULL, $order = NULL) {
424 $selectClauses = array(
425 'civicrm_case.id as case_id',
426 'civicrm_case.subject as case_subject',
427 'civicrm_contact.id as contact_id',
428 'civicrm_contact.sort_name as sort_name',
429 'civicrm_phone.phone as phone',
430 'civicrm_contact.contact_type as contact_type',
431 'civicrm_contact.contact_sub_type as contact_sub_type',
432 't_act.activity_type_id',
433 'c_type.title as case_type',
434 'civicrm_case.case_type_id as case_type_id',
435 'cov_status.label as case_status',
436 'cov_status.label as case_status_name',
437 't_act.status_id',
438 'civicrm_case.start_date as case_start_date',
439 'case_relation_type.label_b_a as case_role',
440 );
6a488035
TO
441
442 if ($type == 'upcoming') {
5f1c8c57 443 $selectClauses = array_merge($selectClauses, array(
444 't_act.desired_date as case_scheduled_activity_date',
445 't_act.id as case_scheduled_activity_id',
446 't_act.act_type_name as case_scheduled_activity_type_name',
447 't_act.act_type AS case_scheduled_activity_type',
448 ));
6a488035
TO
449 }
450 elseif ($type == 'recent') {
5f1c8c57 451 $selectClauses = array_merge($selectClauses, array(
452 't_act.desired_date as case_recent_activity_date',
453 't_act.id as case_recent_activity_id',
454 't_act.act_type_name as case_recent_activity_type_name',
455 't_act.act_type AS case_recent_activity_type',
456 ));
6a488035 457 }
76304e2f 458 elseif ($type == 'any') {
5f1c8c57 459 $selectClauses = array_merge($selectClauses, array(
460 't_act.desired_date as case_activity_date',
461 't_act.id as case_activity_id',
462 't_act.act_type_name as case_activity_type_name',
463 't_act.act_type AS case_activity_type',
464 ));
90319720 465 }
6a488035 466
5f1c8c57 467 $query = CRM_Contact_BAO_Query::appendAnyValueToSelect($selectClauses, 'case_id');
468
6a488035
TO
469 $query .= " FROM civicrm_case
470 INNER JOIN civicrm_case_contact ON civicrm_case.id = civicrm_case_contact.case_id
471 INNER JOIN civicrm_contact ON civicrm_case_contact.contact_id = civicrm_contact.id ";
472
473 if ($type == 'upcoming') {
474 // This gets the earliest activity per case that's scheduled within 14 days from now.
475 // Note we have an inner select to get the min activity id in order to remove duplicates in case there are two with the same datetime.
476 // In this case we don't really care which one, so min(id) works.
477 // optimized in CRM-11837
478 $query .= " INNER JOIN
479(
480 SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type
481 FROM (
482 SELECT *
483 FROM (
484 SELECT *
485 FROM civicrm_view_case_activity_upcoming
486 ORDER BY activity_date_time ASC, id ASC
487 ) AS upcomingOrdered
6a488035
TO
488 ) AS act
489 LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
490 LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id )
491) AS t_act
492";
493 }
494 elseif ($type == 'recent') {
495 // Similarly, the most recent activity in the past 14 days, and exclude scheduled.
496 //improve query performance - CRM-10598
497 $query .= " INNER JOIN
498(
499 SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type
500 FROM (
501 SELECT *
502 FROM (
503 SELECT *
504 FROM civicrm_view_case_activity_recent
505 ORDER BY activity_date_time DESC, id ASC
506 ) AS recentOrdered
6a488035
TO
507 ) AS act
508LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
509 LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id )
510) AS t_act ";
511 }
76304e2f 512 elseif ($type == 'any') {
90319720
BS
513 $query .= " LEFT JOIN
514(
515 SELECT ca4.case_id, act4.id AS id, act4.activity_date_time AS desired_date, act4.activity_type_id, act4.status_id, aov.name AS act_type_name, aov.label AS act_type
516 FROM civicrm_activity act4
517 LEFT JOIN civicrm_case_activity ca4
518 ON ca4.activity_id = act4.id
519 AND act4.is_current_revision = 1
520 LEFT JOIN civicrm_option_group aog
521 ON aog.name='activity_type'
522 LEFT JOIN civicrm_option_value aov
523 ON aov.option_group_id = aog.id
524 AND aov.value = act4.activity_type_id
525) AS t_act";
526 }
6a488035
TO
527
528 $query .= "
529 ON t_act.case_id = civicrm_case.id
530 LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary=1)
531 LEFT JOIN civicrm_relationship case_relationship
66f47235 532 ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active AND case_relationship.case_id = civicrm_case.id )
6a488035
TO
533 LEFT JOIN civicrm_relationship_type case_relation_type
534 ON ( case_relation_type.id = case_relationship.relationship_type_id
535 AND case_relation_type.id = case_relationship.relationship_type_id )
536
8ffdec17
ARW
537 LEFT JOIN civicrm_case_type c_type
538 ON civicrm_case.case_type_id = c_type.id
6a488035
TO
539
540 LEFT JOIN civicrm_option_group cog_status
541 ON cog_status.name = 'case_status'
542
543 LEFT JOIN civicrm_option_value cov_status
544 ON ( civicrm_case.status_id = cov_status.value
545 AND cog_status.id = cov_status.option_group_id )
546";
547
548 if ($condition) {
549 // CRM-8749 backwards compatibility - callers of this function expect to start $condition with "AND"
5f1c8c57 550 $query .= " WHERE (1) AND $condition ";
6a488035 551 }
5f1c8c57 552 $query .= " GROUP BY case_id ";
6a488035 553
5f1c8c57 554 if ($order) {
555 $query .= $order;
6a488035 556 }
5f1c8c57 557 else {
558 if ($type == 'upcoming') {
559 $query .= " ORDER BY case_scheduled_activity_date ASC ";
560 }
561 elseif ($type == 'recent') {
562 $query .= " ORDER BY case_recent_activity_date ASC ";
563 }
564 elseif ($type == 'any') {
565 $query .= " ORDER BY case_activity_date ASC ";
566 }
6a488035 567 }
5f1c8c57 568
569 if ($limit) {
570 $query .= $limit;
90319720 571 }
6a488035
TO
572
573 return $query;
574 }
575
576 /**
cde2037d 577 * Retrieve cases related to particular contact or whole contact used in Dashboard and Tab.
6a488035 578 *
64bd5a0e 579 * @param bool $allCases
5f1c8c57 580 * @param array $params
77b97be7 581 * @param string $context
5f1c8c57 582 * @param bool $getCount
77b97be7 583 *
a6c01b45
CW
584 * @return array
585 * Array of Cases
6a488035 586 */
5f1c8c57 587 public static function getCases($allCases = TRUE, $params = array(), $context = 'dashboard', $getCount = FALSE) {
6a488035
TO
588 $condition = NULL;
589 $casesList = array();
590
d83ee565 591 // validate access for own cases.
6a488035 592 if (!self::accessCiviCase()) {
5f1c8c57 593 return $getCount ? 0 : $casesList;
6a488035
TO
594 }
595
d83ee565
MWMC
596 // Return cached value instead of re-running query
597 if (isset(Civi::$statics[__CLASS__]['totalCount']) && $getCount) {
598 return Civi::$statics[__CLASS__]['totalCount'];
599 }
600
5f1c8c57 601 $type = CRM_Utils_Array::value('type', $params, 'upcoming');
602 $userID = CRM_Core_Session::singleton()->get('userID');
603
604 $caseActivityTypeColumn = 'case_activity_type_name';
605 $caseActivityDateColumn = 'case_activity_date';
606 $caseActivityIDColumn = 'case_activity_id';
607 if ($type == 'upcoming') {
608 $caseActivityDateColumn = 'case_scheduled_activity_date';
609 $caseActivityTypeColumn = 'case_scheduled_activity_type';
610 $caseActivityIDColumn = 'case_scheduled_activity_id';
611 }
612 elseif ($type == 'recent') {
613 $caseActivityDateColumn = 'case_recent_activity_date';
614 $caseActivityTypeColumn = 'case_recent_activity_type';
615 $caseActivityIDColumn = 'case_recent_activity_id';
6a488035
TO
616 }
617
d83ee565 618 // validate access for all cases.
6a488035
TO
619 if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) {
620 $allCases = FALSE;
621 }
622
5f1c8c57 623 $whereClauses = array('civicrm_case.is_deleted = 0 AND civicrm_contact.is_deleted <> 1');
6a488035
TO
624
625 if (!$allCases) {
a5a3c752 626 $whereClauses[] .= " case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
6a488035 627 }
5f1c8c57 628 if (empty($params['status_id']) && ($type == 'upcoming' || $type == 'any')) {
629 $whereClauses[] = " civicrm_case.status_id != " . CRM_Core_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Closed');
6a488035
TO
630 }
631
5f1c8c57 632 foreach (array('case_type_id', 'status_id') as $column) {
633 if (!empty($params[$column])) {
634 $whereClauses[] = sprintf("civicrm_case.%s IN (%s)", $column, $params[$column]);
635 }
636 }
637 $condition = implode(' AND ', $whereClauses);
6a488035 638
d83ee565 639 Civi::$statics[__CLASS__]['totalCount'] = $totalCount = CRM_Core_DAO::singleValueQuery(self::getCaseActivityCountQuery($type, $userID, $condition));
5f1c8c57 640 if ($getCount) {
641 return $totalCount;
6a488035 642 }
5f1c8c57 643 $casesList['total'] = $totalCount;
644
645 $limit = '';
646 if (!empty($params['rp'])) {
647 $params['offset'] = ($params['page'] - 1) * $params['rp'];
648 $params['rowCount'] = $params['rp'];
649 if (!empty($params['rowCount']) && $params['rowCount'] > 0) {
650 $limit = " LIMIT {$params['offset']}, {$params['rowCount']} ";
651 }
6a488035 652 }
5f1c8c57 653
654 $order = NULL;
655 if (!empty($params['sortBy'])) {
656 if (strstr($params['sortBy'], 'date ')) {
657 $params['sortBy'] = str_replace('date', $caseActivityDateColumn, $params['sortBy']);
658 }
659 $order = "ORDER BY " . $params['sortBy'];
90319720 660 }
6a488035 661
5f1c8c57 662 $query = self::getCaseActivityQuery($type, $userID, $condition, $limit, $order);
663 $result = CRM_Core_DAO::executeQuery($query);
664
665 $caseStatus = CRM_Core_OptionGroup::values('case_status', FALSE, FALSE, FALSE, " AND v.name = 'Urgent' ");
666
6a488035
TO
667 // we're going to use the usual actions, so doesn't make sense to duplicate definitions
668 $actions = CRM_Case_Selector_Search::links();
669
6a488035
TO
670 // check is the user has view/edit signer permission
671 $permissions = array(CRM_Core_Permission::VIEW);
672 if (CRM_Core_Permission::check('access all cases and activities') ||
673 (!$allCases && CRM_Core_Permission::check('access my cases and activities'))
674 ) {
675 $permissions[] = CRM_Core_Permission::EDIT;
676 }
677 if (CRM_Core_Permission::check('delete in CiviCase')) {
678 $permissions[] = CRM_Core_Permission::DELETE;
679 }
680 $mask = CRM_Core_Action::mask($permissions);
681
5f1c8c57 682 $caseTypes = CRM_Case_PseudoConstant::caseType('name');
bf5990e7 683 foreach ($result->fetchAll() as $case) {
684 $key = $case['case_id'];
5f1c8c57 685 $casesList[$key] = array();
686 $casesList[$key]['DT_RowId'] = $case['case_id'];
687 $casesList[$key]['DT_RowAttr'] = array('data-entity' => 'case', 'data-id' => $case['case_id']);
688 $casesList[$key]['DT_RowClass'] = "crm-entity";
689
690 $casesList[$key]['activity_list'] = sprintf('<a title="%s" class="crm-expand-row" href="%s"></a>',
691 ts('Activities'),
68167e59 692 CRM_Utils_System::url('civicrm/case/details', array('caseId' => $case['case_id'], 'cid' => $case['contact_id'], 'type' => $type))
5f1c8c57 693 );
694
695 $phone = empty($case['phone']) ? '' : '<br /><span class="description">' . $case['phone'] . '</span>';
696 $casesList[$key]['contact_id'] = sprintf('<a href="%s">%s</a>%s<br /><span class="description">%s: %d</span>',
697 CRM_Utils_System::url('civicrm/contact/view', array('cid' => $case['contact_id'])),
698 $case['sort_name'],
699 $phone,
700 ts('Case ID'),
701 $case['case_id']
702 );
703 $casesList[$key]['subject'] = $case['case_subject'];
704 $casesList[$key]['case_status'] = in_array($case['case_status'], $caseStatus) ? sprintf('<strong>%s</strong>', strtoupper($case['case_status'])) : $case['case_status'];
705 $casesList[$key]['case_type'] = $case['case_type'];
706 $casesList[$key]['case_role'] = CRM_Utils_Array::value('case_role', $case, '---');
c00bd201 707 $casesList[$key]['manager'] = self::getCaseManagerContact($caseTypes[$case['case_type_id']], $case['case_id']);
5f1c8c57 708
5f1c8c57 709 $casesList[$key]['date'] = $case[$caseActivityTypeColumn];
710 if (($actId = CRM_Utils_Array::value('case_scheduled_activity_id', $case)) ||
711 ($actId = CRM_Utils_Array::value('case_recent_activity_id', $case))
712 ) {
713 if (self::checkPermission($actId, 'view', $case['activity_type_id'], $userID)) {
714 if ($type == 'recent') {
715 $casesList[$key]['date'] = sprintf('<a class="action-item crm-hover-button" href="%s" title="%s">%s</a>',
716 CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case[$caseActivityIDColumn])),
717 ts('View activity'),
718 $case[$caseActivityTypeColumn]
719 );
6a488035
TO
720 }
721 else {
5f1c8c57 722 $status = CRM_Utils_Date::overdue($case[$caseActivityDateColumn]) ? 'status-overdue' : 'status-scheduled';
723 $casesList[$key]['date'] = sprintf('<a class="crm-popup %s" href="%s" title="%s">%s</a> &nbsp;&nbsp;',
724 $status,
725 CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case[$caseActivityIDColumn])),
726 ts('View activity'),
727 $case[$caseActivityTypeColumn]
728 );
6a488035
TO
729 }
730 }
cedb74cd 731 if (isset($case['activity_type_id']) && self::checkPermission($actId, 'edit', $case['activity_type_id'], $userID)) {
5f1c8c57 732 $casesList[$key]['date'] .= sprintf('<a class="action-item crm-hover-button" href="%s" title="%s"><i class="crm-i fa-pencil"></i></a>',
30c9a067 733 CRM_Utils_System::url('civicrm/case/activity', array('reset' => 1, 'cid' => $case['contact_id'], 'caseid' => $case['case_id'], 'action' => 'update', 'id' => $actId)),
5f1c8c57 734 ts('Edit activity')
735 );
736 }
6a488035 737 }
5f1c8c57 738 $casesList[$key]['date'] .= "<br/>" . CRM_Utils_Date::customFormat($case[$caseActivityDateColumn]);
739 $casesList[$key]['links'] = CRM_Core_Action::formLink($actions['primaryActions'], $mask,
740 array(
741 'id' => $case['case_id'],
742 'cid' => $case['contact_id'],
743 'cxt' => $context,
744 ),
745 ts('more'),
746 FALSE,
747 'case.actions.primary',
748 'Case',
749 $case['case_id']
750 );
6a488035
TO
751 }
752
753 return $casesList;
754 }
755
756 /**
100fef9d
CW
757 * Get the summary of cases counts by type and status.
758 *
759 * @param bool $allCases
100fef9d 760 * @return array
6a488035 761 */
5f1c8c57 762 public static function getCasesSummary($allCases = TRUE) {
6a488035
TO
763 $caseSummary = array();
764
765 //validate access for civicase.
766 if (!self::accessCiviCase()) {
767 return $caseSummary;
768 }
769
5f1c8c57 770 $userID = CRM_Core_Session::singleton()->get('userID');
771
6a488035
TO
772 //validate access for all cases.
773 if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) {
774 $allCases = FALSE;
775 }
776
e96f025a 777 $caseTypes = CRM_Case_PseudoConstant::caseType();
6a488035 778 $caseStatuses = CRM_Case_PseudoConstant::caseStatus();
e96f025a 779 $caseTypes = array_flip($caseTypes);
6a488035
TO
780
781 // get statuses as headers for the table
782 $url = CRM_Utils_System::url('civicrm/case/search', "reset=1&force=1&all=1&status=");
783 foreach ($caseStatuses as $key => $name) {
784 $caseSummary['headers'][$key]['status'] = $name;
785 $caseSummary['headers'][$key]['url'] = $url . $key;
786 }
787
788 // build rows with actual data
789 $rows = array();
790 $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClause = '';
791
792 if ($allCases) {
793 $userID = 'null';
794 $all = 1;
795 $case_owner = 1;
d5bea1e3 796 $myGroupByClause = ' GROUP BY civicrm_case.id';
6a488035
TO
797 }
798 else {
e96f025a 799 $all = 0;
6a488035 800 $case_owner = 2;
66f47235 801 $myCaseWhereClause = " AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
e96f025a 802 $myGroupByClause = " GROUP BY CONCAT(case_relationship.case_id,'-',case_relationship.contact_id_b)";
6a488035 803 }
3636b520 804 $myGroupByClause .= ", case_status.label, status_id, case_type_id";
6a488035 805
d5bea1e3 806 // FIXME: This query could be a lot more efficient if it used COUNT() instead of returning all rows and then counting them with php
6a488035 807 $query = "
8ffdec17
ARW
808SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
809 case_type_id, case_relationship.contact_id_b
6a488035 810 FROM civicrm_case
d5bea1e3 811 INNER JOIN civicrm_case_contact cc on cc.case_id = civicrm_case.id
8ffdec17 812 LEFT JOIN civicrm_case_type ON civicrm_case.case_type_id = civicrm_case_type.id
6a488035
TO
813 LEFT JOIN civicrm_option_group option_group_case_status ON ( option_group_case_status.name = 'case_status' )
814 LEFT JOIN civicrm_option_value case_status ON ( civicrm_case.status_id = case_status.value
815 AND option_group_case_status.id = case_status.option_group_id )
816 LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id = civicrm_case.id
aee55e82 817 AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active )
d5bea1e3 818 WHERE is_deleted = 0 AND cc.contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted <> 1)
6a488035
TO
819{$myCaseWhereClause} {$myGroupByClause}";
820
33621c4f 821 $res = CRM_Core_DAO::executeQuery($query);
6a488035 822 while ($res->fetch()) {
8cc574cf 823 if (!empty($rows[$res->case_type]) && !empty($rows[$res->case_type][$res->case_status])) {
6a488035
TO
824 $rows[$res->case_type][$res->case_status]['count'] = $rows[$res->case_type][$res->case_status]['count'] + 1;
825 }
826 else {
827 $rows[$res->case_type][$res->case_status] = array(
828 'count' => 1,
829 'url' => CRM_Utils_System::url('civicrm/case/search',
830 "reset=1&force=1&status={$res->status_id}&type={$res->case_type_id}&case_owner={$case_owner}"
831 ),
832 );
833 }
834 }
835 $caseSummary['rows'] = array_merge($caseTypes, $rows);
836
837 return $caseSummary;
838 }
839
840 /**
d2e5d2ce 841 * Get Case roles.
6a488035 842 *
64bd5a0e
TO
843 * @param int $contactID
844 * Contact id.
845 * @param int $caseID
846 * Case id.
100fef9d 847 * @param int $relationshipID
0fd841b0 848 * @param bool $activeOnly
77b97be7 849 *
a6c01b45
CW
850 * @return array
851 * case role / relationships
6a488035 852 *
6a488035 853 */
0fd841b0 854 public static function getCaseRoles($contactID, $caseID, $relationshipID = NULL, $activeOnly = TRUE) {
6a488035 855 $query = '
3b1c37fe
CW
856 SELECT rel.id as civicrm_relationship_id,
857 con.sort_name as sort_name,
6a488035
TO
858 civicrm_email.email as email,
859 civicrm_phone.phone as phone,
3b1c37fe
CW
860 con.id as civicrm_contact_id,
861 IF(rel.contact_id_a = %1, civicrm_relationship_type.label_a_b, civicrm_relationship_type.label_b_a) as relation,
862 civicrm_relationship_type.id as relation_type,
863 IF(rel.contact_id_a = %1, "a_b", "b_a") as relationship_direction
864 FROM civicrm_relationship rel
865 INNER JOIN civicrm_relationship_type ON rel.relationship_type_id = civicrm_relationship_type.id
211fe764 866 INNER JOIN civicrm_contact con ON ((con.id <> %1 AND con.id IN (rel.contact_id_a, rel.contact_id_b)) OR (con.id = %1 AND rel.contact_id_b = rel.contact_id_a AND rel.contact_id_a = %1 AND rel.is_active))
3b1c37fe
CW
867 LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = con.id AND civicrm_phone.is_primary = 1)
868 LEFT JOIN civicrm_email ON (civicrm_email.contact_id = con.id AND civicrm_email.is_primary = 1)
869 WHERE (rel.contact_id_a = %1 OR rel.contact_id_b = %1) AND rel.case_id = %2
0fd841b0
JP
870 AND con.is_deleted = 0';
871
872 if ($activeOnly) {
873 $query .= ' AND rel.is_active = 1 AND (rel.end_date IS NULL OR rel.end_date > NOW())';
874 }
6a488035 875
6a488035
TO
876 $params = array(
877 1 => array($contactID, 'Positive'),
878 2 => array($caseID, 'Positive'),
879 );
880
881 if ($relationshipID) {
a4bac981 882 $query .= ' AND rel.id = %3 ';
6a488035
TO
883 $params[3] = array($relationshipID, 'Integer');
884 }
885 $dao = CRM_Core_DAO::executeQuery($query, $params);
886
887 $values = array();
888 while ($dao->fetch()) {
889 $rid = $dao->civicrm_relationship_id;
890 $values[$rid]['cid'] = $dao->civicrm_contact_id;
891 $values[$rid]['relation'] = $dao->relation;
892 $values[$rid]['name'] = $dao->sort_name;
893 $values[$rid]['email'] = $dao->email;
894 $values[$rid]['phone'] = $dao->phone;
895 $values[$rid]['relation_type'] = $dao->relation_type;
896 $values[$rid]['rel_id'] = $dao->civicrm_relationship_id;
3b1c37fe
CW
897 $values[$rid]['client_id'] = $contactID;
898 $values[$rid]['relationship_direction'] = $dao->relationship_direction;
6a488035
TO
899 }
900
6a488035
TO
901 return $values;
902 }
903
904 /**
d2e5d2ce 905 * Get Case Activities.
6a488035 906 *
64bd5a0e
TO
907 * @param int $caseID
908 * Case id.
909 * @param array $params
910 * Posted params.
911 * @param int $contactID
912 * Contact id.
6a488035 913 *
77b97be7 914 * @param null $context
100fef9d 915 * @param int $userID
359d4010 916 * @param null $type (deprecated)
77b97be7 917 *
a6c01b45 918 * @return array
16b10e64 919 * Array of case activities
6a488035 920 *
6a488035 921 */
00be9182 922 public static function getCaseActivity($caseID, &$params, $contactID, $context = NULL, $userID = NULL, $type = NULL) {
44f817d4 923 $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
9e74e3ce 924 $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
e96f025a 925 $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
034500d4 926 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
9e74e3ce 927
6a488035
TO
928 // CRM-5081 - formatting the dates to omit seconds.
929 // Note the 00 in the date format string is needed otherwise later on it thinks scheduled ones are overdue.
ad280fb6 930 $select = "
3636b520 931 SELECT SQL_CALC_FOUND_ROWS COUNT(ca.id) AS ismultiple,
932 ca.id AS id,
933 ca.activity_type_id AS type,
934 ca.activity_type_id AS activity_type_id,
935 tcc.sort_name AS target_contact_name,
936 tcc.id AS target_contact_id,
937 scc.sort_name AS source_contact_name,
938 scc.id AS source_contact_id,
939 acc.sort_name AS assignee_contact_name,
940 acc.id AS assignee_contact_id,
941 DATE_FORMAT(
942 IF(ca.activity_date_time < NOW() AND ca.status_id=ov.value,
943 ca.activity_date_time,
944 DATE_ADD(NOW(), INTERVAL 1 YEAR)
945 ), '%Y%m%d%H%i00') AS overdue_date,
946 DATE_FORMAT(ca.activity_date_time, '%Y%m%d%H%i00') AS display_date,
947 ca.status_id AS status,
948 ca.subject AS subject,
949 ca.is_deleted AS deleted,
950 ca.priority_id AS priority,
951 ca.weight AS weight,
ad280fb6 952 GROUP_CONCAT(ef.file_id) AS attachment_ids ";
6a488035 953
e96f025a 954 $from = "
ad280fb6
JL
955 FROM civicrm_case_activity cca
956 INNER JOIN civicrm_activity ca
957 ON ca.id = cca.activity_id
958 INNER JOIN civicrm_activity_contact cas
959 ON cas.activity_id = ca.id
960 AND cas.record_type_id = {$sourceID}
961 INNER JOIN civicrm_contact scc
962 ON scc.id = cas.contact_id
963 LEFT JOIN civicrm_activity_contact caa
964 ON caa.activity_id = ca.id
965 AND caa.record_type_id = {$assigneeID}
966 LEFT JOIN civicrm_contact acc
967 ON acc.id = caa.contact_id
968 LEFT JOIN civicrm_activity_contact cat
969 ON cat.activity_id = ca.id
970 AND cat.record_type_id = {$targetID}
971 LEFT JOIN civicrm_contact tcc
972 ON tcc.id = cat.contact_id
973 INNER JOIN civicrm_option_group cog
974 ON cog.name = 'activity_type'
975 INNER JOIN civicrm_option_value cov
976 ON cov.option_group_id = cog.id
977 AND cov.value = ca.activity_type_id
978 AND cov.is_active = 1
979 LEFT JOIN civicrm_entity_file ef
980 ON ef.entity_table = 'civicrm_activity'
981 AND ef.entity_id = ca.id
982 LEFT OUTER JOIN civicrm_option_group og
983 ON og.name = 'activity_status'
984 LEFT OUTER JOIN civicrm_option_value ov
985 ON ov.option_group_id=og.id
986 AND ov.name = 'Scheduled'";
987
988 $where = '
989 WHERE cca.case_id= %1
990 AND ca.is_current_revision = 1';
991
992 if (!empty($params['source_contact_id'])) {
993 $where .= "
994 AND cas.contact_id = " . CRM_Utils_Type::escape($params['source_contact_id'], 'Integer');
6a488035
TO
995 }
996
a7488080 997 if (!empty($params['status_id'])) {
ad280fb6
JL
998 $where .= "
999 AND ca.status_id = " . CRM_Utils_Type::escape($params['status_id'], 'Integer');
6a488035
TO
1000 }
1001
a7488080 1002 if (!empty($params['activity_deleted'])) {
ad280fb6
JL
1003 $where .= "
1004 AND ca.is_deleted = 1";
6a488035
TO
1005 }
1006 else {
ad280fb6
JL
1007 $where .= "
1008 AND ca.is_deleted = 0";
6a488035
TO
1009 }
1010
a7488080 1011 if (!empty($params['activity_type_id'])) {
ad280fb6
JL
1012 $where .= "
1013 AND ca.activity_type_id = " . CRM_Utils_Type::escape($params['activity_type_id'], 'Integer');
6a488035
TO
1014 }
1015
a7488080 1016 if (!empty($params['activity_date_low'])) {
6a488035
TO
1017 $fromActivityDate = CRM_Utils_Type::escape(CRM_Utils_Date::processDate($params['activity_date_low']), 'Date');
1018 }
ad280fb6
JL
1019 if (!empty($fromActivityDate)) {
1020 $where .= "
1021 AND ca.activity_date_time >= '{$fromActivityDate}'";
1022 }
1023
a7488080 1024 if (!empty($params['activity_date_high'])) {
6a488035
TO
1025 $toActivityDate = CRM_Utils_Type::escape(CRM_Utils_Date::processDate($params['activity_date_high']), 'Date');
1026 $toActivityDate = $toActivityDate ? $toActivityDate + 235959 : NULL;
1027 }
6a488035 1028 if (!empty($toActivityDate)) {
ad280fb6
JL
1029 $where .= "
1030 AND ca.activity_date_time <= '{$toActivityDate}'";
6a488035
TO
1031 }
1032
3636b520 1033 $groupBy = "
1034 GROUP BY ca.id, tcc.id, scc.id, acc.id, ov.value";
6a488035 1035
ad280fb6
JL
1036 $sortBy = CRM_Utils_Array::value('sortBy', $params);
1037 if (!$sortBy) {
6a488035 1038 // CRM-5081 - added id to act like creation date
ad280fb6
JL
1039 $orderBy = "
1040 ORDER BY overdue_date ASC, display_date DESC, weight DESC";
6a488035
TO
1041 }
1042 else {
ad280fb6
JL
1043 $sortBy = CRM_Utils_Type::escape($sortBy, 'String');
1044 $orderBy = " ORDER BY $sortBy ";
6a488035
TO
1045 }
1046
3fff685f
JL
1047 $page = CRM_Utils_Array::value('page', $params);
1048 $rp = CRM_Utils_Array::value('rp', $params);
1049
6a488035 1050 if (!$page) {
6a488035 1051 $page = 1;
6a488035
TO
1052 }
1053 if (!$rp) {
1054 $rp = 10;
1055 }
6a488035 1056 $start = (($page - 1) * $rp);
ad280fb6 1057 $limit = " LIMIT $start, $rp";
6a488035 1058
ad280fb6 1059 $query = $select . $from . $where . $groupBy . $orderBy . $limit;
3fff685f 1060 $queryParams = array(1 => array($caseID, 'Integer'));
6a488035 1061
3fff685f 1062 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
24963ae3 1063 $caseCount = CRM_Core_DAO::singleValueQuery('SELECT FOUND_ROWS()');
ad280fb6 1064
e96f025a 1065 $activityTypes = CRM_Case_PseudoConstant::caseActivityType(FALSE, TRUE);
6a488035 1066
0dba8ce1
JP
1067 $compStatusValues = array_keys(
1068 CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::COMPLETED) +
1069 CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::CANCELLED)
1070 );
ad280fb6 1071
6a488035 1072 if (!$userID) {
830bab40 1073 $userID = CRM_Core_Session::getLoggedInContactID();
6a488035
TO
1074 }
1075
830bab40 1076 $caseActivities = [];
ad280fb6 1077
6a488035 1078 while ($dao->fetch()) {
ad280fb6 1079 $caseActivityId = $dao->id;
6a488035 1080
830bab40
MWMC
1081 //Do we have permission to access given case activity record.
1082 if (!self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID)) {
6a488035
TO
1083 continue;
1084 }
1085
359d4010 1086 $caseActivities[$caseActivityId]['DT_RowId'] = $caseActivityId;
ad280fb6 1087 //Add classes to the row, via DataTables syntax
359d4010 1088 $caseActivities[$caseActivityId]['DT_RowClass'] = "crm-entity status-id-$dao->status";
6a488035 1089
ad280fb6 1090 if (CRM_Utils_Array::crmInArray($dao->status, $compStatusValues)) {
359d4010 1091 $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-completed";
6a488035 1092 }
ad280fb6
JL
1093 else {
1094 if (CRM_Utils_Date::overdue($dao->display_date)) {
359d4010 1095 $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-overdue";
ad280fb6
JL
1096 }
1097 else {
359d4010 1098 $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-scheduled";
6a488035
TO
1099 }
1100 }
ad280fb6
JL
1101
1102 if (!empty($dao->priority)) {
0571e734 1103 if ($dao->priority == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'priority_id', 'Urgent')) {
359d4010 1104 $caseActivities[$caseActivityId]['DT_RowClass'] .= " priority-urgent ";
ad280fb6 1105 }
0571e734 1106 elseif ($dao->priority == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'priority_id', 'Low')) {
359d4010 1107 $caseActivities[$caseActivityId]['DT_RowClass'] .= " priority-low ";
6a488035 1108 }
6a488035 1109 }
6a488035 1110
ad280fb6 1111 //Add data to the row for inline editing, via DataTable syntax
359d4010
MW
1112 $caseActivities[$caseActivityId]['DT_RowAttr'] = array();
1113 $caseActivities[$caseActivityId]['DT_RowAttr']['data-entity'] = 'activity';
1114 $caseActivities[$caseActivityId]['DT_RowAttr']['data-id'] = $caseActivityId;
6a488035 1115
ad280fb6 1116 //Activity Date and Time
359d4010 1117 $caseActivities[$caseActivityId]['activity_date_time'] = CRM_Utils_Date::customFormat($dao->display_date);
6a488035 1118
ad280fb6 1119 //Activity Subject
359d4010 1120 $caseActivities[$caseActivityId]['subject'] = $dao->subject;
ad280fb6
JL
1121
1122 //Activity Type
359d4010 1123 $caseActivities[$caseActivityId]['type'] = (!empty($activityTypes[$dao->type]['icon']) ? '<span class="crm-i ' . $activityTypes[$dao->type]['icon'] . '"></span> ' : '')
8c99c0bb 1124 . $activityTypes[$dao->type]['label'];
ad280fb6 1125
359d4010
MW
1126 // Activity Target (With Contact) (There can be more than one)
1127 $targetContact = self::formatContactLink($dao->target_contact_id, $dao->target_contact_name);
1128 if (empty($caseActivities[$caseActivityId]['target_contact_name'])) {
1129 $caseActivities[$caseActivityId]['target_contact_name'] = $targetContact;
1130 }
1131 else {
1132 if (strpos($caseActivities[$caseActivityId]['target_contact_name'], $targetContact) === FALSE) {
1133 $caseActivities[$caseActivityId]['target_contact_name'] .= '; ' . $targetContact;
6a488035 1134 }
ad280fb6 1135 }
ad280fb6 1136
359d4010
MW
1137 // Activity Source Contact (Reporter) (There can only be one)
1138 $sourceContact = self::formatContactLink($dao->source_contact_id, $dao->source_contact_name);
1139 $caseActivities[$caseActivityId]['source_contact_name'] = $sourceContact;
1140
1141 // Activity Assignee (There can be more than one)
1142 $assigneeContact = self::formatContactLink($dao->assignee_contact_id, $dao->assignee_contact_name);
1143 if (empty($caseActivities[$caseActivityId]['assignee_contact_name'])) {
1144 $caseActivities[$caseActivityId]['assignee_contact_name'] = $assigneeContact;
ad280fb6 1145 }
359d4010
MW
1146 else {
1147 if (strpos($caseActivities[$caseActivityId]['assignee_contact_name'], $assigneeContact) === FALSE) {
1148 $caseActivities[$caseActivityId]['assignee_contact_name'] .= '; ' . $assigneeContact;
6a488035
TO
1149 }
1150 }
ad280fb6 1151
b864360d
MWMC
1152 // Activity Status Label for Case activities list
1153 $caseActivities[$caseActivityId]['status_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_status_id', $dao->status);
ad280fb6 1154
830bab40
MWMC
1155 $caseActivities[$caseActivityId]
1156 = self::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivities[$caseActivityId]);
6a488035 1157 }
6a488035 1158
ad280fb6 1159 $caseActivitiesDT = array();
359d4010 1160 $caseActivitiesDT['data'] = array_values($caseActivities);
3fff685f
JL
1161 $caseActivitiesDT['recordsTotal'] = $caseCount;
1162 $caseActivitiesDT['recordsFiltered'] = $caseCount;
ad280fb6
JL
1163
1164 return $caseActivitiesDT;
6a488035
TO
1165 }
1166
830bab40
MWMC
1167 /**
1168 * FIXME: This is a transitional function to facilitate a refactor of this to use CRM_Core_Action and actionLinks
1169 * Add the set of "actionLinks" to the case activity
1170 *
1171 * @param int $caseID
1172 * @param int $contactID
1173 * @param int $userID
1174 * @param string $context
1175 * @param \CRM_Core_DAO $dao
1176 * @param array $caseActivity
1177 *
1178 * @return array caseActivity
1179 */
1180 public static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivity) {
1181 // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup.
1182 $caseActivityId = $dao->id;
1183 $allowView = self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID);
1184 $allowEdit = self::checkPermission($caseActivityId, 'edit', $dao->activity_type_id, $userID);
1185 $allowDelete = self::checkPermission($caseActivityId, 'delete', $dao->activity_type_id, $userID);
1186 $emailActivityTypeIDs = [
1187 'Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email'),
1188 'Inbound Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'),
1189 ];
1190 $url = CRM_Utils_System::url("civicrm/case/activity",
1191 "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE
1192 );
1193 $contextUrl = '';
1194 if ($context == 'fulltext') {
1195 $contextUrl = "&context={$context}";
1196 }
1197 $editUrl = "{$url}&action=update{$contextUrl}";
1198 $deleteUrl = "{$url}&action=delete{$contextUrl}";
1199 $restoreUrl = "{$url}&action=renew{$contextUrl}";
1200 $viewTitle = ts('View activity');
1201 $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted');
1202
1203 $url = "";
1204 $css = 'class="action-item crm-hover-button"';
1205 if ($allowView) {
1206 $viewUrl = CRM_Utils_System::url('civicrm/case/activity/view', array('cid' => $contactID, 'aid' => $caseActivityId));
1207 $url = '<a ' . str_replace('action-item', 'action-item medium-pop-up', $css) . 'href="' . $viewUrl . '" title="' . $viewTitle . '">' . ts('View') . '</a>';
1208 }
1209 $additionalUrl = "&id={$caseActivityId}";
1210 if (!$dao->deleted) {
1211 //hide edit link of activity type email.CRM-4530.
1212 if (!in_array($dao->type, $emailActivityTypeIDs)) {
1213 //hide Edit link if activity type is NOT editable (special case activities).CRM-5871
1214 if ($allowEdit) {
1215 $url .= '<a ' . $css . ' href="' . $editUrl . $additionalUrl . '">' . ts('Edit') . '</a> ';
1216 }
1217 }
1218 if ($allowDelete) {
1219 $url .= ' <a ' . str_replace('action-item', 'action-item small-popup', $css) . ' href="' . $deleteUrl . $additionalUrl . '">' . ts('Delete') . '</a>';
1220 }
1221 }
1222 elseif (!$caseDeleted) {
1223 $url = ' <a ' . $css . ' href="' . $restoreUrl . $additionalUrl . '">' . ts('Restore') . '</a>';
1224 $caseActivity['status_id'] = $caseActivity['status_id'] . '<br /> (deleted)';
1225 }
1226
1227 //check for operations.
1228 if (self::checkPermission($caseActivityId, 'Move To Case', $dao->activity_type_id)) {
1229 $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'move\',' . $caseActivityId . ', ' . $caseID . ', this ); return false;">' . ts('Move To Case') . '</a> ';
1230 }
1231 if (self::checkPermission($caseActivityId, 'Copy To Case', $dao->activity_type_id)) {
1232 $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'copy\',' . $caseActivityId . ',' . $caseID . ', this ); return false;">' . ts('Copy To Case') . '</a> ';
1233 }
1234 // if there are file attachments we will return how many and, if only one, add a link to it
1235 if (!empty($dao->attachment_ids)) {
1236 $attachmentIDs = array_unique(explode(',', $dao->attachment_ids));
1237 $caseActivity['no_attachments'] = count($attachmentIDs);
1238 $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId));
1239 }
1240 $caseActivity['links'] = $url;
1241 return $caseActivity;
1242 }
1243
359d4010
MW
1244 /**
1245 * Helper function to generate a formatted contact link/name for display in the Case activities tab
1246 *
1247 * @param $contactId
1248 * @param $contactName
1249 *
1250 * @return string
1251 */
1252 private static function formatContactLink($contactId, $contactName) {
1253 if (empty($contactId)) {
1254 return NULL;
1255 }
1256
1257 $hasViewContact = CRM_Contact_BAO_Contact_Permission::allow($contactId);
1258
1259 if ($hasViewContact) {
1260 $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid={$contactId}");
1261 return "<a href=\"{$contactViewUrl}\">" . $contactName . "</a>";
1262 }
1263 else {
1264 return $contactName;
1265 }
1266 }
1267
6a488035 1268 /**
d2e5d2ce 1269 * Get Case Related Contacts.
6a488035 1270 *
64bd5a0e
TO
1271 * @param int $caseID
1272 * Case id.
b982dca0 1273 * @param bool $includeDetails
64bd5a0e 1274 * If true include details of contacts.
6a488035 1275 *
a6c01b45
CW
1276 * @return array
1277 * array of return properties
6a488035 1278 *
6a488035 1279 */
b982dca0 1280 public static function getRelatedContacts($caseID, $includeDetails = TRUE) {
69f9c562 1281 $caseRoles = array();
b982dca0 1282 if ($includeDetails) {
0ab56350 1283 $caseInfo = civicrm_api3('Case', 'getsingle', array(
69f9c562 1284 'id' => $caseID,
b982dca0 1285 // Most efficient way of retrieving definition is to also include case type id and name so the api doesn't have to look it up separately
0ab56350 1286 'return' => array('case_type_id', 'case_type_id.name', 'case_type_id.definition'),
69f9c562
CW
1287 ));
1288 if (!empty($caseInfo['case_type_id.definition']['caseRoles'])) {
1289 $caseRoles = CRM_Utils_Array::rekey($caseInfo['case_type_id.definition']['caseRoles'], 'name');
1290 }
1291 }
6a488035 1292 $values = array();
68783143 1293 $query = '
a0c7081b 1294 SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_b_a as role, crt.name_b_a, ce.email, cp.phone
68783143
BS
1295 FROM civicrm_relationship cr
1296 LEFT JOIN civicrm_relationship_type crt
1297 ON crt.id = cr.relationship_type_id
1298 LEFT JOIN civicrm_contact cc
1299 ON cc.id = cr.contact_id_b
1300 LEFT JOIN civicrm_email ce
1301 ON ce.contact_id = cc.id
1302 AND ce.is_primary= 1
a0c7081b
CW
1303 LEFT JOIN civicrm_phone cp
1304 ON cp.contact_id = cc.id
1305 AND cp.is_primary= 1
7a51786d 1306 WHERE cr.case_id = %1 AND cr.is_active AND cc.is_deleted <> 1';
6a488035
TO
1307
1308 $params = array(1 => array($caseID, 'Integer'));
1309 $dao = CRM_Core_DAO::executeQuery($query, $params);
1310
1311 while ($dao->fetch()) {
b982dca0 1312 if (!$includeDetails) {
6a488035
TO
1313 $values[$dao->id] = 1;
1314 }
1315 else {
69f9c562 1316 $details = array(
6a488035
TO
1317 'contact_id' => $dao->id,
1318 'display_name' => $dao->name,
1319 'sort_name' => $dao->sort_name,
69f9c562 1320 'relationship_type_id' => $dao->relationship_type_id,
6a488035
TO
1321 'role' => $dao->role,
1322 'email' => $dao->email,
a0c7081b 1323 'phone' => $dao->phone,
6a488035 1324 );
b982dca0 1325 // Add more info about the role (creator, manager)
c2c37497 1326 $role = CRM_Utils_Array::value($dao->name_b_a, $caseRoles);
69f9c562
CW
1327 if ($role) {
1328 unset($role['name']);
1329 $details += $role;
1330 }
1331 $values[] = $details;
6a488035
TO
1332 }
1333 }
6a488035
TO
1334
1335 return $values;
1336 }
1337
1338 /**
100fef9d 1339 * Send e-mail copy of activity
6a488035 1340 *
100fef9d 1341 * @param int $clientId
64bd5a0e
TO
1342 * @param int $activityId
1343 * Activity Id.
1344 * @param array $contacts
1345 * Array of related contact.
6a488035 1346 *
77b97be7 1347 * @param null $attachments
100fef9d 1348 * @param int $caseId
77b97be7 1349 *
67d19299 1350 * @return bool |array
6a488035 1351 */
00be9182 1352 public static function sendActivityCopy($clientId, $activityId, $contacts, $attachments = NULL, $caseId) {
6a488035 1353 if (!$activityId) {
67d19299 1354 return FALSE;
6a488035
TO
1355 }
1356
1357 $tplParams = $activityInfo = array();
8d04ae48
AP
1358 $activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityId, 'activity_type_id');
1359 // If it's a case activity
6a488035 1360 if ($caseId) {
6a488035 1361 $nonCaseActivityTypes = CRM_Core_PseudoConstant::activityType();
a7488080 1362 if (!empty($nonCaseActivityTypes[$activityTypeId])) {
6a488035
TO
1363 $anyActivity = TRUE;
1364 }
1365 else {
1366 $anyActivity = FALSE;
1367 }
1368 $tplParams['isCaseActivity'] = 1;
1369 $tplParams['client_id'] = $clientId;
1370 }
1371 else {
1372 $anyActivity = TRUE;
1373 }
1374
1375 $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
1376 $isRedact = $xmlProcessorProcess->getRedactActivityEmail();
1377
1378 $xmlProcessorReport = new CRM_Case_XMLProcessor_Report();
1379
1380 $activityInfo = $xmlProcessorReport->getActivityInfo($clientId, $activityId, $anyActivity, $isRedact);
1381 if ($caseId) {
1382 $activityInfo['fields'][] = array('label' => 'Case ID', 'type' => 'String', 'value' => $caseId);
1383 }
8d04ae48 1384 $tplParams['activityTypeName'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_DAO_Activity', 'activity_type_id', $activityTypeId);
6a488035
TO
1385 $tplParams['activity'] = $activityInfo;
1386 foreach ($tplParams['activity']['fields'] as $k => $val) {
1387 if (CRM_Utils_Array::value('label', $val) == ts('Subject')) {
1388 $activitySubject = $val['value'];
1389 break;
1390 }
1391 }
1392 $session = CRM_Core_Session::singleton();
1393 // CRM-8926 If user is not logged in, use the activity creator as userID
1394 if (!($userID = $session->get('userID'))) {
4322672b 1395 $userID = CRM_Activity_BAO_Activity::getSourceContactID($activityId);
6a488035
TO
1396 }
1397
1398 //also create activities simultaneously of this copy.
1399 $activityParams = array();
1400
1401 $activityParams['source_record_id'] = $activityId;
1402 $activityParams['source_contact_id'] = $userID;
95a718e1 1403 $activityParams['activity_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Activity_DAO_Activity', 'activity_type_id', 'Email');
6a488035 1404 $activityParams['activity_date_time'] = date('YmdHis');
95a718e1
JP
1405 $activityParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Activity_DAO_Activity', 'activity_status_id', 'Completed');
1406 $activityParams['medium_id'] = CRM_Core_PseudoConstant::getKey('CRM_Activity_DAO_Activity', 'encounter_medium', 'email');
6a488035
TO
1407 $activityParams['case_id'] = $caseId;
1408 $activityParams['is_auto'] = 0;
1409 $activityParams['target_id'] = $clientId;
1410
1411 $tplParams['activitySubject'] = $activitySubject;
1412
1413 // if it’s a case activity, add hashed id to the template (CRM-5916)
1414 if ($caseId) {
1415 $tplParams['idHash'] = substr(sha1(CIVICRM_SITE_KEY . $caseId), 0, 7);
1416 }
1417
1418 $result = array();
8aeeea00
EH
1419 // CRM-20308 get receiptFrom defaults see https://issues.civicrm.org/jira/browse/CRM-20308
1420 $receiptFrom = self::getReceiptFrom($activityId);
6a488035
TO
1421
1422 $recordedActivityParams = array();
1423
1424 foreach ($contacts as $mail => $info) {
1425 $tplParams['contact'] = $info;
1426 self::buildPermissionLinks($tplParams, $activityParams);
1427
21827a41 1428 $displayName = CRM_Utils_Array::value('display_name', $info);
6a488035 1429
c6327d7d 1430 list($result[CRM_Utils_Array::value('contact_id', $info)], $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate(
6a488035
TO
1431 array(
1432 'groupName' => 'msg_tpl_workflow_case',
1433 'valueName' => 'case_activity',
21827a41 1434 'contactId' => CRM_Utils_Array::value('contact_id', $info),
6a488035
TO
1435 'tplParams' => $tplParams,
1436 'from' => $receiptFrom,
1437 'toName' => $displayName,
1438 'toEmail' => $mail,
1439 'attachments' => $attachments,
1440 )
1441 );
1442
898f01ea 1443 $activityParams['subject'] = ts('%1 - copy sent to %2', [1 => $activitySubject, 2 => $displayName]);
6a488035
TO
1444 $activityParams['details'] = $message;
1445
21827a41 1446 if (!empty($result[$info['contact_id']])) {
6a488035
TO
1447 /*
1448 * Really only need to record one activity with all the targets combined.
1449 * Originally the template was going to possibly have different content, e.g. depending on permissions,
1450 * but it's always the same content at the moment.
1451 */
1452 if (empty($recordedActivityParams)) {
1453 $recordedActivityParams = $activityParams;
1454 }
1455 else {
1456 $recordedActivityParams['subject'] .= "; $displayName";
1457 }
1458 $recordedActivityParams['target_contact_id'][] = $info['contact_id'];
1459 }
1460 else {
21827a41 1461 unset($result[CRM_Utils_Array::value('contact_id', $info)]);
6a488035
TO
1462 }
1463 }
1464
1465 if (!empty($recordedActivityParams)) {
1466 $activity = CRM_Activity_BAO_Activity::create($recordedActivityParams);
1467
1468 //create case_activity record if its case activity.
1469 if ($caseId) {
1470 $caseParams = array(
1471 'activity_id' => $activity->id,
1472 'case_id' => $caseId,
1473 );
1474 self::processCaseActivity($caseParams);
1475 }
1476 }
1477
1478 return $result;
1479 }
1480
1481 /**
1482 * Retrieve count of activities having a particular type, and
1483 * associated with a particular case.
1484 *
64bd5a0e
TO
1485 * @param int $caseId
1486 * ID of the case.
1487 * @param int $activityTypeId
1488 * ID of the activity type.
6a488035
TO
1489 *
1490 * @return array
6a488035 1491 */
00be9182 1492 public static function getCaseActivityCount($caseId, $activityTypeId) {
e96f025a 1493 $queryParam = array(
1494 1 => array($caseId, 'Integer'),
6a488035
TO
1495 2 => array($activityTypeId, 'Integer'),
1496 );
1497 $query = "SELECT count(ca.id) as countact
1498 FROM civicrm_activity ca
1499 INNER JOIN civicrm_case_activity cca ON ca.id = cca.activity_id
1500 WHERE ca.activity_type_id = %2
1501 AND cca.case_id = %1
1502 AND ca.is_deleted = 0";
1503
1504 $dao = CRM_Core_DAO::executeQuery($query, $queryParam);
1505 if ($dao->fetch()) {
1506 return $dao->countact;
1507 }
1508
1509 return FALSE;
1510 }
1511
1512 /**
d2e5d2ce 1513 * Create an activity for a case via email.
6a488035 1514 *
64bd5a0e
TO
1515 * @param int $file
1516 * Email sent.
6a488035 1517 *
72b3a70c
CW
1518 * @return array|void
1519 * $activity object of newly creted activity via email
6a488035 1520 */
00be9182 1521 public static function recordActivityViaEmail($file) {
6a488035
TO
1522 if (!file_exists($file) ||
1523 !is_readable($file)
1524 ) {
1525 return CRM_Core_Error::fatal(ts('File %1 does not exist or is not readable',
d6f468d3
KJ
1526 array(1 => $file)
1527 ));
6a488035
TO
1528 }
1529
1530 $result = CRM_Utils_Mail_Incoming::parse($file);
1531 if ($result['is_error']) {
1532 return $result;
1533 }
1534
1535 foreach ($result['to'] as $to) {
1536 $caseId = NULL;
1537
1538 $emailPattern = '/^([A-Z0-9._%+-]+)\+([\d]+)@[A-Z0-9.-]+\.[A-Z]{2,4}$/i';
1539 $replacement = preg_replace($emailPattern, '$2', $to['email']);
1540
1541 if ($replacement !== $to['email']) {
1542 $caseId = $replacement;
1543 //if caseId is invalid, return as error file
1544 if (!CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseId, 'id')) {
1545 return CRM_Core_Error::createAPIError(ts('Invalid case ID ( %1 ) in TO: field.',
d6f468d3
KJ
1546 array(1 => $caseId)
1547 ));
6a488035
TO
1548 }
1549 }
1550 else {
1551 continue;
1552 }
1553
1554 // TODO: May want to replace this with a call to getRelatedAndGlobalContacts() when this feature is revisited.
1555 // (Or for efficiency call the global one outside the loop and then union with this each time.)
b982dca0 1556 $contactDetails = self::getRelatedContacts($caseId, FALSE);
6a488035 1557
a7488080 1558 if (!empty($contactDetails[$result['from']['id']])) {
6a488035
TO
1559 $params = array();
1560 $params['subject'] = $result['subject'];
1561 $params['activity_date_time'] = $result['date'];
1562 $params['details'] = $result['body'];
1563 $params['source_contact_id'] = $result['from']['id'];
9c248a42 1564 $params['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed');
6a488035
TO
1565
1566 $details = CRM_Case_PseudoConstant::caseActivityType();
1567 $matches = array();
1568 preg_match('/^\W+([a-zA-Z0-9_ ]+)(\W+)?\n/i',
1569 $result['body'], $matches
1570 );
1571
1572 if (!empty($matches) && isset($matches[1])) {
1573 $activityType = trim($matches[1]);
1574 if (isset($details[$activityType])) {
1575 $params['activity_type_id'] = $details[$activityType]['id'];
1576 }
1577 }
1578 if (!isset($params['activity_type_id'])) {
9c248a42 1579 $params['activity_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email');
6a488035
TO
1580 }
1581
1582 // create activity
1583 $activity = CRM_Activity_BAO_Activity::create($params);
1584
1585 $caseParams = array(
1586 'activity_id' => $activity->id,
1587 'case_id' => $caseId,
1588 );
1589 self::processCaseActivity($caseParams);
1590 }
1591 else {
1592 return CRM_Core_Error::createAPIError(ts('FROM email contact %1 doesn\'t have a relationship to the referenced case.',
d6f468d3
KJ
1593 array(1 => $result['from']['email'])
1594 ));
6a488035
TO
1595 }
1596 }
1597 }
1598
1599 /**
d2e5d2ce 1600 * Retrieve the scheduled activity type and date.
6a488035 1601 *
64bd5a0e
TO
1602 * @param array $cases
1603 * Array of contact and case id.
77b97be7
EM
1604 *
1605 * @param string $type
6a488035 1606 *
a6c01b45
CW
1607 * @return array
1608 * Array of scheduled activity type and date
6a488035 1609 *
6a488035 1610 *
6a488035 1611 */
00be9182 1612 public static function getNextScheduledActivity($cases, $type = 'upcoming') {
6a488035
TO
1613 $session = CRM_Core_Session::singleton();
1614 $userID = $session->get('userID');
1615
1616 $caseID = implode(',', $cases['case_id']);
1617 $contactID = implode(',', $cases['contact_id']);
1618
5f1c8c57 1619 $condition = " civicrm_case_contact.contact_id IN( {$contactID} )
6a488035
TO
1620 AND civicrm_case.id IN( {$caseID})
1621 AND civicrm_case.is_deleted = {$cases['case_deleted']}";
1622
2ff620ae 1623 $query = self::getCaseActivityQuery($type, $userID, $condition);
6a488035 1624
33621c4f 1625 $res = CRM_Core_DAO::executeQuery($query);
6a488035
TO
1626
1627 $activityInfo = array();
1628 while ($res->fetch()) {
1629 if ($type == 'upcoming') {
1630 $activityInfo[$res->case_id]['date'] = $res->case_scheduled_activity_date;
1631 $activityInfo[$res->case_id]['type'] = $res->case_scheduled_activity_type;
1632 }
1633 else {
1634 $activityInfo[$res->case_id]['date'] = $res->case_recent_activity_date;
1635 $activityInfo[$res->case_id]['type'] = $res->case_recent_activity_type;
1636 }
1637 }
1638
1639 return $activityInfo;
1640 }
1641
1642 /**
d2e5d2ce 1643 * Combine all the exportable fields from the lower levels object.
6a488035 1644 *
a6c01b45
CW
1645 * @return array
1646 * array of exportable Fields
6a488035 1647 */
00be9182 1648 public static function &exportableFields() {
6a488035
TO
1649 if (!self::$_exportableFields) {
1650 if (!self::$_exportableFields) {
1651 self::$_exportableFields = array();
1652 }
1653
e96f025a 1654 $fields = CRM_Case_DAO_Case::export();
6a488035 1655 $fields['case_role'] = array('title' => ts('Role in Case'));
e96f025a 1656 $fields['case_type'] = array(
1657 'title' => ts('Case Type'),
6a488035
TO
1658 'name' => 'case_type',
1659 );
e96f025a 1660 $fields['case_status'] = array(
1661 'title' => ts('Case Status'),
6a488035
TO
1662 'name' => 'case_status',
1663 );
1664
e75182f2
JJ
1665 // add custom data for cases
1666 $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Case'));
1667
6a488035
TO
1668 self::$_exportableFields = $fields;
1669 }
1670 return self::$_exportableFields;
1671 }
1672
1673 /**
d2e5d2ce 1674 * Restore the record that are associated with this case.
6a488035 1675 *
64bd5a0e
TO
1676 * @param int $caseId
1677 * Id of the case to restore.
6a488035 1678 *
72b3a70c 1679 * @return bool
6a488035 1680 */
00be9182 1681 public static function restoreCase($caseId) {
6a488035
TO
1682 //restore activities
1683 $activities = self::getCaseActivityDates($caseId);
1684 if ($activities) {
1685 foreach ($activities as $value) {
1686 CRM_Activity_BAO_Activity::restoreActivity($value);
1687 }
1688 }
1689 //restore case
e96f025a 1690 $case = new CRM_Case_DAO_Case();
1691 $case->id = $caseId;
6a488035
TO
1692 $case->is_deleted = 0;
1693 $case->save();
1694
1695 //CRM-7364, enable relationships
1696 self::enableDisableCaseRelationships($caseId, TRUE);
1697 return TRUE;
1698 }
1699
4c6ce474
EM
1700 /**
1701 * @param $groupInfo
1702 * @param null $sort
1703 * @param null $showLinks
1704 * @param bool $returnOnlyCount
1705 * @param int $offset
1706 * @param int $rowCount
1707 *
1708 * @return array
1709 */
00be9182 1710 public static function getGlobalContacts(&$groupInfo, $sort = NULL, $showLinks = NULL, $returnOnlyCount = FALSE, $offset = 0, $rowCount = 25) {
6a488035
TO
1711 $globalContacts = array();
1712
1713 $settingsProcessor = new CRM_Case_XMLProcessor_Settings();
1714 $settings = $settingsProcessor->run();
1715 if (!empty($settings)) {
1716 $groupInfo['name'] = $settings['groupname'];
1717 if ($groupInfo['name']) {
1718 $searchParams = array('name' => $groupInfo['name']);
1719 $results = array();
1720 CRM_Contact_BAO_Group::retrieve($searchParams, $results);
1721 if ($results) {
e96f025a 1722 $groupInfo['id'] = $results['id'];
6a488035 1723 $groupInfo['title'] = $results['title'];
b3188db2 1724 $params = array(array('group', '=', $groupInfo['id'], 0, 0));
e96f025a 1725 $return = array('contact_id' => 1, 'sort_name' => 1, 'display_name' => 1, 'email' => 1, 'phone' => 1);
d79c94d5 1726 list($globalContacts) = CRM_Contact_BAO_Query::apiQuery($params, $return, NULL, $sort, $offset, $rowCount, TRUE, $returnOnlyCount);
6a488035
TO
1727
1728 if ($returnOnlyCount) {
1729 return $globalContacts;
1730 }
1731
1732 if ($showLinks) {
e96f025a 1733 foreach ($globalContacts as $idx => $contact) {
d79c94d5 1734 $globalContacts[$idx]['sort_name'] = '<a href="' . CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$contact['contact_id']}") . '">' . $contact['sort_name'] . '</a>';
6a488035
TO
1735 }
1736 }
1737 }
1738 }
1739 }
1740 return $globalContacts;
1741 }
1742
4c6ce474 1743 /**
d2e5d2ce 1744 * Convenience function to get both case contacts and global in one array.
100fef9d 1745 * @param int $caseId
4c6ce474
EM
1746 *
1747 * @return array
1748 */
00be9182 1749 public static function getRelatedAndGlobalContacts($caseId) {
6a488035
TO
1750 $relatedContacts = self::getRelatedContacts($caseId);
1751
1752 $groupInfo = array();
1753 $globalContacts = self::getGlobalContacts($groupInfo);
1754
1755 //unset values which are not required.
1756 foreach ($globalContacts as $k => & $v) {
1757 unset($v['email_id']);
1758 unset($v['group_contact_id']);
1759 unset($v['status']);
1760 unset($v['phone']);
1761 $v['role'] = $groupInfo['title'];
1762 }
1763 //include multiple listings for the same contact/different roles.
1764 $relatedGlobalContacts = array_merge($relatedContacts, $globalContacts);
1765 return $relatedGlobalContacts;
1766 }
1767
1768 /**
100fef9d 1769 * Get Case ActivitiesDueDates with given criteria.
6a488035 1770 *
64bd5a0e
TO
1771 * @param int $caseID
1772 * Case id.
1773 * @param array $criteriaParams
1774 * Given criteria.
1775 * @param bool $latestDate
72b3a70c 1776 * If set newest or oldest date is selected.
6a488035 1777 *
72b3a70c
CW
1778 * @return array
1779 * case activities due dates
6a488035 1780 *
6a488035 1781 */
00be9182 1782 public static function getCaseActivityDates($caseID, $criteriaParams = array(), $latestDate = FALSE) {
e96f025a 1783 $values = array();
6a488035 1784 $selectDate = " ca.activity_date_time";
e96f025a 1785 $where = $groupBy = ' ';
6a488035
TO
1786
1787 if (!$caseID) {
408b79bf 1788 return NULL;
6a488035
TO
1789 }
1790
1791 if ($latestDate) {
a7488080 1792 if (!empty($criteriaParams['activity_type_id'])) {
6a488035
TO
1793 $where .= " AND ca.activity_type_id = " . CRM_Utils_Type::escape($criteriaParams['activity_type_id'], 'Integer');
1794 $where .= " AND ca.is_current_revision = 1";
e5cceea5 1795 $groupBy .= " GROUP BY ca.activity_type_id, ca.id";
6a488035
TO
1796 }
1797
a7488080 1798 if (!empty($criteriaParams['newest'])) {
6a488035
TO
1799 $selectDate = " max(ca.activity_date_time) ";
1800 }
1801 else {
1802 $selectDate = " min(ca.activity_date_time) ";
1803 }
1804 }
1805
1806 $query = "SELECT ca.id, {$selectDate} as activity_date
1807 FROM civicrm_activity ca
1808 LEFT JOIN civicrm_case_activity cca ON cca.activity_id = ca.id LEFT JOIN civicrm_case cc ON cc.id = cca.case_id
1809 WHERE cc.id = %1 {$where} {$groupBy}";
1810
1811 $params = array(1 => array($caseID, 'Integer'));
1812 $dao = CRM_Core_DAO::executeQuery($query, $params);
1813
1814 while ($dao->fetch()) {
1815 $values[$dao->id]['id'] = $dao->id;
1816 $values[$dao->id]['activity_date'] = $dao->activity_date;
1817 }
6a488035
TO
1818 return $values;
1819 }
1820
1821 /**
100fef9d 1822 * Create activities when Case or Other roles assigned/modified/deleted.
6a488035 1823 *
100fef9d 1824 * @param int $caseId
64bd5a0e
TO
1825 * @param int $relationshipId
1826 * Relationship id.
1827 * @param int $relContactId
1828 * Case role assignee contactId.
100fef9d 1829 * @param int $contactId
6a488035 1830 */
00be9182 1831 public static function createCaseRoleActivity($caseId, $relationshipId, $relContactId = NULL, $contactId = NULL) {
6a488035
TO
1832 if (!$caseId || !$relationshipId || empty($relationshipId)) {
1833 return;
1834 }
1835
1836 $queryParam = array();
1837 if (is_array($relationshipId)) {
1838 $relationshipId = implode(',', $relationshipId);
1839 $relationshipClause = " civicrm_relationship.id IN ($relationshipId)";
1840 }
1841 else {
1842 $relationshipClause = " civicrm_relationship.id = %1";
1843 $queryParam[1] = array($relationshipId, 'Positive');
1844 }
1845
1846 $query = "
1847 SELECT cc.display_name as clientName,
1848 cca.display_name as assigneeContactName,
1849 civicrm_relationship.case_id as caseId,
1850 civicrm_relationship_type.label_a_b as relation_a_b,
1851 civicrm_relationship_type.label_b_a as relation_b_a,
1852 civicrm_relationship.contact_id_b as rel_contact_id,
1853 civicrm_relationship.contact_id_a as assign_contact_id
1854 FROM civicrm_relationship_type, civicrm_relationship
1855 LEFT JOIN civicrm_contact cc ON cc.id = civicrm_relationship.contact_id_b
1856 LEFT JOIN civicrm_contact cca ON cca.id = civicrm_relationship.contact_id_a
1857 WHERE civicrm_relationship.relationship_type_id = civicrm_relationship_type.id AND {$relationshipClause}";
1858
1859 $dao = CRM_Core_DAO::executeQuery($query, $queryParam);
1860
1861 while ($dao->fetch()) {
e3b9b4f6
KW
1862 // The assignee is not the client.
1863 if ($dao->rel_contact_id != $contactId) {
6a488035
TO
1864 $caseRelationship = $dao->relation_a_b;
1865 $assigneContactName = $dao->clientName;
1866 $assigneContactIds[$dao->rel_contact_id] = $dao->rel_contact_id;
1867 }
1868 else {
1869 $caseRelationship = $dao->relation_b_a;
1870 $assigneContactName = $dao->assigneeContactName;
1871 $assigneContactIds[$dao->assign_contact_id] = $dao->assign_contact_id;
1872 }
1873 }
1874
1875 $session = CRM_Core_Session::singleton();
1876 $activityParams = array(
1877 'source_contact_id' => $session->get('userID'),
1878 'subject' => $caseRelationship . ' : ' . $assigneContactName,
1879 'activity_date_time' => date('YmdHis'),
9c248a42 1880 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed'),
6a488035
TO
1881 );
1882
1883 //if $relContactId is passed, role is added or modified.
1884 if (!empty($relContactId)) {
1885 $activityParams['assignee_contact_id'] = $assigneContactIds;
9c248a42 1886 $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Assign Case Role');
6a488035
TO
1887 }
1888 else {
9c248a42 1889 $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Remove Case Role');
6a488035
TO
1890 }
1891
1892 $activityParams['activity_type_id'] = $activityTypeID;
1893
1894 $activity = CRM_Activity_BAO_Activity::create($activityParams);
1895
1896 //create case_activity record.
1897 $caseParams = array(
1898 'activity_id' => $activity->id,
1899 'case_id' => $caseId,
1900 );
1901
1902 CRM_Case_BAO_Case::processCaseActivity($caseParams);
1903 }
1904
1905 /**
100fef9d 1906 * Get case manger
6a488035
TO
1907 * contact which is assigned a case role of case manager.
1908 *
64bd5a0e
TO
1909 * @param int $caseType
1910 * Case type.
1911 * @param int $caseId
1912 * Case id.
6a488035 1913 *
c00bd201 1914 * @return string
1915 * html hyperlink of manager contact view page
6a488035 1916 *
6a488035 1917 */
00be9182 1918 public static function getCaseManagerContact($caseType, $caseId) {
6a488035 1919 if (!$caseType || !$caseId) {
408b79bf 1920 return NULL;
6a488035
TO
1921 }
1922
5757b086 1923 $caseManagerName = '---';
6a488035
TO
1924 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
1925
1926 $managerRoleId = $xmlProcessor->getCaseManagerRoleId($caseType);
1927
1928 if (!empty($managerRoleId)) {
1929 $managerRoleQuery = "
1930SELECT civicrm_contact.id as casemanager_id,
1931 civicrm_contact.sort_name as casemanager
1932 FROM civicrm_contact
211fe764 1933 LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
6a488035 1934 LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
7d5aee02 1935 WHERE civicrm_case.id = %2 AND is_active = 1";
6a488035
TO
1936
1937 $managerRoleParams = array(
1938 1 => array($managerRoleId, 'Integer'),
1939 2 => array($caseId, 'Integer'),
1940 );
1941
1942 $dao = CRM_Core_DAO::executeQuery($managerRoleQuery, $managerRoleParams);
1943 if ($dao->fetch()) {
5757b086 1944 $caseManagerName = sprintf('<a href="%s">%s</a>',
c00bd201 1945 CRM_Utils_System::url('civicrm/contact/view', array('cid' => $dao->casemanager_id)),
1946 $dao->casemanager
1947 );
6a488035
TO
1948 }
1949 }
5757b086 1950
1951 return $caseManagerName;
6a488035
TO
1952 }
1953
4c6ce474 1954 /**
100fef9d 1955 * @param int $contactId
4c6ce474
EM
1956 * @param bool $excludeDeleted
1957 *
eeb45e43 1958 * @return int
4c6ce474 1959 */
00be9182 1960 public static function caseCount($contactId = NULL, $excludeDeleted = TRUE) {
0a1a8b63 1961 $params = array('check_permissions' => TRUE);
6a488035 1962 if ($excludeDeleted) {
0a1a8b63 1963 $params['is_deleted'] = 0;
6a488035
TO
1964 }
1965 if ($contactId) {
0a1a8b63 1966 $params['contact_id'] = $contactId;
6a488035 1967 }
eeb45e43
CW
1968 try {
1969 return civicrm_api3('Case', 'getcount', $params);
1970 }
1971 catch (CiviCRM_API3_Exception $e) {
1972 // Lack of permissions will throw an exception
1973 return 0;
1974 }
6a488035
TO
1975 }
1976
1977 /**
6e19e2ea 1978 * Retrieve related case ids for given case.
6a488035 1979 *
6e19e2ea 1980 * @param int $caseId
64bd5a0e
TO
1981 * @param bool $excludeDeleted
1982 * Do not include deleted cases.
6a488035 1983 *
72b3a70c 1984 * @return array
6a488035 1985 */
6e19e2ea 1986 public static function getRelatedCaseIds($caseId, $excludeDeleted = TRUE) {
6a488035
TO
1987 //FIXME : do check for permissions.
1988
6e19e2ea
CW
1989 if (!$caseId) {
1990 return array();
6a488035
TO
1991 }
1992
b864360d 1993 $linkActType = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Link Cases');
6a488035 1994 if (!$linkActType) {
6e19e2ea 1995 return array();
6a488035
TO
1996 }
1997
1998 $whereClause = "mainCase.id = %2";
1999 if ($excludeDeleted) {
2000 $whereClause .= " AND ( relAct.is_deleted = 0 OR relAct.is_deleted IS NULL )";
2001 }
2002
6a488035
TO
2003 $query = "
2004 SELECT relCaseAct.case_id
2005 FROM civicrm_case mainCase
2006 INNER JOIN civicrm_case_activity mainCaseAct ON (mainCaseAct.case_id = mainCase.id)
2007 INNER JOIN civicrm_activity mainAct ON (mainCaseAct.activity_id = mainAct.id AND mainAct.activity_type_id = %1)
2008 INNER JOIN civicrm_case_activity relCaseAct ON (relCaseAct.activity_id = mainAct.id AND mainCaseAct.id != relCaseAct.id)
2009 INNER JOIN civicrm_activity relAct ON (relCaseAct.activity_id = relAct.id AND relAct.activity_type_id = %1)
2010 WHERE $whereClause";
2011
2012 $dao = CRM_Core_DAO::executeQuery($query, array(
2013 1 => array($linkActType, 'Integer'),
6e19e2ea 2014 2 => array($caseId, 'Integer'),
6a488035
TO
2015 ));
2016 $relatedCaseIds = array();
2017 while ($dao->fetch()) {
2018 $relatedCaseIds[$dao->case_id] = $dao->case_id;
2019 }
6a488035 2020
6e19e2ea
CW
2021 return array_values($relatedCaseIds);
2022 }
2023
2024 /**
2025 * Retrieve related case details for given case.
2026 *
2027 * @param int $caseId
2028 * @param bool $excludeDeleted
2029 * Do not include deleted cases.
2030 *
2031 * @return array
2032 */
2033 public static function getRelatedCases($caseId, $excludeDeleted = TRUE) {
2034 $relatedCaseIds = self::getRelatedCaseIds($caseId, $excludeDeleted);
2035 $relatedCases = array();
2036
2037 if (!$relatedCaseIds) {
2038 return array();
6a488035
TO
2039 }
2040
2041 $whereClause = 'relCase.id IN ( ' . implode(',', $relatedCaseIds) . ' )';
2042 if ($excludeDeleted) {
2043 $whereClause .= " AND ( relCase.is_deleted = 0 OR relCase.is_deleted IS NULL )";
2044 }
2045
2046 //filter for permissioned cases.
2047 $filterCases = array();
2048 $doFilterCases = FALSE;
2049 if (!CRM_Core_Permission::check('access all cases and activities')) {
2050 $doFilterCases = TRUE;
5f1c8c57 2051 $filterCases = CRM_Case_BAO_Case::getCases(FALSE);
6a488035
TO
2052 }
2053
2054 //2. fetch the details of related cases.
2055 $query = "
2056 SELECT relCase.id as id,
8ffdec17 2057 civicrm_case_type.title as case_type,
6a488035 2058 client.display_name as client_name,
74b15fae
CR
2059 client.id as client_id,
2060 relCase.status_id
6a488035
TO
2061 FROM civicrm_case relCase
2062 INNER JOIN civicrm_case_contact relCaseContact ON ( relCase.id = relCaseContact.case_id )
2063 INNER JOIN civicrm_contact client ON ( client.id = relCaseContact.contact_id )
8ffdec17 2064 LEFT JOIN civicrm_case_type ON relCase.case_type_id = civicrm_case_type.id
6a488035
TO
2065 WHERE {$whereClause}";
2066
e96f025a 2067 $dao = CRM_Core_DAO::executeQuery($query);
6a488035
TO
2068 $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid=");
2069 $hasViewContact = CRM_Core_Permission::giveMeAllACLs();
74b15fae 2070 $statuses = CRM_Case_BAO_Case::buildOptions('status_id');
6a488035
TO
2071
2072 while ($dao->fetch()) {
2073 $caseView = NULL;
2074 if (!$doFilterCases || array_key_exists($dao->id, $filterCases)) {
2075 $caseViewStr = "reset=1&id={$dao->id}&cid={$dao->client_id}&action=view&context=case&selectedChild=case";
2076 $caseViewUrl = CRM_Utils_System::url("civicrm/contact/view/case", $caseViewStr);
6ce08914 2077 $caseView = "<a class='action-item no-popup crm-hover-button' href='{$caseViewUrl}'>" . ts('View Case') . "</a>";
6a488035
TO
2078 }
2079 $clientView = $dao->client_name;
2080 if ($hasViewContact) {
2081 $clientView = "<a href='{$contactViewUrl}{$dao->client_id}'>$dao->client_name</a>";
2082 }
2083
2084 $relatedCases[$dao->id] = array(
2085 'case_id' => $dao->id,
2086 'case_type' => $dao->case_type,
2087 'client_name' => $clientView,
74b15fae 2088 'case_status' => $statuses[$dao->status_id],
6a488035
TO
2089 'links' => $caseView,
2090 );
2091 }
6a488035
TO
2092
2093 return $relatedCases;
2094 }
2095
2096 /**
2097 * Merge two duplicate contacts' cases - follow CRM-5758 rules.
2098 *
2099 * @see CRM_Dedupe_Merger::cpTables()
2100 *
2101 * TODO: use the 3rd $sqls param to append sql statements rather than executing them here
cde2037d
EM
2102 *
2103 * @param int $mainContactId
2104 * @param int $otherContactId
6a488035 2105 */
00be9182 2106 public static function mergeContacts($mainContactId, $otherContactId) {
6a488035
TO
2107 self::mergeCases($mainContactId, NULL, $otherContactId);
2108 }
2109
2110 /**
2111 * Function perform two task.
2112 * 1. Merge two duplicate contacts cases - follow CRM-5758 rules.
2113 * 2. Merge two cases of same contact - follow CRM-5598 rules.
2114 *
64bd5a0e
TO
2115 * @param int $mainContactId
2116 * Contact id of main contact record.
2117 * @param int $mainCaseId
2118 * Case id of main case record.
2119 * @param int $otherContactId
2120 * Contact id of record which is going to merge.
2121 * @param int $otherCaseId
2122 * Case id of record which is going to merge.
77b97be7
EM
2123 *
2124 * @param bool $changeClient
6a488035 2125 *
df8d3074 2126 * @return int|NULL
6a488035 2127 */
a130e045 2128 public static function mergeCases(
28d4d481
TO
2129 $mainContactId, $mainCaseId = NULL, $otherContactId = NULL,
2130 $otherCaseId = NULL, $changeClient = FALSE) {
6a488035
TO
2131 $moveToTrash = TRUE;
2132
2133 $duplicateContacts = FALSE;
2134 if ($mainContactId && $otherContactId &&
2135 $mainContactId != $otherContactId
2136 ) {
2137 $duplicateContacts = TRUE;
2138 }
2139
2140 $duplicateCases = FALSE;
2141 if ($mainCaseId && $otherCaseId &&
2142 $mainCaseId != $otherCaseId
2143 ) {
2144 $duplicateCases = TRUE;
2145 }
2146
2147 $mainCaseIds = array();
2148 if (!$duplicateContacts && !$duplicateCases) {
2149 return $mainCaseIds;
2150 }
2151
b864360d
MWMC
2152 $activityTypes = CRM_Activity_BAO_Activity::buildOptions('activity_type_id', 'validate');
2153 $completedActivityStatus = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed');
44f817d4 2154 $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
9e74e3ce 2155 $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
2156 $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
2157 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
8ef12e64 2158
6a488035
TO
2159 $processCaseIds = array($otherCaseId);
2160 if ($duplicateContacts && !$duplicateCases) {
2161 if ($changeClient) {
2162 $processCaseIds = array($mainCaseId);
2163 }
2164 else {
2165 //get all case ids for other contact.
2166 $processCaseIds = self::retrieveCaseIdsByContactId($otherContactId, TRUE);
2167 }
2168 if (!is_array($processCaseIds)) {
2169 return;
2170 }
2171 }
2172
2173 $session = CRM_Core_Session::singleton();
2174 $currentUserId = $session->get('userID');
2175
02094cdb
JJ
2176 CRM_Utils_Hook::pre_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient);
2177
6a488035
TO
2178 // copy all cases and connect to main contact id.
2179 foreach ($processCaseIds as $otherCaseId) {
2180 if ($duplicateContacts) {
2181 $mainCase = CRM_Core_DAO::copyGeneric('CRM_Case_DAO_Case', array('id' => $otherCaseId));
2182 $mainCaseId = $mainCase->id;
2183 if (!$mainCaseId) {
2184 continue;
2185 }
8bd86283
DG
2186
2187 // CRM-11662 Copy Case custom data
2188 $extends = array('case');
2189 $groupTree = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, NULL, $extends);
2190 if ($groupTree) {
2191 foreach ($groupTree as $groupID => $group) {
2192 $table[$groupTree[$groupID]['table_name']] = array('entity_id');
2193 foreach ($group['fields'] as $fieldID => $field) {
2194 $table[$groupTree[$groupID]['table_name']][] = $groupTree[$groupID]['fields'][$fieldID]['column_name'];
2195 }
2196 }
2197
2198 foreach ($table as $tableName => $tableColumns) {
e96f025a 2199 $insert = 'INSERT INTO ' . $tableName . ' (' . implode(', ', $tableColumns) . ') ';
8bd86283 2200 $tableColumns[0] = $mainCaseId;
e96f025a 2201 $select = 'SELECT ' . implode(', ', $tableColumns);
2202 $from = ' FROM ' . $tableName;
2203 $where = " WHERE {$tableName}.entity_id = {$otherCaseId}";
2204 $query = $insert . $select . $from . $where;
33621c4f 2205 $dao = CRM_Core_DAO::executeQuery($query);
8bd86283
DG
2206 }
2207 }
e96f025a 2208
6a488035
TO
2209 $mainCaseIds[] = $mainCaseId;
2210 //insert record for case contact.
2211 $otherCaseContact = new CRM_Case_DAO_CaseContact();
2212 $otherCaseContact->case_id = $otherCaseId;
2213 $otherCaseContact->find();
2214 while ($otherCaseContact->fetch()) {
2215 $mainCaseContact = new CRM_Case_DAO_CaseContact();
2216 $mainCaseContact->case_id = $mainCaseId;
2217 $mainCaseContact->contact_id = $otherCaseContact->contact_id;
2218 if ($mainCaseContact->contact_id == $otherContactId) {
2219 $mainCaseContact->contact_id = $mainContactId;
2220 }
2221 //avoid duplicate object.
2222 if (!$mainCaseContact->find(TRUE)) {
2223 $mainCaseContact->save();
2224 }
6a488035 2225 }
6a488035
TO
2226 }
2227 elseif (!$otherContactId) {
2228 $otherContactId = $mainContactId;
2229 }
2230
2231 if (!$mainCaseId || !$otherCaseId ||
2232 !$mainContactId || !$otherContactId
2233 ) {
2234 continue;
2235 }
2236
2237 // get all activities for other case.
2238 $otherCaseActivities = array();
2239 CRM_Core_DAO::commonRetrieveAll('CRM_Case_DAO_CaseActivity', 'case_id', $otherCaseId, $otherCaseActivities);
2240
2241 //for duplicate cases do not process singleton activities.
2242 $otherActivityIds = $singletonActivityIds = array();
2243 foreach ($otherCaseActivities as $caseActivityId => $otherIds) {
2244 $otherActId = CRM_Utils_Array::value('activity_id', $otherIds);
2245 if (!$otherActId || in_array($otherActId, $otherActivityIds)) {
2246 continue;
2247 }
2248 $otherActivityIds[] = $otherActId;
2249 }
2250 if ($duplicateCases) {
2251 if ($openCaseType = array_search('Open Case', $activityTypes)) {
2252 $sql = "
2253SELECT id
2254 FROM civicrm_activity
2255 WHERE activity_type_id = $openCaseType
2256 AND id IN ( " . implode(',', array_values($otherActivityIds)) . ');';
2257 $dao = CRM_Core_DAO::executeQuery($sql);
2258 while ($dao->fetch()) {
2259 $singletonActivityIds[] = $dao->id;
2260 }
6a488035
TO
2261 }
2262 }
2263
2264 // migrate all activities and connect to main contact.
2265 $copiedActivityIds = $activityMappingIds = array();
2266 sort($otherActivityIds);
2267 foreach ($otherActivityIds as $otherActivityId) {
2268
2269 //for duplicate cases -
2270 //do not migrate singleton activities.
2271 if (!$otherActivityId || in_array($otherActivityId, $singletonActivityIds)) {
2272 continue;
2273 }
2274
2275 //migrate activity record.
2276 $otherActivity = new CRM_Activity_DAO_Activity();
2277 $otherActivity->id = $otherActivityId;
2278 if (!$otherActivity->find(TRUE)) {
2279 continue;
2280 }
2281
2282 $mainActVals = array();
2283 $mainActivity = new CRM_Activity_DAO_Activity();
2284 CRM_Core_DAO::storeValues($otherActivity, $mainActVals);
2285 $mainActivity->copyValues($mainActVals);
2286 $mainActivity->id = NULL;
2287 $mainActivity->activity_date_time = CRM_Utils_Date::isoToMysql($otherActivity->activity_date_time);
6a488035
TO
2288 $mainActivity->source_record_id = CRM_Utils_Array::value($mainActivity->source_record_id,
2289 $activityMappingIds
2290 );
2291
2292 $mainActivity->original_id = CRM_Utils_Array::value($mainActivity->original_id,
2293 $activityMappingIds
2294 );
2295
2296 $mainActivity->parent_id = CRM_Utils_Array::value($mainActivity->parent_id,
2297 $activityMappingIds
2298 );
2299 $mainActivity->save();
2300 $mainActivityId = $mainActivity->id;
2301 if (!$mainActivityId) {
2302 continue;
2303 }
2304
2305 $activityMappingIds[$otherActivityId] = $mainActivityId;
4322672b 2306 // insert log of all activities
6a488035
TO
2307 CRM_Activity_BAO_Activity::logActivityAction($mainActivity);
2308
6a488035
TO
2309 $copiedActivityIds[] = $otherActivityId;
2310
2311 //create case activity record.
2312 $mainCaseActivity = new CRM_Case_DAO_CaseActivity();
2313 $mainCaseActivity->case_id = $mainCaseId;
2314 $mainCaseActivity->activity_id = $mainActivityId;
2315 $mainCaseActivity->save();
6a488035 2316
4322672b 2317 //migrate source activity.
2318 $otherSourceActivity = new CRM_Activity_DAO_ActivityContact();
2319 $otherSourceActivity->activity_id = $otherActivityId;
2320 $otherSourceActivity->record_type_id = $sourceID;
2321 $otherSourceActivity->find();
2322 while ($otherSourceActivity->fetch()) {
2323 $mainActivitySource = new CRM_Activity_DAO_ActivityContact();
2324 $mainActivitySource->record_type_id = $sourceID;
2325 $mainActivitySource->activity_id = $mainActivityId;
2326 $mainActivitySource->contact_id = $otherSourceActivity->contact_id;
2327 if ($mainActivitySource->contact_id == $otherContactId) {
2328 $mainActivitySource->contact_id = $mainContactId;
2329 }
2330 //avoid duplicate object.
2331 if (!$mainActivitySource->find(TRUE)) {
2332 $mainActivitySource->save();
2333 }
4322672b 2334 }
4322672b 2335
6a488035 2336 //migrate target activities.
4e3d3cfc 2337 $otherTargetActivity = new CRM_Activity_DAO_ActivityContact();
6a488035 2338 $otherTargetActivity->activity_id = $otherActivityId;
9e74e3ce 2339 $otherTargetActivity->record_type_id = $targetID;
6a488035
TO
2340 $otherTargetActivity->find();
2341 while ($otherTargetActivity->fetch()) {
4e3d3cfc 2342 $mainActivityTarget = new CRM_Activity_DAO_ActivityContact();
9e74e3ce 2343 $mainActivityTarget->record_type_id = $targetID;
6a488035 2344 $mainActivityTarget->activity_id = $mainActivityId;
00bf7e59 2345 $mainActivityTarget->contact_id = $otherTargetActivity->contact_id;
2346 if ($mainActivityTarget->contact_id == $otherContactId) {
2347 $mainActivityTarget->contact_id = $mainContactId;
6a488035
TO
2348 }
2349 //avoid duplicate object.
2350 if (!$mainActivityTarget->find(TRUE)) {
2351 $mainActivityTarget->save();
2352 }
6a488035 2353 }
6a488035
TO
2354
2355 //migrate assignee activities.
4e3d3cfc 2356 $otherAssigneeActivity = new CRM_Activity_DAO_ActivityContact();
6a488035 2357 $otherAssigneeActivity->activity_id = $otherActivityId;
9e74e3ce 2358 $otherAssigneeActivity->record_type_id = $assigneeID;
6a488035
TO
2359 $otherAssigneeActivity->find();
2360 while ($otherAssigneeActivity->fetch()) {
4e3d3cfc 2361 $mainAssigneeActivity = new CRM_Activity_DAO_ActivityContact();
6a488035 2362 $mainAssigneeActivity->activity_id = $mainActivityId;
9e74e3ce 2363 $mainAssigneeActivity->record_type_id = $assigneeID;
00bf7e59 2364 $mainAssigneeActivity->contact_id = $otherAssigneeActivity->contact_id;
2365 if ($mainAssigneeActivity->contact_id == $otherContactId) {
2366 $mainAssigneeActivity->contact_id = $mainContactId;
6a488035
TO
2367 }
2368 //avoid duplicate object.
2369 if (!$mainAssigneeActivity->find(TRUE)) {
2370 $mainAssigneeActivity->save();
2371 }
6a488035 2372 }
8c31eef5
D
2373
2374 // copy custom fields and attachments
4322672b 2375 $aparams = array(
2376 'activityID' => $otherActivityId,
2377 'mainActivityId' => $mainActivityId,
2378 );
8c31eef5 2379 CRM_Activity_BAO_Activity::copyExtendedActivityData($aparams);
6a488035
TO
2380 }
2381
2382 //copy case relationship.
2383 if ($duplicateContacts) {
2384 //migrate relationship records.
2385 $otherRelationship = new CRM_Contact_DAO_Relationship();
2386 $otherRelationship->case_id = $otherCaseId;
2387 $otherRelationship->find();
2388 $otherRelationshipIds = array();
2389 while ($otherRelationship->fetch()) {
2390 $otherRelVals = array();
2391 $updateOtherRel = FALSE;
2392 CRM_Core_DAO::storeValues($otherRelationship, $otherRelVals);
2393
2394 $mainRelationship = new CRM_Contact_DAO_Relationship();
2395 $mainRelationship->copyValues($otherRelVals);
2396 $mainRelationship->id = NULL;
2397 $mainRelationship->case_id = $mainCaseId;
2398 if ($mainRelationship->contact_id_a == $otherContactId) {
2399 $updateOtherRel = TRUE;
2400 $mainRelationship->contact_id_a = $mainContactId;
2401 }
2402
2403 //case creator change only when we merge user contact.
2404 if ($mainRelationship->contact_id_b == $otherContactId) {
2405 //do not change creator for change client.
2406 if (!$changeClient) {
2407 $updateOtherRel = TRUE;
2408 $mainRelationship->contact_id_b = ($currentUserId) ? $currentUserId : $mainContactId;
2409 }
2410 }
2411 $mainRelationship->end_date = CRM_Utils_Date::isoToMysql($otherRelationship->end_date);
2412 $mainRelationship->start_date = CRM_Utils_Date::isoToMysql($otherRelationship->start_date);
2413
2414 //avoid duplicate object.
2415 if (!$mainRelationship->find(TRUE)) {
2416 $mainRelationship->save();
2417 }
6a488035
TO
2418
2419 //get the other relationship ids to update end date.
2420 if ($updateOtherRel) {
2421 $otherRelationshipIds[$otherRelationship->id] = $otherRelationship->id;
2422 }
2423 }
6a488035
TO
2424
2425 //update other relationships end dates
2426 if (!empty($otherRelationshipIds)) {
2427 $sql = 'UPDATE civicrm_relationship
2428 SET end_date = CURDATE()
2429 WHERE id IN ( ' . implode(',', $otherRelationshipIds) . ')';
2430 CRM_Core_DAO::executeQuery($sql);
2431 }
2432 }
2433
2434 //move other case to trash.
2435 $mergeCase = self::deleteCase($otherCaseId, $moveToTrash);
2436 if (!$mergeCase) {
2437 continue;
2438 }
2439
2440 $mergeActSubject = $mergeActSubjectDetails = $mergeActType = '';
2441 if ($changeClient) {
2442 $mainContactDisplayName = CRM_Contact_BAO_Contact::displayName($mainContactId);
2443 $otherContactDisplayName = CRM_Contact_BAO_Contact::displayName($otherContactId);
2444
2445 $mergeActType = array_search('Reassigned Case', $activityTypes);
2446 $mergeActSubject = ts("Case %1 reassigned client from %2 to %3. New Case ID is %4.",
2447 array(
e96f025a 2448 1 => $otherCaseId,
2449 2 => $otherContactDisplayName,
2450 3 => $mainContactDisplayName,
21dfd5f5 2451 4 => $mainCaseId,
6a488035
TO
2452 )
2453 );
2454 }
2455 elseif ($duplicateContacts) {
2456 $mergeActType = array_search('Merge Case', $activityTypes);
2457 $mergeActSubject = ts("Case %1 copied from contact id %2 to contact id %3 via merge. New Case ID is %4.",
2458 array(
e96f025a 2459 1 => $otherCaseId,
2460 2 => $otherContactId,
2461 3 => $mainContactId,
21dfd5f5 2462 4 => $mainCaseId,
6a488035
TO
2463 )
2464 );
2465 }
2466 else {
2467 $mergeActType = array_search('Merge Case', $activityTypes);
2468 $mergeActSubject = ts("Case %1 merged into case %2", array(1 => $otherCaseId, 2 => $mainCaseId));
2469 if (!empty($copiedActivityIds)) {
2470 $sql = '
2471SELECT id, subject, activity_date_time, activity_type_id
2472FROM civicrm_activity
2473WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
2474 $dao = CRM_Core_DAO::executeQuery($sql);
2475 while ($dao->fetch()) {
2476 $mergeActSubjectDetails .= "{$dao->activity_date_time} :: {$activityTypes[$dao->activity_type_id]}";
2477 if ($dao->subject) {
2478 $mergeActSubjectDetails .= " :: {$dao->subject}";
2479 }
2480 $mergeActSubjectDetails .= "<br />";
2481 }
2482 }
2483 }
2484
b864360d 2485 // Create merge activity record. Source for merge activity is the logged in user's contact ID ($currentUserId).
6a488035
TO
2486 $activityParams = array(
2487 'subject' => $mergeActSubject,
2488 'details' => $mergeActSubjectDetails,
b864360d 2489 'status_id' => $completedActivityStatus,
6a488035 2490 'activity_type_id' => $mergeActType,
8c677b07 2491 'source_contact_id' => $currentUserId,
6a488035
TO
2492 'activity_date_time' => date('YmdHis'),
2493 );
2494
2495 $mergeActivity = CRM_Activity_BAO_Activity::create($activityParams);
2496 $mergeActivityId = $mergeActivity->id;
2497 if (!$mergeActivityId) {
2498 continue;
2499 }
6a488035
TO
2500
2501 //connect merge activity to case.
2502 $mergeCaseAct = array(
2503 'case_id' => $mainCaseId,
2504 'activity_id' => $mergeActivityId,
2505 );
2506
2507 self::processCaseActivity($mergeCaseAct);
2508 }
02094cdb
JJ
2509
2510 CRM_Utils_Hook::post_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient);
2511
6a488035
TO
2512 return $mainCaseIds;
2513 }
2514
2515 /**
2516 * Validate contact permission for
2517 * edit/view on activity record and build links.
2518 *
64bd5a0e
TO
2519 * @param array $tplParams
2520 * Params to be sent to template for sending email.
2521 * @param array $activityParams
2522 * Info of the activity.
6a488035 2523 */
00be9182 2524 public static function buildPermissionLinks(&$tplParams, $activityParams) {
6a488035
TO
2525 $activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityParams['source_record_id'],
2526 'activity_type_id', 'id'
2527 );
2528
a7488080 2529 if (!empty($tplParams['isCaseActivity'])) {
6a488035
TO
2530 $tplParams['editActURL'] = CRM_Utils_System::url('civicrm/case/activity',
2531 "reset=1&cid={$activityParams['target_id']}&caseid={$activityParams['case_id']}&action=update&id={$activityParams['source_record_id']}", TRUE
2532 );
2533
2534 $tplParams['viewActURL'] = CRM_Utils_System::url('civicrm/case/activity/view',
2535 "reset=1&aid={$activityParams['source_record_id']}&cid={$activityParams['target_id']}&caseID={$activityParams['case_id']}", TRUE
2536 );
2537
2538 $tplParams['manageCaseURL'] = CRM_Utils_System::url('civicrm/contact/view/case',
2539 "reset=1&id={$activityParams['case_id']}&cid={$activityParams['target_id']}&action=view&context=home", TRUE
2540 );
2541 }
2542 else {
2543 $tplParams['editActURL'] = CRM_Utils_System::url('civicrm/contact/view/activity',
2544 "atype=$activityTypeId&action=update&reset=1&id={$activityParams['source_record_id']}&cid={$tplParams['contact']['contact_id']}&context=activity", TRUE
2545 );
2546
2547 $tplParams['viewActURL'] = CRM_Utils_System::url('civicrm/contact/view/activity',
2548 "atype=$activityTypeId&action=view&reset=1&id={$activityParams['source_record_id']}&cid={$tplParams['contact']['contact_id']}&context=activity", TRUE
2549 );
2550 }
2551 }
2552
2553 /**
2554 * Validate contact permission for
2555 * given operation on activity record.
2556 *
64bd5a0e
TO
2557 * @param int $activityId
2558 * Activity record id.
2559 * @param string $operation
2560 * User operation.
2561 * @param int $actTypeId
2562 * Activity type id.
2563 * @param int $contactId
2564 * Contact id/if not pass consider logged in.
2565 * @param bool $checkComponent
2566 * Do we need to check component enabled.
6a488035 2567 *
a130e045 2568 * @return bool
6a488035 2569 */
00be9182 2570 public static function checkPermission($activityId, $operation, $actTypeId = NULL, $contactId = NULL, $checkComponent = TRUE) {
6a488035
TO
2571 $allow = FALSE;
2572 if (!$actTypeId && $activityId) {
2573 $actTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityId, 'activity_type_id');
2574 }
2575
2576 if (!$activityId || !$operation || !$actTypeId) {
2577 return $allow;
2578 }
2579
2580 //do check for civicase component enabled.
077dbf5e
CW
2581 if ($checkComponent && !self::enabled()) {
2582 return $allow;
6a488035
TO
2583 }
2584
2585 //do check for cases.
2586 $caseActOperations = array(
2587 'File On Case',
2588 'Link Cases',
2589 'Move To Case',
2590 'Copy To Case',
2591 );
2592
2593 if (in_array($operation, $caseActOperations)) {
abd06efc
CW
2594 static $caseCount;
2595 if (!isset($caseCount)) {
eeb45e43
CW
2596 try {
2597 $caseCount = civicrm_api3('Case', 'getcount', array(
2598 'check_permissions' => TRUE,
2599 'status_id' => array('!=' => 'Closed'),
2600 'is_deleted' => 0,
2601 'end_date' => array('IS NULL' => 1),
2602 ));
2603 }
2604 catch (CiviCRM_API3_Exception $e) {
2605 // Lack of permissions will throw an exception
2606 $caseCount = 0;
2607 }
6a488035
TO
2608 }
2609 if ($operation == 'File On Case') {
abd06efc 2610 $allow = !empty($caseCount);
6a488035
TO
2611 }
2612 else {
abd06efc 2613 $allow = ($caseCount > 1);
6a488035
TO
2614 }
2615 }
2616
2617 $actionOperations = array('view', 'edit', 'delete');
2618 if (in_array($operation, $actionOperations)) {
2619
2620 //do cache when user has non/supper permission.
2621 static $allowOperations;
2622
2623 if (!is_array($allowOperations) ||
2624 !array_key_exists($operation, $allowOperations)
2625 ) {
2626
2627 if (!$contactId) {
2628 $session = CRM_Core_Session::singleton();
2629 $contactId = $session->get('userID');
2630 }
2631
2632 //check for permissions.
2633 $permissions = array(
2634 'view' => array(
2635 'access my cases and activities',
2636 'access all cases and activities',
2637 ),
2638 'edit' => array(
2639 'access my cases and activities',
2640 'access all cases and activities',
2641 ),
2642 'delete' => array('delete activities'),
2643 );
2644
2645 //check for core permission.
2646 $hasPermissions = array();
2647 $checkPermissions = CRM_Utils_Array::value($operation, $permissions);
2648 if (is_array($checkPermissions)) {
2649 foreach ($checkPermissions as $per) {
2650 if (CRM_Core_Permission::check($per)) {
2651 $hasPermissions[$operation][] = $per;
2652 }
2653 }
2654 }
2655
2656 //has permissions.
2657 if (!empty($hasPermissions)) {
2658 //need to check activity object specific.
2659 if (in_array($operation, array(
e96f025a 2660 'view',
21dfd5f5 2661 'edit',
e96f025a 2662 ))
2663 ) {
6a488035
TO
2664 //do we have supper permission.
2665 if (in_array('access all cases and activities', $hasPermissions[$operation])) {
2666 $allowOperations[$operation] = $allow = TRUE;
2667 }
2668 else {
2669 //user has only access to my cases and activity.
2670 //here object specific permmions come in picture.
2671
2672 //edit - contact must be source or assignee
2673 //view - contact must be source/assignee/target
2674 $isTarget = $isAssignee = $isSource = FALSE;
44f817d4 2675 $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
4322672b 2676 $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
2677 $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
2678 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
6a488035 2679
4e3d3cfc 2680 $target = new CRM_Activity_DAO_ActivityContact();
9e74e3ce 2681 $target->record_type_id = $targetID;
6a488035 2682 $target->activity_id = $activityId;
00bf7e59 2683 $target->contact_id = $contactId;
6a488035
TO
2684 if ($target->find(TRUE)) {
2685 $isTarget = TRUE;
2686 }
2687
4e3d3cfc 2688 $assignee = new CRM_Activity_DAO_ActivityContact();
6a488035 2689 $assignee->activity_id = $activityId;
9e74e3ce 2690 $assignee->record_type_id = $assigneeID;
00bf7e59 2691 $assignee->contact_id = $contactId;
6a488035
TO
2692 if ($assignee->find(TRUE)) {
2693 $isAssignee = TRUE;
2694 }
2695
4322672b 2696 $source = new CRM_Activity_DAO_ActivityContact();
2697 $source->activity_id = $activityId;
2698 $source->record_type_id = $sourceID;
2699 $source->contact_id = $contactId;
2700 if ($source->find(TRUE)) {
6a488035
TO
2701 $isSource = TRUE;
2702 }
2703
2704 if ($operation == 'edit') {
2705 if ($isAssignee || $isSource) {
2706 $allow = TRUE;
2707 }
2708 }
2709 if ($operation == 'view') {
2710 if ($isTarget || $isAssignee || $isSource) {
2711 $allow = TRUE;
2712 }
2713 }
2714 }
2715 }
2716 elseif (is_array($hasPermissions[$operation])) {
2717 $allowOperations[$operation] = $allow = TRUE;
2718 }
2719 }
2720 else {
2721 //contact do not have permission.
2722 $allowOperations[$operation] = FALSE;
2723 }
2724 }
2725 else {
2726 //use cache.
2727 //here contact might have supper/non permission.
2728 $allow = $allowOperations[$operation];
2729 }
2730 }
2731
2732 //do further only when operation is granted.
2733 if ($allow) {
b864360d 2734 $actTypeName = CRM_Core_PseudoConstant::getName('CRM_Activity_BAO_Activity', 'activity_type_id', $actTypeId);
6a488035
TO
2735
2736 //do not allow multiple copy / edit action.
e96f025a 2737 $singletonNames = array(
2738 'Open Case',
2739 'Reassigned Case',
2740 'Merge Case',
2741 'Link Cases',
2742 'Assign Case Role',
2743 'Email',
21dfd5f5 2744 'Inbound Email',
e96f025a 2745 );
6a488035
TO
2746
2747 //do not allow to delete these activities, CRM-4543
2748 $doNotDeleteNames = array('Open Case', 'Change Case Type', 'Change Case Status', 'Change Case Start Date');
2749
2750 //allow edit operation.
2751 $allowEditNames = array('Open Case');
2752
ee90a98c
CR
2753 if (CRM_Core_Permission::check('edit inbound email basic information') ||
2754 CRM_Core_Permission::check('edit inbound email basic information and content')
2755 ) {
2756 $allowEditNames[] = 'Inbound Email';
2757 }
2758
6a488035 2759 // do not allow File on Case
e96f025a 2760 $doNotFileNames = array(
2761 'Open Case',
2762 'Change Case Type',
2763 'Change Case Status',
2764 'Change Case Start Date',
2765 'Reassigned Case',
2766 'Merge Case',
2767 'Link Cases',
21dfd5f5 2768 'Assign Case Role',
e96f025a 2769 );
6a488035
TO
2770
2771 if (in_array($actTypeName, $singletonNames)) {
2772 $allow = FALSE;
2773 if ($operation == 'File On Case') {
2774 $allow = (in_array($actTypeName, $doNotFileNames)) ? FALSE : TRUE;
2775 }
2776 if (in_array($operation, $actionOperations)) {
2777 $allow = TRUE;
2778 if ($operation == 'edit') {
2779 $allow = (in_array($actTypeName, $allowEditNames)) ? TRUE : FALSE;
2780 }
2781 elseif ($operation == 'delete') {
2782 $allow = (in_array($actTypeName, $doNotDeleteNames)) ? FALSE : TRUE;
2783 }
2784 }
2785 }
2786 if ($allow && ($operation == 'delete') &&
2787 in_array($actTypeName, $doNotDeleteNames)
2788 ) {
2789 $allow = FALSE;
2790 }
2791
2792 if ($allow && ($operation == 'File On Case') &&
2793 in_array($actTypeName, $doNotFileNames)
2794 ) {
2795 $allow = FALSE;
2796 }
2797
2798 //check settings file for masking actions
2799 //on the basis the activity types
2800 //hide Edit link if activity type is NOT editable
2801 //(special case activities).CRM-5871
2802 if ($allow && in_array($operation, $actionOperations)) {
2803 static $actionFilter = array();
2804 if (!array_key_exists($operation, $actionFilter)) {
2805 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
2806 $actionFilter[$operation] = $xmlProcessor->get('Settings', 'ActivityTypes', FALSE, $operation);
2807 }
2808 if (array_key_exists($operation, $actionFilter[$operation]) &&
2809 in_array($actTypeId, $actionFilter[$operation][$operation])
2810 ) {
2811 $allow = FALSE;
2812 }
2813 }
2814 }
2815
2816 return $allow;
2817 }
2818
2819 /**
100fef9d 2820 * Since we drop 'access CiviCase', allow access
6a488035
TO
2821 * if user has 'access my cases and activities'
2822 * or 'access all cases and activities'
2823 */
00be9182 2824 public static function accessCiviCase() {
077dbf5e 2825 if (!self::enabled()) {
6a488035
TO
2826 return FALSE;
2827 }
2828
2829 if (CRM_Core_Permission::check('access my cases and activities') ||
2830 CRM_Core_Permission::check('access all cases and activities')
2831 ) {
2832 return TRUE;
2833 }
2834
2835 return FALSE;
2836 }
2837
2838 /**
d2e5d2ce 2839 * Verify user has permission to access a case.
077dbf5e
CW
2840 *
2841 * @param int $caseId
64bd5a0e
TO
2842 * @param bool $denyClosed
2843 * Set TRUE if one wants closed cases to be treated as inaccessible.
077dbf5e
CW
2844 *
2845 * @return bool
2846 */
00be9182 2847 public static function accessCase($caseId, $denyClosed = TRUE) {
077dbf5e
CW
2848 if (!$caseId || !self::enabled()) {
2849 return FALSE;
2850 }
2851
3924e596
CW
2852 $params = array('id' => $caseId, 'check_permissions' => TRUE);
2853 if ($denyClosed && !CRM_Core_Permission::check('access all cases and activities')) {
2854 $params['status_id'] = array('!=' => 'Closed');
546abeb1 2855 }
eeb45e43
CW
2856 try {
2857 return (bool) civicrm_api3('Case', 'getcount', $params);
2858 }
2859 catch (CiviCRM_API3_Exception $e) {
2860 // Lack of permissions will throw an exception
2861 return FALSE;
2862 }
077dbf5e
CW
2863 }
2864
6a488035 2865 /**
d2e5d2ce 2866 * Check whether activity is a case Activity.
6a488035 2867 *
64bd5a0e
TO
2868 * @param int $activityID
2869 * Activity id.
6a488035 2870 *
a130e045 2871 * @return bool
6a488035 2872 */
00be9182 2873 public static function isCaseActivity($activityID) {
6a488035
TO
2874 $isCaseActivity = FALSE;
2875 if ($activityID) {
2876 $params = array(1 => array($activityID, 'Integer'));
2877 $query = "SELECT id FROM civicrm_case_activity WHERE activity_id = %1";
2878 if (CRM_Core_DAO::singleValueQuery($query, $params)) {
2879 $isCaseActivity = TRUE;
2880 }
2881 }
2882
2883 return $isCaseActivity;
2884 }
2885
2886 /**
d2e5d2ce 2887 * Get all the case type ids currently in use.
6a488035 2888 *
a6c01b45 2889 * @return array
6a488035 2890 */
00be9182 2891 public static function getUsedCaseType() {
6a488035
TO
2892 static $caseTypeIds;
2893
2894 if (!is_array($caseTypeIds)) {
2895 $query = "SELECT DISTINCT( civicrm_case.case_type_id ) FROM civicrm_case";
2896
2897 $dao = CRM_Core_DAO::executeQuery($query);
2898 $caseTypeIds = array();
2899 while ($dao->fetch()) {
2900 $typeId = explode(CRM_Core_DAO::VALUE_SEPARATOR,
2901 $dao->case_type_id
2902 );
2903 $caseTypeIds[] = $typeId[1];
2904 }
2905 }
2906
2907 return $caseTypeIds;
2908 }
2909
2910 /**
d2e5d2ce 2911 * Get all the case status ids currently in use.
6a488035 2912 *
a6c01b45 2913 * @return array
6a488035 2914 */
00be9182 2915 public static function getUsedCaseStatuses() {
6a488035
TO
2916 static $caseStatusIds;
2917
2918 if (!is_array($caseStatusIds)) {
2919 $query = "SELECT DISTINCT( civicrm_case.status_id ) FROM civicrm_case";
2920
2921 $dao = CRM_Core_DAO::executeQuery($query);
2922 $caseStatusIds = array();
2923 while ($dao->fetch()) {
2924 $caseStatusIds[] = $dao->status_id;
2925 }
2926 }
2927
2928 return $caseStatusIds;
2929 }
2930
2931 /**
d2e5d2ce 2932 * Get all the encounter medium ids currently in use.
72b3a70c 2933 *
6a488035
TO
2934 * @return array
2935 */
00be9182 2936 public static function getUsedEncounterMediums() {
6a488035
TO
2937 static $mediumIds;
2938
2939 if (!is_array($mediumIds)) {
2940 $query = "SELECT DISTINCT( civicrm_activity.medium_id ) FROM civicrm_activity";
2941
2942 $dao = CRM_Core_DAO::executeQuery($query);
2943 $mediumIds = array();
2944 while ($dao->fetch()) {
2945 $mediumIds[] = $dao->medium_id;
2946 }
2947 }
2948
2949 return $mediumIds;
2950 }
2951
2952 /**
100fef9d 2953 * Check case configuration.
6a488035 2954 *
100fef9d 2955 * @param int $contactId
77b97be7 2956 *
a6c01b45 2957 * @return array
6a488035 2958 */
00be9182 2959 public static function isCaseConfigured($contactId = NULL) {
6a488035
TO
2960 $configured = array_fill_keys(array('configured', 'allowToAddNewCase', 'redirectToCaseAdmin'), FALSE);
2961
2962 //lets check for case configured.
2963 $allCasesCount = CRM_Case_BAO_Case::caseCount(NULL, FALSE);
2964 $configured['configured'] = ($allCasesCount) ? TRUE : FALSE;
2965 if (!$configured['configured']) {
2966 //do check for case type and case status.
0372ffa2 2967 $caseTypes = CRM_Case_PseudoConstant::caseType('title', FALSE);
6a488035
TO
2968 if (!empty($caseTypes)) {
2969 $configured['configured'] = TRUE;
2970 if (!$configured['configured']) {
2971 $caseStatuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE);
2972 if (!empty($caseStatuses)) {
2973 $configured['configured'] = TRUE;
2974 }
2975 }
2976 }
2977 }
2978 if ($configured['configured']) {
2979 //do check for active case type and case status.
2980 $caseTypes = CRM_Case_PseudoConstant::caseType();
2981 if (!empty($caseTypes)) {
2982 $caseStatuses = CRM_Case_PseudoConstant::caseStatus();
2983 if (!empty($caseStatuses)) {
2984 $configured['allowToAddNewCase'] = TRUE;
2985 }
2986 }
2987
2988 //do we need to redirect user to case admin.
2989 if (!$configured['allowToAddNewCase'] && $contactId) {
2990 //check for current contact case count.
2991 $currentContatCasesCount = CRM_Case_BAO_Case::caseCount($contactId);
2992 //redirect user to case admin page.
2993 if (!$currentContatCasesCount) {
2994 $configured['redirectToCaseAdmin'] = TRUE;
2995 }
2996 }
2997 }
2998
2999 return $configured;
3000 }
3001
d6f468d3 3002 /**
d2e5d2ce 3003 * Used during case component enablement and during ugprade.
72b3a70c
CW
3004 *
3005 * @return bool
6a488035 3006 */
00be9182 3007 public static function createCaseViews() {
6a4257d4 3008 $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
a19fc402
TO
3009 $dao = new CRM_Core_DAO();
3010
6a488035 3011 $sql = self::createCaseViewsQuery('upcoming');
6a488035
TO
3012 $dao->query($sql);
3013 if (PEAR::getStaticProperty('DB_DataObject', 'lastError')) {
6a488035
TO
3014 return FALSE;
3015 }
3016
3017 // Above error doesn't get caught?
3018 $doublecheck = $dao->singleValueQuery("SELECT count(id) FROM civicrm_view_case_activity_upcoming");
3019 if (is_null($doublecheck)) {
3020 return FALSE;
3021 }
3022
3023 $sql = self::createCaseViewsQuery('recent');
6a488035
TO
3024 $dao->query($sql);
3025 if (PEAR::getStaticProperty('DB_DataObject', 'lastError')) {
6a488035
TO
3026 return FALSE;
3027 }
3028
3029 // Above error doesn't get caught?
3030 $doublecheck = $dao->singleValueQuery("SELECT count(id) FROM civicrm_view_case_activity_recent");
3031 if (is_null($doublecheck)) {
3032 return FALSE;
3033 }
3034
3035 return TRUE;
3036 }
3037
d6f468d3 3038 /**
100fef9d 3039 * Helper function, also used by the upgrade in case of error
72b3a70c 3040 *
cde2037d
EM
3041 * @param string $section
3042 *
72b3a70c 3043 * @return string
6a488035 3044 */
00be9182 3045 public static function createCaseViewsQuery($section = 'upcoming') {
6a488035 3046 $sql = "";
d66c61b6 3047 $scheduled_id = CRM_Core_Pseudoconstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Scheduled');
6a488035
TO
3048 switch ($section) {
3049 case 'upcoming':
3050 $sql = "CREATE OR REPLACE VIEW `civicrm_view_case_activity_upcoming`
3051 AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
3052 FROM civicrm_case_activity ca
3053 INNER JOIN civicrm_activity a ON ca.activity_id=a.id
3cf1fae9 3054 WHERE a.activity_date_time =
2b95a25b 3055(SELECT b.activity_date_time FROM civicrm_case_activity bca
3056 INNER JOIN civicrm_activity b ON bca.activity_id=b.id
3057 WHERE b.activity_date_time <= DATE_ADD( NOW(), INTERVAL 14 DAY )
3058 AND b.is_current_revision = 1 AND b.is_deleted=0 AND b.status_id = $scheduled_id
3059 AND bca.case_id = ca.case_id ORDER BY b.activity_date_time ASC LIMIT 1)";
6a488035
TO
3060 break;
3061
3062 case 'recent':
3063 $sql = "CREATE OR REPLACE VIEW `civicrm_view_case_activity_recent`
3064 AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
3065 FROM civicrm_case_activity ca
3066 INNER JOIN civicrm_activity a ON ca.activity_id=a.id
3cf1fae9 3067 WHERE a.activity_date_time =
2b95a25b 3068(SELECT b.activity_date_time FROM civicrm_case_activity bca
3069 INNER JOIN civicrm_activity b ON bca.activity_id=b.id
3070 WHERE b.activity_date_time >= DATE_SUB( NOW(), INTERVAL 14 DAY )
3071 AND b.is_current_revision = 1 AND b.is_deleted=0 AND b.status_id <> $scheduled_id
3072 AND bca.case_id = ca.case_id ORDER BY b.activity_date_time DESC LIMIT 1)";
6a488035
TO
3073 break;
3074 }
6a488035 3075 return $sql;
e96f025a 3076 }
3077
3078 /**
100fef9d 3079 * Add/copy relationships, when new client is added for a case
e96f025a 3080 *
64bd5a0e
TO
3081 * @param int $caseId
3082 * Case id.
3083 * @param int $contactId
3084 * Contact id / new client id.
e96f025a 3085 */
00be9182 3086 public static function addCaseRelationships($caseId, $contactId) {
44466d80
KJ
3087 // get the case role / relationships for the case
3088 $caseRelationships = new CRM_Contact_DAO_Relationship();
3089 $caseRelationships->case_id = $caseId;
3090 $caseRelationships->find();
3091 $relationshipTypes = array();
3092
3093 // make sure we don't add duplicate relationships of same relationship type.
3094 while ($caseRelationships->fetch() && !in_array($caseRelationships->relationship_type_id, $relationshipTypes)) {
3095 $values = array();
3096 CRM_Core_DAO::storeValues($caseRelationships, $values);
3097
3098 // add relationship for new client.
3099 $newRelationship = new CRM_Contact_DAO_Relationship();
3100 $newRelationship->copyValues($values);
3101 $newRelationship->id = NULL;
3102 $newRelationship->case_id = $caseId;
3103 $newRelationship->contact_id_a = $contactId;
3104 $newRelationship->end_date = CRM_Utils_Date::isoToMysql($caseRelationships->end_date);
3105 $newRelationship->start_date = CRM_Utils_Date::isoToMysql($caseRelationships->start_date);
3106
3107 // another check to avoid duplicate relationship, in cases where client is removed and re-added again.
3108 if (!$newRelationship->find(TRUE)) {
3109 $newRelationship->save();
3110 }
44466d80
KJ
3111
3112 // store relationship type of newly created relationship
3113 $relationshipTypes[] = $caseRelationships->relationship_type_id;
3114 }
6a488035 3115 }
14a679f1
KJ
3116
3117 /**
d2e5d2ce 3118 * Get the list of clients for a case.
14a679f1
KJ
3119 *
3120 * @param int $caseId
3121 *
a6c01b45
CW
3122 * @return array
3123 * associated array with client ids
14a679f1 3124 */
00be9182 3125 public static function getCaseClients($caseId) {
14a679f1
KJ
3126 $clients = array();
3127 $caseContact = new CRM_Case_DAO_CaseContact();
3128 $caseContact->case_id = $caseId;
78762324 3129 $caseContact->orderBy('id');
14a679f1
KJ
3130 $caseContact->find();
3131
e96f025a 3132 while ($caseContact->fetch()) {
14a679f1
KJ
3133 $clients[] = $caseContact->contact_id;
3134 }
3135
3136 return $clients;
3137 }
16c0ec8d 3138
3b1c37fe
CW
3139 /**
3140 * @param int $caseId
3141 * @param string $direction
3142 * @param int $cid
3143 * @param int $relTypeId
3144 * @throws \CRM_Core_Exception
3145 * @throws \CiviCRM_API3_Exception
3146 */
3147 public static function endCaseRole($caseId, $direction, $cid, $relTypeId) {
3148 // Validate inputs
3149 if ($direction !== 'a' && $direction !== 'b') {
3150 throw new CRM_Core_Exception('Invalid relationship direction');
3151 }
3152
3153 // This case might have multiple clients, so we lookup by relationship instead of by id to get them all
3154 $sql = "SELECT id FROM civicrm_relationship WHERE case_id = %1 AND contact_id_{$direction} = %2 AND relationship_type_id = %3";
3155 $dao = CRM_Core_DAO::executeQuery($sql, array(
3156 1 => array($caseId, 'Positive'),
3157 2 => array($cid, 'Positive'),
3158 3 => array($relTypeId, 'Positive'),
3159 ));
3160 while ($dao->fetch()) {
3161 civicrm_api3('relationship', 'create', array(
3162 'id' => $dao->id,
3163 'is_active' => 0,
3164 'end_date' => 'now',
3165 ));
3166 }
3167 }
3168
16c0ec8d
CW
3169 /**
3170 * Get options for a given case field.
3171 * @see CRM_Core_DAO::buildOptions
3172 *
64bd5a0e
TO
3173 * @param string $fieldName
3174 * @param string $context
408b79bf 3175 * @see CRM_Core_DAO::buildOptionsContext
64bd5a0e 3176 * @param array $props
72b3a70c 3177 * Whatever is known about this dao object.
77b97be7 3178 *
a130e045 3179 * @return array|bool
16c0ec8d
CW
3180 */
3181 public static function buildOptions($fieldName, $context = NULL, $props = array()) {
3182 $className = __CLASS__;
3183 $params = array();
3184 switch ($fieldName) {
3185 // This field is not part of this object but the api supports it
3186 case 'medium_id':
3187 $className = 'CRM_Activity_BAO_Activity';
3188 break;
31c28ed5
CW
3189
3190 // Filter status id by case type id
3191 case 'status_id':
3192 if (!empty($props['case_type_id'])) {
3193 $idField = is_numeric($props['case_type_id']) ? 'id' : 'name';
3194 $caseType = civicrm_api3('CaseType', 'getsingle', array($idField => $props['case_type_id'], 'return' => 'definition'));
3195 if (!empty($caseType['definition']['statuses'])) {
3196 $params['condition'] = 'v.name IN ("' . implode('","', $caseType['definition']['statuses']) . '")';
3197 }
3198 }
3199 break;
16c0ec8d
CW
3200 }
3201 return CRM_Core_PseudoConstant::get($className, $fieldName, $params, $context);
3202 }
96025800 3203
174a1918
CW
3204 /**
3205 * @inheritDoc
3206 */
20e41014 3207 public function addSelectWhereClause() {
0b80f0b4
CW
3208 // We always return an array with these keys, even if they are empty,
3209 // because this tells the query builder that we have considered these fields for acls
ff9340a4
CW
3210 $clauses = array(
3211 'id' => array(),
3212 // Only case admins can view deleted cases
0b80f0b4 3213 'is_deleted' => CRM_Core_Permission::check('administer CiviCase') ? array() : array("= 0"),
ff9340a4 3214 );
174a1918 3215 // Ensure the user has permission to view the case client
d1d3c04a 3216 $contactClause = CRM_Utils_SQL::mergeSubquery('Contact');
ff9340a4
CW
3217 if ($contactClause) {
3218 $contactClause = implode(' AND contact_id ', $contactClause);
3219 $clauses['id'][] = "IN (SELECT case_id FROM civicrm_case_contact WHERE contact_id $contactClause)";
174a1918 3220 }
0b80f0b4 3221 // The api gatekeeper ensures the user has at least "access my cases and activities"
174a1918
CW
3222 // so if they do not have permission to see all cases we'll assume they can only access their own
3223 if (!CRM_Core_Permission::check('access all cases and activities')) {
3224 $user = (int) CRM_Core_Session::getLoggedInContactID();
ff9340a4 3225 $clauses['id'][] = "IN (
174a1918 3226 SELECT r.case_id FROM civicrm_relationship r, civicrm_case_contact cc WHERE r.is_active = 1 AND cc.case_id = r.case_id AND (
ff9340a4 3227 (r.contact_id_a = cc.contact_id AND r.contact_id_b = $user) OR (r.contact_id_b = cc.contact_id AND r.contact_id_a = $user)
174a1918
CW
3228 )
3229 )";
3230 }
2b240c0c 3231 CRM_Utils_Hook::selectWhereClause($this, $clauses);
ff9340a4 3232 return $clauses;
174a1918
CW
3233 }
3234
8aeeea00 3235 /**
3cf1fae9 3236 * CRM-20308: Method to get the contact id to use as from contact for email copy
8aeeea00
EH
3237 * 1. Activity Added by Contact's email address
3238 * 2. System Default From Address
3239 * 3. Default Organization Contact email address
3240 * 4. Logged in user
3241 *
3cf1fae9 3242 * @param int $activityID
3243 *
8aeeea00
EH
3244 * @return mixed $emailFromContactId
3245 * @see https://issues.civicrm.org/jira/browse/CRM-20308
3246 */
3cf1fae9 3247 public static function getReceiptFrom($activityID) {
3248 $name = $address = NULL;
3249
4c981f37
MW
3250 if (!empty($activityID) && (Civi::settings()->get('allow_mail_from_logged_in_contact'))) {
3251 // This breaks SPF/DMARC if email is sent from an email address that the server is not authorised to send from.
3252 // so we can disable this behaviour with the "allow_mail_from_logged_in_contact" setting.
3cf1fae9 3253 // There is always a 'Added by' contact for a activity,
3254 // so we can safely use ActivityContact.Getvalue API
3255 $sourceContactId = civicrm_api3('ActivityContact', 'getvalue', array(
3256 'activity_id' => $activityID,
3257 'record_type_id' => 'Activity Source',
3258 'return' => 'contact_id',
3259 ));
3260 list($name, $address) = CRM_Contact_BAO_Contact_Location::getEmailDetails($sourceContactId);
8aeeea00 3261 }
3cf1fae9 3262
3263 // If 'From' email address not found for Source Activity Contact then
3264 // fetch the email from domain or logged in user.
3265 if (empty($address)) {
3266 list($name, $address) = CRM_Core_BAO_Domain::getDefaultReceiptFrom();
8aeeea00 3267 }
3cf1fae9 3268
8aeeea00
EH
3269 return "$name <$address>";
3270 }
3271
1d6f94ab
CW
3272 /**
3273 * @return array
3274 */
3275 public static function getEntityRefFilters() {
3276 $filters = [
3277 [
3278 'key' => 'case_id.case_type_id',
3279 'value' => ts('Case Type'),
3280 'entity' => 'Case',
3281 ],
3282 [
3283 'key' => 'case_id.status_id',
3284 'value' => ts('Case Status'),
3285 'entity' => 'Case',
3286 ],
3287 ];
3288 foreach (CRM_Contact_BAO_Contact::getEntityRefFilters() as $filter) {
2229cf4f 3289 $filter += ['entity' => 'Contact'];
1d6f94ab
CW
3290 $filter['key'] = 'contact_id.' . $filter['key'];
3291 $filters[] = $filter;
3292 }
3293 return $filters;
3294 }
3295
6a488035 3296}