Merge pull request #14480 from JMAConsulting/core-553
[civicrm-core.git] / CRM / Case / Form / CaseView.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2019
32 */
33
34 /**
35 * This class generates view mode for CiviCase.
36 */
37 class CRM_Case_Form_CaseView extends CRM_Core_Form {
38 /**
39 * Check for merge cases.
40 * @var bool
41 */
42 private $_mergeCases = FALSE;
43
44 /**
45 * Set variables up before form is built.
46 */
47 public function preProcess() {
48 $this->_showRelatedCases = CRM_Utils_Array::value('relatedCases', $_GET);
49
50 $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
51 $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients();
52 $this->assign('multiClient', $isMultiClient);
53
54 //pull the related cases.
55 $this->assign('showRelatedCases', FALSE);
56 if ($this->_showRelatedCases) {
57 $relatedCases = $this->get('relatedCases');
58 if (!isset($relatedCases)) {
59 $cId = CRM_Utils_Request::retrieve('cid', 'Integer');
60 $caseId = CRM_Utils_Request::retrieve('id', 'Integer');
61 $relatedCases = CRM_Case_BAO_Case::getRelatedCases($caseId);
62 }
63 $this->assign('relatedCases', $relatedCases);
64 $this->assign('showRelatedCases', TRUE);
65 CRM_Utils_System::setTitle(ts('Related Cases'));
66 return;
67 }
68
69 $this->_hasAccessToAllCases = CRM_Core_Permission::check('access all cases and activities');
70 $this->assign('hasAccessToAllCases', $this->_hasAccessToAllCases);
71
72 $this->assign('contactID', $this->_contactID = (int) $this->get('cid'));
73 $this->assign('caseID', $this->_caseID = (int) $this->get('id'));
74
75 // Access check.
76 if (!CRM_Case_BAO_Case::accessCase($this->_caseID, FALSE)) {
77 CRM_Core_Error::statusBounce(ts('You do not have permission to access this case.'));
78 }
79
80 $fulltext = CRM_Utils_Request::retrieve('context', 'Alphanumeric');
81 if ($fulltext == 'fulltext') {
82 $this->assign('fulltext', $fulltext);
83 }
84
85 $this->assign('contactType', CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type'));
86 $this->assign('userID', CRM_Core_Session::getLoggedInContactID());
87
88 //retrieve details about case
89 $params = ['id' => $this->_caseID];
90
91 $returnProperties = ['case_type_id', 'subject', 'status_id', 'start_date'];
92 CRM_Core_DAO::commonRetrieve('CRM_Case_BAO_Case', $params, $values, $returnProperties);
93
94 $statuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE);
95 $caseTypeName = CRM_Case_BAO_Case::getCaseType($this->_caseID, 'name');
96 $caseType = CRM_Case_BAO_Case::getCaseType($this->_caseID);
97
98 $this->_caseDetails = [
99 'case_type' => $caseType,
100 'case_status' => CRM_Utils_Array::value($values['case_status_id'], $statuses),
101 'case_subject' => CRM_Utils_Array::value('subject', $values),
102 'case_start_date' => $values['case_start_date'],
103 ];
104 $this->_caseType = $caseTypeName;
105 $this->assign('caseDetails', $this->_caseDetails);
106
107 $reportUrl = CRM_Utils_System::url('civicrm/case/report',
108 "reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&asn=",
109 FALSE, NULL, FALSE
110 );
111 $this->assign('reportUrl', $reportUrl);
112
113 // add to recently viewed
114
115 $url = CRM_Utils_System::url('civicrm/contact/view/case',
116 "action=view&reset=1&id={$this->_caseID}&cid={$this->_contactID}&context=home"
117 );
118
119 $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactID);
120 $this->assign('displayName', $displayName);
121
122 CRM_Utils_System::setTitle($displayName . ' - ' . $caseType);
123
124 $recentOther = [];
125 if (CRM_Core_Permission::checkActionPermission('CiviCase', CRM_Core_Action::DELETE)) {
126 $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/case',
127 "action=delete&reset=1&id={$this->_caseID}&cid={$this->_contactID}&context=home"
128 );
129 }
130
131 // Add the recently viewed case
132 CRM_Utils_Recent::add($displayName . ' - ' . $caseType,
133 $url,
134 $this->_caseID,
135 'Case',
136 $this->_contactID,
137 NULL,
138 $recentOther
139 );
140
141 //get the related cases for given case.
142 $relatedCases = $this->get('relatedCases');
143 if (!isset($relatedCases)) {
144 $relatedCases = CRM_Case_BAO_Case::getRelatedCases($this->_caseID);
145 $relatedCases = empty($relatedCases) ? FALSE : $relatedCases;
146 $this->set('relatedCases', $relatedCases);
147 }
148 $this->assign('hasRelatedCases', (bool) $relatedCases);
149 if ($relatedCases) {
150 $this->assign('relatedCaseLabel', ts('%1 Related Case', [
151 'count' => count($relatedCases),
152 'plural' => '%1 Related Cases',
153 ]));
154 $this->assign('relatedCaseUrl', CRM_Utils_System::url('civicrm/contact/view/case', [
155 'id' => $this->_caseID,
156 'cid' => $this->_contactID,
157 'relatedCases' => 1,
158 'action' => 'view',
159 ]));
160 }
161
162 $entitySubType = !empty($values['case_type_id']) ? $values['case_type_id'] : NULL;
163 $this->assign('caseTypeID', $entitySubType);
164 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Case',
165 NULL,
166 $this->_caseID,
167 NULL,
168 $entitySubType
169 );
170 CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree, FALSE, NULL, NULL, NULL, $this->_caseID);
171 }
172
173 /**
174 * Set default values for the form.
175 *
176 * @return array;
177 */
178 public function setDefaultValues() {
179 $defaults = [];
180 return $defaults;
181 }
182
183 /**
184 * Build the form object.
185 */
186 public function buildQuickForm() {
187 //this call is for show related cases.
188 if ($this->_showRelatedCases) {
189 return;
190 }
191
192 $allowedRelationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType($this->_contactID);
193
194 CRM_Core_Resources::singleton()
195 ->addScriptFile('civicrm', 'js/crm.livePage.js', 1, 'html-header')
196 ->addScriptFile('civicrm', 'templates/CRM/Case/Form/CaseView.js', 2, 'html-header')
197 ->addVars('relationshipTypes', CRM_Contact_Form_Relationship::getRelationshipTypeMetadata($allowedRelationshipTypes));
198
199 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
200 $caseRoles = $xmlProcessor->get($this->_caseType, 'CaseRoles');
201 $reports = $xmlProcessor->get($this->_caseType, 'ActivitySets');
202
203 //adding case manager.CRM-4510.
204 $managerRoleId = $xmlProcessor->getCaseManagerRoleId($this->_caseType);
205 if (!empty($managerRoleId)) {
206 $caseRoles[$managerRoleId] = $caseRoles[$managerRoleId] . '<br />' . '(' . ts('Case Manager') . ')';
207 }
208
209 $aTypes = $xmlProcessor->get($this->_caseType, 'ActivityTypes', TRUE);
210
211 $allActTypes = CRM_Activity_BAO_Activity::buildOptions('activity_type_id', 'validate');
212 $emailActivityType = array_search('Email', $allActTypes);
213 $pdfActivityType = array_search('Print PDF Letter', $allActTypes);
214
215 if ($pdfActivityType) {
216 $this->assign('exportDoc', CRM_Utils_System::url('civicrm/activity/pdf/add',
217 "action=add&context=standalone&reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&atype=$pdfActivityType"));
218 }
219
220 // remove Open Case activity type since we're inside an existing case
221 if ($openActTypeId = array_search('Open Case', $allActTypes)) {
222 unset($aTypes[$openActTypeId]);
223 }
224
225 // Only show "link cases" activity if other cases exist.
226 $linkActTypeId = array_search('Link Cases', $allActTypes);
227 if ($linkActTypeId) {
228 $count = civicrm_api3('Case', 'getcount', [
229 'check_permissions' => TRUE,
230 'id' => ['!=' => $this->_caseID],
231 'is_deleted' => 0,
232 ]);
233 if (!$count) {
234 unset($aTypes[$linkActTypeId]);
235 }
236 }
237
238 if (!$xmlProcessor->getNaturalActivityTypeSort()) {
239 asort($aTypes);
240 }
241
242 $activityLinks = ['' => ts('Add Activity')];
243 foreach ($aTypes as $type => $label) {
244 if ($type == $emailActivityType) {
245 $url = CRM_Utils_System::url('civicrm/activity/email/add',
246 "action=add&context=standalone&reset=1&caseid={$this->_caseID}&atype=$type",
247 FALSE, NULL, FALSE
248 );
249 }
250 elseif ($type == $pdfActivityType) {
251 $url = CRM_Utils_System::url('civicrm/activity/pdf/add',
252 "action=add&context=standalone&reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&atype=$type",
253 FALSE, NULL, FALSE);
254 }
255 else {
256 $url = CRM_Utils_System::url('civicrm/case/activity',
257 "action=add&reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&atype=$type",
258 FALSE, NULL, FALSE
259 );
260 }
261 $activityLinks[$url] = $label;
262 }
263
264 $this->add('select', 'add_activity_type_id', '', $activityLinks, FALSE, ['class' => 'crm-select2 crm-action-menu fa-calendar-check-o twenty']);
265 if ($this->_hasAccessToAllCases) {
266 $this->add('select', 'report_id', '',
267 ['' => ts('Activity Audit')] + $reports,
268 FALSE,
269 ['class' => 'crm-select2 crm-action-menu fa-list-alt']
270 );
271 $this->add('select', 'timeline_id', '',
272 ['' => ts('Add Timeline')] + $reports,
273 FALSE,
274 ['class' => 'crm-select2 crm-action-menu fa-list-ol']
275 );
276 }
277 $this->addElement('submit', $this->getButtonName('next'), ' ', ['class' => 'hiddenElement']);
278
279 $this->buildMergeCaseForm();
280
281 //call activity form
282 self::activityForm($this, $aTypes);
283
284 //get case related relationships (Case Role)
285 $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($this->_contactID, $this->_caseID);
286
287 //save special label because we unset it in the loop
288 $managerLabel = empty($managerRoleId) ? '' : $caseRoles[$managerRoleId];
289
290 foreach ($caseRelationships as $key => & $value) {
291 if (!empty($managerRoleId)) {
292 if (substr($managerRoleId, 0, -4) == $value['relation_type'] && substr($managerRoleId, -3) == $value['relationship_direction']) {
293 $value['relation'] = $managerLabel;
294 }
295 }
296
297 //calculate roles that don't have relationships
298 if (!empty($caseRoles[$value['relation_type']])) {
299 unset($caseRoles[$value['relation_type']]);
300 }
301 }
302
303 $this->assign('caseRelationships', $caseRelationships);
304
305 //also add client as role. CRM-4438
306 $caseRoles['client'] = CRM_Case_BAO_Case::getContactNames($this->_caseID);
307
308 $this->assign('caseRoles', $caseRoles);
309
310 // Retrieve ALL client relationships
311 $relClient = CRM_Contact_BAO_Relationship::getRelationship($this->_contactID,
312 CRM_Contact_BAO_Relationship::CURRENT,
313 0, 0, 0, NULL, NULL, FALSE
314 );
315
316 // Now build 'Other Relationships' array by removing relationships that are already listed under Case Roles
317 // so they don't show up twice.
318 $clientRelationships = [];
319 foreach ($relClient as $r) {
320 if (!array_key_exists($r['id'], $caseRelationships)) {
321 $clientRelationships[] = $r;
322 }
323 }
324 $this->assign('clientRelationships', $clientRelationships);
325
326 // Now global contact list that appears on all cases.
327 $globalGroupInfo = [];
328 CRM_Case_BAO_Case::getGlobalContacts($globalGroupInfo);
329 $this->assign('globalGroupInfo', $globalGroupInfo);
330
331 // List relationship types for adding an arbitrary new role to the case
332 $this->add('select',
333 'role_type',
334 ts('Relationship Type'),
335 ['' => ts('- select type -')] + $allowedRelationshipTypes,
336 FALSE,
337 ['class' => 'crm-select2 twenty', 'data-select-params' => '{"allowClear": false}']
338 );
339
340 $hookCaseSummary = CRM_Utils_Hook::caseSummary($this->_caseID);
341 if (is_array($hookCaseSummary)) {
342 $this->assign('hookCaseSummary', $hookCaseSummary);
343 }
344
345 $allTags = CRM_Core_BAO_Tag::getColorTags('civicrm_case');
346
347 if (!empty($allTags)) {
348 $this->add('select2', 'case_tag', ts('Tags'), $allTags, FALSE,
349 ['id' => 'tags', 'multiple' => 'multiple']
350 );
351
352 $tags = CRM_Core_BAO_EntityTag::getTag($this->_caseID, 'civicrm_case');
353
354 foreach ($tags as $tid) {
355 $tagInfo = CRM_Utils_Array::findInTree($tid, $allTags);
356 if ($tagInfo) {
357 $tags[$tid] = $tagInfo;
358 }
359 else {
360 unset($tags[$tid]);
361 }
362 }
363
364 $this->setDefaults(['case_tag' => implode(',', array_keys($tags))]);
365
366 $this->assign('tags', $tags);
367 $this->assign('showTags', TRUE);
368 }
369 else {
370 $this->assign('showTags', FALSE);
371 }
372
373 // build tagset widget
374
375 // see if we have any tagsets which can be assigned to cases
376 $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_case');
377 $tagSetTags = [];
378 if ($parentNames) {
379 $this->assign('showTags', TRUE);
380 $tagSetItems = civicrm_api3('entityTag', 'get', [
381 'entity_id' => $this->_caseID,
382 'entity_table' => 'civicrm_case',
383 'tag_id.parent_id.is_tagset' => 1,
384 'options' => ['limit' => 0],
385 'return' => ["tag_id.parent_id", "tag_id.parent_id.name", "tag_id.name"],
386 ]);
387 foreach ($tagSetItems['values'] as $tag) {
388 $tagSetTags += [
389 $tag['tag_id.parent_id'] => [
390 'name' => $tag['tag_id.parent_id.name'],
391 'items' => [],
392 ],
393 ];
394 $tagSetTags[$tag['tag_id.parent_id']]['items'][] = $tag['tag_id.name'];
395 }
396 }
397 $this->assign('tagSetTags', $tagSetTags);
398 CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_case', $this->_caseID, FALSE, TRUE);
399
400 $this->addButtons([
401 [
402 'type' => 'cancel',
403 'name' => ts('Done'),
404 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
405 'isDefault' => TRUE,
406 ],
407 ]);
408 }
409
410 /**
411 * Process the form.
412 */
413 public function postProcess() {
414 $params = $this->controller->exportValues($this->_name);
415 $buttonName = $this->controller->getButtonName();
416
417 // user context
418 $url = CRM_Utils_System::url('civicrm/contact/view/case',
419 "reset=1&action=view&cid={$this->_contactID}&id={$this->_caseID}&show=1"
420 );
421 $session = CRM_Core_Session::singleton();
422 $session->pushUserContext($url);
423
424 if (!empty($params['timeline_id']) && !empty($_POST['_qf_CaseView_next'])) {
425 civicrm_api3('Case', 'addtimeline', [
426 'case_id' => $this->_caseID,
427 'timeline' => $params['timeline_id'],
428 ]);
429
430 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
431 $reports = $xmlProcessor->get($this->_caseType, 'ActivitySets');
432 CRM_Core_Session::setStatus(ts('Activities from the %1 activity set have been added to this case.',
433 [1 => $reports[$params['timeline_id']]]
434 ), ts('Done'), 'success');
435 }
436 elseif ($this->_mergeCases &&
437 $buttonName == '_qf_CaseView_next_merge_case'
438 ) {
439
440 $mainCaseId = $params['merge_case_id'];
441 $otherCaseId = $this->_caseID;
442
443 //merge two cases.
444 CRM_Case_BAO_Case::mergeCases($this->_contactID, $mainCaseId, NULL, $otherCaseId);
445
446 //redirect user to main case view.
447 $url = CRM_Utils_System::url('civicrm/contact/view/case',
448 "reset=1&action=view&cid={$this->_contactID}&id={$mainCaseId}&show=1"
449 );
450 $session = CRM_Core_Session::singleton();
451 $session->pushUserContext($url);
452 }
453 }
454
455 /**
456 * Build the activity selector/datatable
457 * @param CRM_Core_Form $form
458 * @param array $aTypes
459 * To include acivities related to current case id $form->_caseID.
460 */
461 public static function activityForm($form, $aTypes = []) {
462 $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($form->_contactID, $form->_caseID);
463 //build reporter select
464 $reporters = ["" => ts(' - any reporter - ')];
465 foreach ($caseRelationships as $key => & $value) {
466 $reporters[$value['cid']] = $value['name'] . " ( {$value['relation']} )";
467 }
468 $form->add('select', 'reporter_id', ts('Reporter/Role'), $reporters, FALSE, ['id' => 'reporter_id_' . $form->_caseID]);
469
470 // take all case activity types for search filter, CRM-7187
471 $aTypesFilter = [];
472 $allCaseActTypes = CRM_Case_PseudoConstant::caseActivityType();
473 foreach ($allCaseActTypes as $typeDetails) {
474 if (!in_array($typeDetails['name'], ['Open Case'])) {
475 $aTypesFilter[$typeDetails['id']] = CRM_Utils_Array::value('label', $typeDetails);
476 }
477 }
478 $aTypesFilter = $aTypesFilter + $aTypes;
479 asort($aTypesFilter);
480 $form->add('select', 'activity_type_filter_id', ts('Activity Type'), ['' => ts('- select activity type -')] + $aTypesFilter, FALSE, ['id' => 'activity_type_filter_id_' . $form->_caseID]);
481
482 $activityStatus = CRM_Core_PseudoConstant::activityStatus();
483 $form->add('select', 'status_id', ts('Status'), ["" => ts(' - any status - ')] + $activityStatus, FALSE, ['id' => 'status_id_' . $form->_caseID]);
484
485 // activity date search filters
486 $form->add('datepicker', 'activity_date_low_' . $form->_caseID, ts('Activity Dates - From'), [], FALSE, ['time' => FALSE]);
487 $form->add('datepicker', 'activity_date_high_' . $form->_caseID, ts('To'), [], FALSE, ['time' => FALSE]);
488
489 if (CRM_Core_Permission::check('administer CiviCRM')) {
490 $form->add('checkbox', 'activity_deleted', ts('Deleted Activities'), '', FALSE, ['id' => 'activity_deleted_' . $form->_caseID]);
491 }
492 }
493
494 /**
495 * Form elements for merging cases
496 */
497 public function buildMergeCaseForm() {
498 $otherCases = [];
499 $result = civicrm_api3('Case', 'get', [
500 'check_permissions' => TRUE,
501 'contact_id' => $this->_contactID,
502 'is_deleted' => 0,
503 'id' => ['!=' => $this->_caseID],
504 'return' => ['id', 'start_date', 'case_type_id.title'],
505 ]);
506 foreach ($result['values'] as $id => $case) {
507 $otherCases[$id] = "#$id: {$case['case_type_id.title']} " . ts('(opened %1)', [1 => $case['start_date']]);
508 }
509
510 $this->assign('mergeCases', $this->_mergeCases = (bool) $otherCases);
511
512 if ($otherCases) {
513 $this->add('select', 'merge_case_id',
514 ts('Select Case for Merge'),
515 [
516 '' => ts('- select case -'),
517 ] + $otherCases,
518 FALSE,
519 ['class' => 'crm-select2 huge']
520 );
521 $this->addElement('submit',
522 $this->getButtonName('next', 'merge_case'),
523 ts('Merge'),
524 [
525 'class' => 'hiddenElement',
526 ]
527 );
528 }
529 }
530
531 }