Merge pull request #18276 from civicrm/5.29
[civicrm-core.git] / CRM / Case / Form / Case.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 form components for case activity.
20 */
21 class CRM_Case_Form_Case extends CRM_Core_Form {
22
23 /**
24 * The context
25 *
26 * @var string
27 */
28 public $_context = 'case';
29
30 /**
31 * Case Id
32 * @var int
33 */
34 public $_caseId = NULL;
35
36 /**
37 * Client Id
38 * @var int
39 */
40 public $_currentlyViewedContactId = NULL;
41
42 /**
43 * Activity Type File
44 * @var int
45 */
46 public $_activityTypeFile = NULL;
47
48 /**
49 * Logged in contact Id
50 * @var int
51 */
52 public $_currentUserId = NULL;
53
54 /**
55 * Activity type Id
56 * @var int
57 */
58 public $_activityTypeId = NULL;
59
60 /**
61 * Activity type Id
62 * @var int
63 */
64 public $_activityId = NULL;
65
66 /**
67 * Action
68 * @var int
69 */
70 public $_action;
71
72 /**
73 * Case type id
74 * @var int
75 */
76 public $_caseTypeId = NULL;
77
78 public $submitOnce = TRUE;
79
80 /**
81 * Explicitly declare the entity api name.
82 */
83 public function getDefaultEntity() {
84 return 'Case';
85 }
86
87 /**
88 * Get the entity id being edited.
89 *
90 * @return int|null
91 */
92 public function getEntityId() {
93 return $this->_caseId;
94 }
95
96 /**
97 * Build the form object.
98 */
99 public function preProcess() {
100 if (empty($this->_action)) {
101 $this->_action = CRM_Core_Action::ADD;
102 }
103
104 $this->_caseId = CRM_Utils_Request::retrieve('id', 'Positive', $this);
105
106 $this->_currentlyViewedContactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
107
108 if ($this->_action & CRM_Core_Action::ADD && !$this->_currentlyViewedContactId) {
109 // check for add contacts permissions
110 if (!CRM_Core_Permission::check('add contacts')) {
111 CRM_Utils_System::permissionDenied();
112 return;
113 }
114 }
115
116 //CRM-4418
117 if (!CRM_Core_Permission::checkActionPermission('CiviCase', $this->_action)) {
118 CRM_Core_Error::statusBounce(ts('You do not have permission to access this page.'));
119 }
120
121 if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) {
122 return TRUE;
123 }
124
125 if (!$this->_caseId) {
126 $caseAttributes = [
127 'case_type_id' => ts('Case Type'),
128 'status_id' => ts('Case Status'),
129 'medium_id' => ts('Activity Medium'),
130 ];
131
132 foreach ($caseAttributes as $key => $label) {
133 if (!CRM_Case_BAO_Case::buildOptions($key, 'create')) {
134 CRM_Core_Error::statusBounce(ts('You do not have any active %1', [1 => $label]));
135 }
136 }
137 }
138
139 if ($this->_action & CRM_Core_Action::ADD) {
140 $this->_activityTypeId = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Open Case');
141 if (!$this->_activityTypeId) {
142 CRM_Core_Error::statusBounce(ts('The Open Case activity type is missing or disabled. Please have your site administrator check Administer > Option Lists > Activity Types for the CiviCase component.'));
143 }
144 }
145
146 //check for case permissions.
147 if (!CRM_Case_BAO_Case::accessCiviCase()) {
148 CRM_Core_Error::statusBounce(ts('You are not authorized to access this page.'));
149 }
150 if (($this->_action & CRM_Core_Action::ADD) &&
151 (!CRM_Core_Permission::check('access all cases and activities') &&
152 !CRM_Core_Permission::check('add cases')
153 )
154 ) {
155 CRM_Core_Error::statusBounce(ts('You are not authorized to access this page.'));
156 }
157
158 if ($this->_activityTypeFile = CRM_Activity_BAO_Activity::getFileForActivityTypeId($this->_activityTypeId,
159 'Case'
160 )
161 ) {
162 $this->assign('activityTypeFile', $this->_activityTypeFile);
163 }
164
165 $details = CRM_Case_PseudoConstant::caseActivityType(FALSE);
166
167 CRM_Utils_System::setTitle($details[$this->_activityTypeId]['label']);
168 $this->assign('activityType', $details[$this->_activityTypeId]['label']);
169 $this->assign('activityTypeDescription', $details[$this->_activityTypeId]['description']);
170
171 if (isset($this->_currentlyViewedContactId)) {
172 $contact = new CRM_Contact_DAO_Contact();
173 $contact->id = $this->_currentlyViewedContactId;
174 if (!$contact->find(TRUE)) {
175 CRM_Core_Error::statusBounce(ts('Client contact does not exist: %1', [1 => $this->_currentlyViewedContactId]));
176 }
177 $this->assign('clientName', $contact->display_name);
178 }
179
180 $session = CRM_Core_Session::singleton();
181 $this->_currentUserId = $session->get('userID');
182
183 //Add activity custom data is included in this page
184 CRM_Custom_Form_CustomData::preProcess($this, NULL, $this->_activityTypeId, 1, 'Activity');
185 $className = "CRM_Case_Form_Activity_{$this->_activityTypeFile}";
186 $className::preProcess($this);
187 $activityGroupTree = $this->_groupTree;
188
189 // Add case custom data to form
190 $caseTypeId = CRM_Utils_Array::value('case_type_id', CRM_Utils_Request::exportValues(), $this->_caseTypeId);
191 CRM_Custom_Form_CustomData::addToForm($this, $caseTypeId);
192
193 // so that grouptree is not populated with case fields, since the grouptree is used
194 // for populating activity custom fields.
195 $this->_groupTree = $activityGroupTree;
196 }
197
198 /**
199 * Set default values for the form.
200 */
201 public function setDefaultValues() {
202 if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) {
203 return TRUE;
204 }
205 $className = "CRM_Case_Form_Activity_{$this->_activityTypeFile}";
206 $defaults = $className::setDefaultValues($this);
207 $defaults = array_merge($defaults, CRM_Custom_Form_CustomData::setDefaultValues($this));
208 return $defaults;
209 }
210
211 public function buildQuickForm() {
212 $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
213 $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients();
214 $this->assign('multiClient', $isMultiClient);
215
216 if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) {
217 $title = ts('Delete');
218 if ($this->_action & CRM_Core_Action::RENEW) {
219 $title = ts('Restore');
220 }
221 $this->addButtons([
222 [
223 'type' => 'next',
224 'name' => $title,
225 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
226 'isDefault' => TRUE,
227 ],
228 [
229 'type' => 'cancel',
230 'name' => ts('Cancel'),
231 ],
232 ]);
233 return;
234 }
235
236 // Add the activity custom data to the form
237 CRM_Custom_Form_CustomData::buildQuickForm($this);
238
239 // we don't want to show button on top of custom form
240 $this->assign('noPreCustomButton', TRUE);
241
242 $s = CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', 'subject');
243 if (!is_array($s)) {
244 $s = [];
245 }
246 $this->add('text', 'activity_subject', ts('Subject'),
247 array_merge($s, [
248 'maxlength' => '128',
249 ]), TRUE
250 );
251
252 $tags = CRM_Core_BAO_Tag::getColorTags('civicrm_case');
253
254 if (!empty($tags)) {
255 $this->add('select2', 'tag', ts('Tags'), $tags, FALSE,
256 ['class' => 'huge', 'multiple' => 'multiple']
257 );
258 }
259
260 // build tag widget
261 $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_case');
262 CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_case', NULL, FALSE, TRUE);
263
264 $this->addButtons([
265 [
266 'type' => 'next',
267 'name' => ts('Save'),
268 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
269 'isDefault' => TRUE,
270 ],
271 [
272 'type' => 'cancel',
273 'name' => ts('Cancel'),
274 ],
275 ]);
276
277 $className = "CRM_Case_Form_Activity_{$this->_activityTypeFile}";
278 $className::buildQuickForm($this);
279 }
280
281 /**
282 * Add local and global form rules.
283 *
284 * @return bool
285 */
286 public function addRules() {
287 if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) {
288 return TRUE;
289 }
290 $className = "CRM_Case_Form_Activity_{$this->_activityTypeFile}";
291 $this->addFormRule([$className, 'formRule'], $this);
292 $this->addFormRule(['CRM_Case_Form_Case', 'formRule'], $this);
293 }
294
295 /**
296 * Global validation rules for the form.
297 *
298 * @param array $values
299 * Posted values of the form.
300 *
301 * @param $files
302 * @param CRM_Core_Form $form
303 *
304 * @return array
305 * list of errors to be posted back to the form
306 */
307 public static function formRule($values, $files, $form) {
308 return TRUE;
309 }
310
311 /**
312 * Wrapper for unit testing the post process submit function.
313 *
314 * @param $params
315 * @param $activityTypeFile
316 * @param $contactId
317 * @param $context
318 * @return CRM_Case_BAO_Case
319 */
320 public function testSubmit($params, $activityTypeFile, $contactId, $context = "case") {
321 $this->controller = new CRM_Core_Controller();
322
323 $this->_activityTypeFile = $activityTypeFile;
324 $this->_currentUserId = $contactId;
325 $this->_context = $context;
326
327 return $this->submit($params);
328 }
329
330 /**
331 * Submit the form with given params.
332 *
333 * @param $params
334 */
335 public function submit(&$params) {
336 $params['now'] = date("Ymd");
337
338 // 1. call begin post process
339 if ($this->_activityTypeFile) {
340 $className = "CRM_Case_Form_Activity_{$this->_activityTypeFile}";
341 $className::beginPostProcess($this, $params);
342 }
343
344 if (!empty($params['hidden_custom']) &&
345 !isset($params['custom'])
346 ) {
347 $params['custom'] = CRM_Core_BAO_CustomField::postProcess(
348 $params,
349 NULL,
350 'Case'
351 );
352 }
353
354 // 2. create/edit case
355 if (!empty($params['case_type_id'])) {
356 $params['case_type'] = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $params['case_type_id'], 'name', 'id');
357 $params['subject'] = $params['activity_subject'];
358 // 'civicrm_case.details' is not used in core but is used in the CiviCase extension
359 $params['details'] = $params['activity_details'];
360 }
361 $caseObj = CRM_Case_BAO_Case::create($params);
362 $this->_caseId = $params['case_id'] = $caseObj->id;
363 // unset any ids, custom data
364 unset($params['id'], $params['custom']);
365
366 // add tags if exists
367 $tagParams = [];
368 if (!empty($params['tag'])) {
369 $tagParams = [];
370 if (!is_array($params['tag'])) {
371 $params['tag'] = explode(',', $params['tag']);
372 }
373 foreach ($params['tag'] as $tag) {
374 $tagParams[$tag] = 1;
375 }
376 }
377 CRM_Core_BAO_EntityTag::create($tagParams, 'civicrm_case', $caseObj->id);
378
379 //save free tags
380 if (isset($params['case_taglist']) && !empty($params['case_taglist'])) {
381 CRM_Core_Form_Tag::postProcess($params['case_taglist'], $caseObj->id, 'civicrm_case', $this);
382 }
383
384 // user context
385 $url = CRM_Utils_System::url('civicrm/contact/view/case',
386 "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$caseObj->id}"
387 );
388 CRM_Core_Session::singleton()->pushUserContext($url);
389
390 // 3. format activity custom data
391 if (!empty($params['hidden_custom'])) {
392 $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, $this->_activityTypeId);
393 $customFields = CRM_Utils_Array::crmArrayMerge($customFields,
394 CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE,
395 NULL, NULL, TRUE
396 )
397 );
398 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
399 $this->_activityId,
400 'Activity'
401 );
402 }
403
404 // 4. call end post process
405 if ($this->_activityTypeFile) {
406 $className::endPostProcess($this, $params);
407 }
408
409 return $caseObj;
410 }
411
412 /**
413 * Process the form submission.
414 */
415 public function postProcess() {
416 $transaction = new CRM_Core_Transaction();
417
418 // check if dedupe button, if so return.
419 $buttonName = $this->controller->getButtonName();
420 if (isset($this->_dedupeButtonName) && $buttonName == $this->_dedupeButtonName) {
421 return;
422 }
423
424 if ($this->_action & CRM_Core_Action::DELETE) {
425 $caseDelete = CRM_Case_BAO_Case::deleteCase($this->_caseId, TRUE);
426 if ($caseDelete) {
427 CRM_Core_Session::setStatus(ts('You can view and / or restore deleted cases by checking the "Deleted Cases" option under Find Cases.'), ts('Case Deleted'), 'success');
428 }
429 return;
430 }
431
432 if ($this->_action & CRM_Core_Action::RENEW) {
433 $caseRestore = CRM_Case_BAO_Case::restoreCase($this->_caseId);
434 if ($caseRestore) {
435 CRM_Core_Session::setStatus(ts('The selected case has been restored.'), ts('Restored'), 'success');
436 }
437 return;
438 }
439 // store the submitted values in an array
440 $params = $this->controller->exportValues($this->_name);
441 $this->submit($params);
442
443 CRM_Core_Session::setStatus($params['statusMsg'], ts('Saved'), 'success');
444
445 }
446
447 }