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