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