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