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