Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
6b83d5bd | 6 | | Copyright CiviCRM LLC (c) 2004-2019 | |
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 | |
6b83d5bd | 31 | * @copyright CiviCRM LLC (c) 2004-2019 |
6a488035 TO |
32 | */ |
33 | ||
34 | /** | |
3819f101 | 35 | * This class create activities for a case. |
6a488035 TO |
36 | */ |
37 | class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity { | |
77b97be7 | 38 | |
6a488035 | 39 | /** |
06f21064 | 40 | * Cases this activity belongs to. |
6a488035 | 41 | * |
06f21064 | 42 | * @var []int |
6a488035 TO |
43 | */ |
44 | public $_caseId; | |
45 | ||
46 | /** | |
d2e5d2ce | 47 | * The default case type variable defined. |
6a488035 | 48 | * |
06f21064 | 49 | * @var []int |
6a488035 TO |
50 | */ |
51 | public $_caseType; | |
52 | ||
6a488035 | 53 | /** |
d2e5d2ce | 54 | * The array of releted contact info. |
6a488035 TO |
55 | * |
56 | * @var array | |
57 | */ | |
58 | public $_relatedContacts; | |
59 | ||
06f21064 TO |
60 | /** |
61 | * The case type definition column info | |
62 | * for the caseId; | |
63 | * | |
64 | * @var array | |
65 | */ | |
66 | public $_caseTypeDefinition; | |
67 | ||
6a488035 | 68 | /** |
d2e5d2ce | 69 | * Build the form object. |
6a488035 | 70 | */ |
00be9182 | 71 | public function preProcess() { |
06f21064 TO |
72 | $caseIds = CRM_Utils_Request::retrieve('caseid', 'CommaSeparatedIntegers', $this); |
73 | $this->_caseId = $caseIds ? explode(',', $caseIds) : []; | |
edc80cda | 74 | $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this); |
6a488035 TO |
75 | if (!$this->_context) { |
76 | $this->_context = 'caseActivity'; | |
77 | } | |
78 | $this->_crmDir = 'Case'; | |
79 | $this->assign('context', $this->_context); | |
80 | ||
1b67821f | 81 | parent::preProcess(); |
6a488035 | 82 | |
9c248a42 | 83 | $scheduleStatusId = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Scheduled'); |
6a488035 TO |
84 | $this->assign('scheduleStatusId', $scheduleStatusId); |
85 | ||
6a488035 | 86 | if (!$this->_caseId && $this->_activityId) { |
06f21064 | 87 | $this->_caseId = (array) CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId, |
6a488035 TO |
88 | 'case_id', 'activity_id' |
89 | ); | |
90 | } | |
91 | if ($this->_caseId) { | |
92 | $this->assign('caseId', $this->_caseId); | |
725fd9d9 | 93 | $this->assign('countId', count($this->_caseId)); |
ad32fddf | 94 | $this->assign('caseID', CRM_Utils_Array::first($this->_caseId)); |
6a488035 TO |
95 | } |
96 | ||
97 | if (!$this->_caseId || | |
98 | (!$this->_activityId && !$this->_activityTypeId) | |
99 | ) { | |
100 | CRM_Core_Error::fatal('required params missing.'); | |
101 | } | |
102 | ||
103 | //check for case activity access. | |
104 | if (!CRM_Case_BAO_Case::accessCiviCase()) { | |
105 | CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); | |
106 | } | |
107 | //validate case id. | |
108 | if ($this->_caseId && | |
109 | !CRM_Core_Permission::check('access all cases and activities') | |
110 | ) { | |
be2fb01f | 111 | $params = ['type' => 'any']; |
5f1c8c57 | 112 | $allCases = CRM_Case_BAO_Case::getCases(TRUE, $params); |
7fa5bb16 | 113 | if (count(array_intersect($this->_caseId, array_keys($allCases))) == 0) { |
6a488035 TO |
114 | CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); |
115 | } | |
116 | } | |
117 | ||
118 | //validate case activity id. | |
119 | if ($this->_activityId && | |
120 | ($this->_action & CRM_Core_Action::UPDATE) | |
121 | ) { | |
122 | $valid = CRM_Case_BAO_Case::checkPermission($this->_activityId, 'edit', | |
123 | $this->_activityTypeId | |
124 | ); | |
125 | if (!$valid) { | |
126 | CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); | |
127 | } | |
128 | } | |
129 | ||
cc30482e TO |
130 | foreach ($this->_caseId as $casePos => $caseId) { |
131 | $this->_caseType[$casePos] = CRM_Case_BAO_Case::getCaseType($caseId, 'name'); | |
725fd9d9 | 132 | } |
6a488035 TO |
133 | $this->assign('caseType', $this->_caseType); |
134 | ||
06f21064 TO |
135 | $this->_caseTypeDefinition = $this->getCaseTypeDefinition(); |
136 | ||
6a488035 TO |
137 | $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); |
138 | $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); | |
139 | $this->assign('multiClient', $isMultiClient); | |
140 | ||
cc30482e TO |
141 | foreach ($this->_caseId as $casePos => $caseId) { |
142 | $clients[] = CRM_Case_BAO_Case::getContactNames($caseId); | |
725fd9d9 | 143 | } |
6a488035 TO |
144 | $this->assign('client_names', $clients); |
145 | ||
725fd9d9 | 146 | $caseIds = implode(',', $this->_caseId); |
6a488035 TO |
147 | // set context for pushUserContext and for statusBounce |
148 | if ($this->_context == 'fulltext') { | |
149 | if ($this->_action == CRM_Core_Action::UPDATE || $this->_action == CRM_Core_Action::DELETE) { | |
150 | $url = CRM_Utils_System::url('civicrm/contact/view/case', | |
725fd9d9 | 151 | "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$caseIds}&show=1&context={$this->_context}" |
6a488035 TO |
152 | ); |
153 | } | |
154 | else { | |
155 | $url = CRM_Utils_System::url('civicrm/contact/search/custom', 'force=1'); | |
156 | } | |
157 | } | |
158 | else { | |
159 | $url = CRM_Utils_System::url('civicrm/contact/view/case', | |
725fd9d9 | 160 | "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$caseIds}&show=1" |
6a488035 TO |
161 | ); |
162 | } | |
163 | if (!$this->_activityId) { | |
164 | $caseTypes = CRM_Case_PseudoConstant::caseType(); | |
165 | ||
166 | if (empty($caseTypes) && ($this->_activityTypeName == 'Change Case Type') && !$this->_caseId) { | |
167 | $url = CRM_Utils_System::url('civicrm/contact/view/case', | |
725fd9d9 | 168 | "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$caseIds}&show=1" |
6a488035 TO |
169 | ); |
170 | $session = CRM_Core_Session::singleton(); | |
171 | $session->pushUserContext($url); | |
172 | CRM_Core_Error::statusBounce(ts("You do not have any active Case Types")); | |
173 | } | |
174 | ||
175 | // check if activity count is within the limit | |
176 | $xmlProcessor = new CRM_Case_XMLProcessor_Process(); | |
cc30482e TO |
177 | foreach ($this->_caseId as $casePos => $caseId) { |
178 | $caseType = $this->_caseType[$casePos]; | |
179 | $activityInst = $xmlProcessor->getMaxInstance($caseType); | |
6a488035 | 180 | |
0d83522a | 181 | // If not bounce back and also provide activity edit link if only one existing activity |
725fd9d9 | 182 | if (isset($activityInst[$this->_activityTypeName])) { |
cc30482e | 183 | $activityCount = CRM_Case_BAO_Case::getCaseActivityCount($caseId, $this->_activityTypeId); |
0d83522a D |
184 | $editUrl = self::checkMaxInstances( |
185 | $caseId, | |
186 | $this->_activityTypeId, | |
187 | $activityInst[$this->_activityTypeName], | |
188 | $this->_currentUserId, | |
189 | $this->_currentlyViewedContactId, | |
190 | $activityCount | |
191 | ); | |
192 | $bounceMessage = self::getMaxInstancesBounceMessage($editUrl, $this->_activityTypeName, $activityInst[$this->_activityTypeName], $activityCount); | |
193 | if ($bounceMessage) { | |
194 | CRM_Core_Error::statusBounce($bounceMessage, $url); | |
6a488035 | 195 | } |
6a488035 TO |
196 | } |
197 | } | |
198 | } | |
199 | ||
53c79877 SM |
200 | // Turn off the prompt which asks the user if they want to create separate |
201 | // activities when specifying multiple contacts "with" a new activity. | |
202 | // Instead, always create one activity with all contacts together. | |
203 | $this->supportsActivitySeparation = FALSE; | |
204 | ||
6a488035 TO |
205 | $session = CRM_Core_Session::singleton(); |
206 | $session->pushUserContext($url); | |
207 | } | |
208 | ||
209 | /** | |
3819f101 | 210 | * Set default values for the form. |
6a488035 | 211 | */ |
00be9182 | 212 | public function setDefaultValues() { |
6a488035 | 213 | $this->_defaults = parent::setDefaultValues(); |
be2fb01f | 214 | $targetContactValues = []; |
725fd9d9 N |
215 | foreach ($this->_caseId as $key => $val) { |
216 | //get all clients. | |
217 | $clients = CRM_Case_BAO_Case::getContactNames($val); | |
218 | if (isset($this->_activityId) && empty($_POST)) { | |
219 | if (!CRM_Utils_Array::crmIsEmptyArray($this->_defaults['target_contact'])) { | |
220 | $targetContactValues = array_combine(array_unique($this->_defaults['target_contact']), | |
221 | explode(';', trim($this->_defaults['target_contact_value'])) | |
222 | ); | |
223 | //exclude all clients. | |
224 | foreach ($clients as $clientId => $vals) { | |
225 | if (array_key_exists($clientId, $targetContactValues)) { | |
226 | unset($targetContactValues[$clientId]); | |
227 | } | |
6a488035 TO |
228 | } |
229 | } | |
230 | } | |
725fd9d9 | 231 | $this->assign('targetContactValues', empty($targetContactValues) ? FALSE : $targetContactValues); |
6a488035 | 232 | |
725fd9d9 N |
233 | if (isset($this->_encounterMedium)) { |
234 | $this->_defaults['medium_id'] = $this->_encounterMedium; | |
235 | } | |
236 | elseif (empty($this->_defaults['medium_id'])) { | |
237 | // set default encounter medium CRM-4816 | |
238 | $medium = CRM_Core_OptionGroup::values('encounter_medium', FALSE, FALSE, FALSE, 'AND is_default = 1'); | |
239 | if (count($medium) == 1) { | |
240 | $this->_defaults['medium_id'] = key($medium); | |
241 | } | |
6a488035 | 242 | } |
6a488035 | 243 | |
725fd9d9 N |
244 | return $this->_defaults; |
245 | } | |
6a488035 TO |
246 | } |
247 | ||
248 | public function buildQuickForm() { | |
249 | $this->_fields['source_contact_id']['label'] = ts('Reported By'); | |
f7305cbc | 250 | unset($this->_fields['status_id']['attributes']['required']); |
6a488035 | 251 | |
06f21064 TO |
252 | if ($this->restrictAssignmentByUserAccount()) { |
253 | $assigneeParameters['uf_user'] = 1; | |
254 | } | |
255 | ||
256 | $activityAssignmentGroups = $this->getActivityAssignmentGroups(); | |
257 | if (!empty($activityAssignmentGroups)) { | |
258 | $assigneeParameters['group'] = ['IN' => $activityAssignmentGroups]; | |
259 | } | |
260 | ||
261 | if (!empty($assigneeParameters)) { | |
262 | $this->_fields['assignee_contact_id']['attributes']['api']['params'] | |
263 | = array_merge($this->_fields['assignee_contact_id']['attributes']['api']['params'], $assigneeParameters); | |
264 | ||
265 | $this->_fields['followup_assignee_contact_id']['attributes']['api']['params'] | |
266 | = array_merge($this->_fields['followup_assignee_contact_id']['attributes']['api']['params'], $assigneeParameters); | |
267 | ||
268 | //Disallow creating a contact from the assignee field UI. | |
269 | $this->_fields['assignee_contact_id']['attributes']['create'] = FALSE; | |
270 | $this->_fields['followup_assignee_contact_id']['attributes']['create'] = FALSE; | |
271 | } | |
272 | ||
6a488035 TO |
273 | if ($this->_caseType) { |
274 | $xmlProcessor = new CRM_Case_XMLProcessor_Process(); | |
be2fb01f | 275 | $aTypes = []; |
06f21064 | 276 | foreach (array_unique($this->_caseType) as $val) { |
725fd9d9 N |
277 | $activityTypes = $xmlProcessor->get($val, 'ActivityTypes', TRUE); |
278 | $aTypes = $aTypes + $activityTypes; | |
279 | } | |
6a488035 TO |
280 | |
281 | // remove Open Case activity type since we're inside an existing case | |
9c248a42 | 282 | $openCaseID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Open Case'); |
6a488035 TO |
283 | unset($aTypes[$openCaseID]); |
284 | asort($aTypes); | |
be2fb01f | 285 | $this->_fields['followup_activity_type_id']['attributes'] = ['' => '- select activity type -'] + $aTypes; |
6a488035 TO |
286 | } |
287 | ||
b7617307 | 288 | parent::buildQuickForm(); |
6a488035 TO |
289 | |
290 | if ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::DETACH | CRM_Core_Action::RENEW)) { | |
291 | return; | |
292 | } | |
293 | ||
6a488035 TO |
294 | $this->assign('urlPath', 'civicrm/case/activity'); |
295 | ||
296 | $encounterMediums = CRM_Case_PseudoConstant::encounterMedium(); | |
cedb74cd | 297 | |
06f51047 CW |
298 | if ($this->_activityTypeFile == 'OpenCase' && $this->_action == CRM_Core_Action::UPDATE) { |
299 | $this->getElement('activity_date_time')->freeze(); | |
300 | ||
cedb74cd MWMC |
301 | if ($this->_activityId) { |
302 | // Fixme: what's the justification for this? It seems like it is just re-adding an option in case it is the default and disabled. | |
303 | // Is that really a big problem? | |
304 | $this->_encounterMedium = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $this->_activityId, 'medium_id'); | |
305 | if (!array_key_exists($this->_encounterMedium, $encounterMediums)) { | |
306 | $encounterMediums[$this->_encounterMedium] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'medium_id', $this->_encounterMedium); | |
307 | } | |
6a488035 TO |
308 | } |
309 | } | |
310 | ||
311 | $this->add('select', 'medium_id', ts('Medium'), $encounterMediums, TRUE); | |
725fd9d9 N |
312 | $i = 0; |
313 | foreach ($this->_caseId as $key => $val) { | |
a82f59a1 | 314 | $this->_relatedContacts[] = $rgc = CRM_Case_BAO_Case::getRelatedAndGlobalContacts($val); |
725fd9d9 N |
315 | $contName = CRM_Case_BAO_Case::getContactNames($val); |
316 | foreach ($contName as $nkey => $nval) { | |
e547f744 | 317 | array_push($this->_relatedContacts[$i][0], $this->_relatedContacts[$i][0]['managerOf'] = $nval['display_name']); |
725fd9d9 N |
318 | } |
319 | $i++; | |
320 | } | |
6a488035 | 321 | |
6a488035 | 322 | //add case client in send a copy selector.CRM-4438. |
725fd9d9 | 323 | foreach ($this->_caseId as $key => $val) { |
e547f744 | 324 | $relatedContacts[] = $relCon = CRM_Case_BAO_Case::getContactNames($val); |
725fd9d9 N |
325 | } |
326 | ||
6a488035 TO |
327 | if (!empty($relatedContacts)) { |
328 | foreach ($relatedContacts as $relatedContact) { | |
329 | $this->_relatedContacts[] = $relatedContact; | |
330 | } | |
331 | } | |
332 | ||
333 | if (!empty($this->_relatedContacts)) { | |
be2fb01f | 334 | $checkBoxes = []; |
6a488035 | 335 | foreach ($this->_relatedContacts as $id => $row) { |
ee1ccac5 | 336 | foreach ($row as $key => $value) { |
be2fb01f | 337 | $checkBoxes[$key] = $this->addElement('checkbox', $key, NULL, NULL, ['class' => 'select-row']); |
ee1ccac5 | 338 | } |
6a488035 TO |
339 | } |
340 | ||
341 | $this->addGroup($checkBoxes, 'contact_check'); | |
342 | $this->addElement('checkbox', 'toggleSelect', NULL, NULL, | |
be2fb01f | 343 | ['class' => 'select-rows'] |
6a488035 TO |
344 | ); |
345 | $this->assign('searchRows', $this->_relatedContacts); | |
346 | } | |
a82f59a1 | 347 | $this->_relatedContacts = $rgc + $relCon; |
6a488035 | 348 | |
be2fb01f | 349 | $this->addFormRule(['CRM_Case_Form_Activity', 'formRule'], $this); |
6a488035 TO |
350 | } |
351 | ||
352 | /** | |
d2e5d2ce | 353 | * Global form rule. |
6a488035 | 354 | * |
64bd5a0e TO |
355 | * @param array $fields |
356 | * The input form values. | |
357 | * @param array $files | |
358 | * The uploaded files if any. | |
77b97be7 EM |
359 | * @param $self |
360 | * | |
72b3a70c CW |
361 | * @return bool|array |
362 | * true if no errors, else array of errors | |
6a488035 | 363 | */ |
00be9182 | 364 | public static function formRule($fields, $files, $self) { |
6a488035 TO |
365 | // skip form rule if deleting |
366 | if (CRM_Utils_Array::value('_qf_Activity_next_', $fields) == 'Delete' || CRM_Utils_Array::value('_qf_Activity_next_', $fields) == 'Restore') { | |
367 | return TRUE; | |
368 | } | |
369 | ||
6ea16bbf | 370 | return parent::formRule($fields, $files, $self); |
6a488035 TO |
371 | } |
372 | ||
373 | /** | |
d2e5d2ce | 374 | * Process the form submission. |
6a488035 | 375 | * |
100fef9d | 376 | * @param array $params |
6a488035 | 377 | */ |
2d4a6b57 | 378 | public function postProcess($params = NULL) { |
6a488035 TO |
379 | $transaction = new CRM_Core_Transaction(); |
380 | ||
381 | if ($this->_action & CRM_Core_Action::DELETE) { | |
382 | $statusMsg = NULL; | |
383 | ||
384 | //block deleting activities which affects | |
385 | //case attributes.CRM-4543 | |
386 | $activityCondition = " AND v.name IN ('Open Case', 'Change Case Type', 'Change Case Status', 'Change Case Start Date')"; | |
387 | $caseAttributeActivities = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, $activityCondition); | |
388 | ||
389 | if (!array_key_exists($this->_activityTypeId, $caseAttributeActivities)) { | |
be2fb01f | 390 | $params = ['id' => $this->_activityId]; |
6a488035 TO |
391 | $activityDelete = CRM_Activity_BAO_Activity::deleteActivity($params, TRUE); |
392 | if ($activityDelete) { | |
393 | $statusMsg = ts('The selected activity has been moved to the Trash. You can view and / or restore deleted activities by checking "Deleted Activities" from the Case Activities search filter (under Manage Case).<br />'); | |
394 | } | |
395 | } | |
396 | else { | |
397 | $statusMsg = ts("Selected Activity cannot be deleted."); | |
398 | } | |
399 | ||
be2fb01f | 400 | $tagParams = [ |
6a488035 | 401 | 'entity_table' => 'civicrm_activity', |
21dfd5f5 | 402 | 'entity_id' => $this->_activityId, |
be2fb01f | 403 | ]; |
6a488035 TO |
404 | CRM_Core_BAO_EntityTag::del($tagParams); |
405 | ||
406 | CRM_Core_Session::setStatus('', $statusMsg, 'info'); | |
407 | return; | |
408 | } | |
409 | ||
410 | if ($this->_action & CRM_Core_Action::RENEW) { | |
50237bc9 | 411 | $statusMsg = NULL; |
be2fb01f | 412 | $params = ['id' => $this->_activityId]; |
6a488035 TO |
413 | $activityRestore = CRM_Activity_BAO_Activity::restoreActivity($params); |
414 | if ($activityRestore) { | |
415 | $statusMsg = ts('The selected activity has been restored.<br />'); | |
416 | } | |
417 | CRM_Core_Session::setStatus('', $statusMsg, 'info'); | |
418 | return; | |
419 | } | |
420 | ||
421 | // store the submitted values in an array | |
831af101 D |
422 | // Explanation for why we only check the is_unittest element: Prior to adding that check, there was no check and so any $params passed in would have been overwritten. Just in case somebody is passing in some non-null params and that broken code would have inadvertently been working, we can maintain backwards compatibility by only checking for the is_unittest parameter, and so that broken code will still work. At the same time this allows unit tests to pass in a $params without it getting overwritten. See also PR #2077 for some discussion of when the $params parameter was added as a passed in variable. |
423 | if (empty($params['is_unittest'])) { | |
424 | $params = $this->controller->exportValues($this->_name); | |
425 | } | |
6a488035 TO |
426 | |
427 | //set parent id if its edit mode | |
428 | if ($parentId = CRM_Utils_Array::value('parent_id', $this->_defaults)) { | |
429 | $params['parent_id'] = $parentId; | |
430 | } | |
431 | ||
6a488035 TO |
432 | $params['activity_type_id'] = $this->_activityTypeId; |
433 | ||
434 | // format with contact (target contact) values | |
3911d992 DJ |
435 | if (isset($params['target_contact_id'])) { |
436 | $params['target_contact_id'] = explode(',', $params['target_contact_id']); | |
6a488035 TO |
437 | } |
438 | else { | |
be2fb01f | 439 | $params['target_contact_id'] = []; |
6a488035 TO |
440 | } |
441 | ||
442 | // format activity custom data | |
a7488080 | 443 | if (!empty($params['hidden_custom'])) { |
6a488035 | 444 | if ($this->_activityId) { |
756b5b30 | 445 | // retrieve and include the custom data of old Activity |
be2fb01f | 446 | $oldActivity = civicrm_api3('Activity', 'getsingle', ['id' => $this->_activityId]); |
309c49b2 | 447 | $params = array_merge($oldActivity, $params); |
756b5b30 | 448 | |
6a488035 TO |
449 | // unset custom fields-id from params since we want custom |
450 | // fields to be saved for new activity. | |
451 | foreach ($params as $key => $value) { | |
be2fb01f | 452 | $match = []; |
6a488035 TO |
453 | if (preg_match('/^(custom_\d+_)(\d+)$/', $key, $match)) { |
454 | $params[$match[1] . '-1'] = $params[$key]; | |
455 | ||
456 | // for autocomplete transfer hidden value instead of label | |
457 | if ($params[$key] && isset($params[$key . '_id'])) { | |
458 | $params[$match[1] . '-1_id'] = $params[$key . '_id']; | |
459 | unset($params[$key . '_id']); | |
460 | } | |
461 | unset($params[$key]); | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
466 | // build custom data getFields array | |
467 | $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, $this->_activityTypeId); | |
468 | $customFields = CRM_Utils_Array::crmArrayMerge($customFields, | |
469 | CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, | |
470 | NULL, NULL, TRUE | |
471 | ) | |
472 | ); | |
473 | $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, | |
6a488035 TO |
474 | $this->_activityId, |
475 | 'Activity' | |
476 | ); | |
477 | } | |
478 | ||
50237bc9 | 479 | // assigning formatted value |
a7488080 | 480 | if (!empty($params['assignee_contact_id'])) { |
6a488035 TO |
481 | $params['assignee_contact_id'] = explode(',', $params['assignee_contact_id']); |
482 | } | |
483 | else { | |
be2fb01f | 484 | $params['assignee_contact_id'] = []; |
6a488035 TO |
485 | } |
486 | ||
6a488035 TO |
487 | if (isset($this->_activityId)) { |
488 | // activity which hasn't been modified by a user yet | |
489 | if ($this->_defaults['is_auto'] == 1) { | |
490 | $params['is_auto'] = 0; | |
491 | } | |
492 | ||
493 | // always create a revision of an case activity. CRM-4533 | |
494 | $newActParams = $params; | |
495 | ||
496 | // add target contact values in update mode | |
497 | if (empty($params['target_contact_id']) && !empty($this->_defaults['target_contact'])) { | |
498 | $newActParams['target_contact_id'] = $this->_defaults['target_contact']; | |
499 | } | |
6a488035 TO |
500 | } |
501 | ||
502 | if (!isset($newActParams)) { | |
503 | // add more attachments if needed for old activity | |
504 | CRM_Core_BAO_File::formatAttachment($params, | |
505 | $params, | |
506 | 'civicrm_activity' | |
507 | ); | |
508 | ||
509 | // call begin post process, before the activity is created/updated. | |
510 | $this->beginPostProcess($params); | |
725fd9d9 N |
511 | foreach ($this->_caseId as $key => $val) { |
512 | $params['case_id'] = $val; | |
513 | // activity create/update | |
514 | $activity = CRM_Activity_BAO_Activity::create($params); | |
be2fb01f | 515 | $vvalue[] = ['case_id' => $val, 'actId' => $activity->id]; |
725fd9d9 N |
516 | // call end post process, after the activity has been created/updated. |
517 | $this->endPostProcess($params, $activity); | |
518 | } | |
6a488035 TO |
519 | } |
520 | else { | |
521 | // since the params we need to set are very few, and we don't want rest of the | |
522 | // work done by bao create method , lets use dao object to make the changes | |
be2fb01f | 523 | $params = ['id' => $this->_activityId]; |
6a488035 TO |
524 | $params['is_current_revision'] = 0; |
525 | $activity = new CRM_Activity_DAO_Activity(); | |
526 | $activity->copyValues($params); | |
527 | $activity->save(); | |
528 | } | |
529 | ||
530 | // create a new version of activity if activity was found to | |
531 | // have been modified/created by user | |
532 | if (isset($newActParams)) { | |
533 | // set proper original_id | |
a7488080 | 534 | if (!empty($this->_defaults['original_id'])) { |
6a488035 TO |
535 | $newActParams['original_id'] = $this->_defaults['original_id']; |
536 | } | |
537 | else { | |
538 | $newActParams['original_id'] = $activity->id; | |
539 | } | |
6a488035 | 540 | |
756b5b30 | 541 | //is_current_revision will be set to 1 by default. |
6a488035 TO |
542 | // add attachments if any |
543 | CRM_Core_BAO_File::formatAttachment($newActParams, | |
544 | $newActParams, | |
545 | 'civicrm_activity' | |
546 | ); | |
547 | ||
548 | // call begin post process, before the activity is created/updated. | |
549 | $this->beginPostProcess($newActParams); | |
725fd9d9 N |
550 | foreach ($this->_caseId as $key => $val) { |
551 | $newActParams['case_id'] = $val; | |
552 | $activity = CRM_Activity_BAO_Activity::create($newActParams); | |
be2fb01f | 553 | $vvalue[] = ['case_id' => $val, 'actId' => $activity->id]; |
725fd9d9 N |
554 | // call end post process, after the activity has been created/updated. |
555 | $this->endPostProcess($newActParams, $activity); | |
556 | } | |
6a488035 TO |
557 | // copy files attached to old activity if any, to new one, |
558 | // as long as users have not selected the 'delete attachment' option. | |
8506cda6 | 559 | if (empty($newActParams['is_delete_attachment']) && ($this->_activityId != $activity->id)) { |
6a488035 TO |
560 | CRM_Core_BAO_File::copyEntityFile('civicrm_activity', $this->_activityId, |
561 | 'civicrm_activity', $activity->id | |
562 | ); | |
563 | } | |
564 | ||
565 | // copy back params to original var | |
566 | $params = $newActParams; | |
567 | } | |
568 | ||
725fd9d9 N |
569 | foreach ($vvalue as $vkey => $vval) { |
570 | if ($vval['actId']) { | |
571 | // add tags if exists | |
be2fb01f | 572 | $tagParams = []; |
725fd9d9 | 573 | if (!empty($params['tag'])) { |
63b7aefc DB |
574 | if (!is_array($params['tag'])) { |
575 | $params['tag'] = explode(',', $params['tag']); | |
725fd9d9 | 576 | } |
63b7aefc DB |
577 | |
578 | $tagParams = array_fill_keys($params['tag'], 1); | |
6a488035 | 579 | } |
6a488035 | 580 | |
725fd9d9 N |
581 | //save static tags |
582 | CRM_Core_BAO_EntityTag::create($tagParams, 'civicrm_activity', $vval['actId']); | |
6a488035 | 583 | |
725fd9d9 N |
584 | //save free tags |
585 | if (isset($params['taglist']) && !empty($params['taglist'])) { | |
586 | CRM_Core_Form_Tag::postProcess($params['taglist'], $vval['actId'], 'civicrm_activity', $this); | |
587 | } | |
6a488035 | 588 | } |
6a488035 | 589 | |
725fd9d9 N |
590 | // update existing case record if needed |
591 | $caseParams = $params; | |
592 | $caseParams['id'] = $vval['case_id']; | |
725fd9d9 N |
593 | if (!empty($caseParams['case_status_id'])) { |
594 | $caseParams['status_id'] = $caseParams['case_status_id']; | |
595 | } | |
6a488035 | 596 | |
725fd9d9 N |
597 | // unset params intended for activities only |
598 | unset($caseParams['subject'], $caseParams['details'], | |
599 | $caseParams['status_id'], $caseParams['custom'] | |
600 | ); | |
1b67821f | 601 | CRM_Case_BAO_Case::create($caseParams); |
725fd9d9 | 602 | // create case activity record |
be2fb01f | 603 | $caseParams = [ |
725fd9d9 N |
604 | 'activity_id' => $vval['actId'], |
605 | 'case_id' => $vval['case_id'], | |
be2fb01f | 606 | ]; |
725fd9d9 | 607 | CRM_Case_BAO_Case::processCaseActivity($caseParams); |
6a488035 TO |
608 | } |
609 | ||
6a488035 TO |
610 | // send copy to selected contacts. |
611 | $mailStatus = ''; | |
be2fb01f | 612 | $mailToContacts = []; |
6a488035 TO |
613 | |
614 | //CRM-5695 | |
615 | //check for notification settings for assignee contacts | |
be2fb01f | 616 | $selectedContacts = ['contact_check']; |
aaffa79f | 617 | if (Civi::settings()->get('activity_assignee_notification')) { |
6a488035 TO |
618 | $selectedContacts[] = 'assignee_contact_id'; |
619 | } | |
620 | ||
725fd9d9 N |
621 | foreach ($vvalue as $vkey => $vval) { |
622 | foreach ($selectedContacts as $dnt => $val) { | |
35522279 | 623 | if (array_key_exists($val, $params) && !CRM_Utils_Array::crmIsEmptyArray($params[$val])) { |
cd122921 | 624 | if ($val == 'contact_check') { |
725fd9d9 | 625 | $mailStatus = ts("A copy of the activity has also been sent to selected contacts(s)."); |
cd122921 | 626 | } |
627 | else { | |
be2fb01f | 628 | $this->_relatedContacts = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames([$vval['actId']], TRUE, FALSE); |
725fd9d9 | 629 | $mailStatus .= ' ' . ts("A copy of the activity has also been sent to assignee contacts(s)."); |
cd122921 | 630 | } |
725fd9d9 N |
631 | //build an associative array with unique email addresses. |
632 | foreach ($params[$val] as $key => $value) { | |
633 | if ($val == 'contact_check') { | |
634 | $id = $key; | |
6a488035 TO |
635 | } |
636 | else { | |
725fd9d9 N |
637 | $id = $value; |
638 | } | |
639 | ||
640 | if (isset($id) && array_key_exists($id, $this->_relatedContacts) && isset($this->_relatedContacts[$id]['email'])) { | |
641 | //if email already exists in array then append with ', ' another role only otherwise add it to array. | |
642 | if ($contactDetails = CRM_Utils_Array::value($this->_relatedContacts[$id]['email'], $mailToContacts)) { | |
643 | $caseRole = CRM_Utils_Array::value('role', $this->_relatedContacts[$id]); | |
644 | $mailToContacts[$this->_relatedContacts[$id]['email']]['role'] = $contactDetails['role'] . ', ' . $caseRole; | |
645 | } | |
646 | else { | |
647 | $mailToContacts[$this->_relatedContacts[$id]['email']] = $this->_relatedContacts[$id]; | |
648 | } | |
6a488035 TO |
649 | } |
650 | } | |
651 | } | |
652 | } | |
6a488035 | 653 | |
be2fb01f | 654 | $extraParams = ['case_id' => $vval['case_id'], 'client_id' => $this->_currentlyViewedContactId]; |
cc7982a1 | 655 | $result = CRM_Activity_BAO_Activity::sendToAssignee($activity, $mailToContacts, $extraParams); |
fc110b68 | 656 | if (empty($result)) { |
6a488035 TO |
657 | $mailStatus = ''; |
658 | } | |
6a488035 | 659 | |
725fd9d9 N |
660 | // create follow up activity if needed |
661 | $followupStatus = ''; | |
662 | if (!empty($params['followup_activity_type_id'])) { | |
663 | $followupActivity = CRM_Activity_BAO_Activity::createFollowupActivity($vval['actId'], $params); | |
6a488035 | 664 | |
725fd9d9 | 665 | if ($followupActivity) { |
be2fb01f | 666 | $caseParams = [ |
353ffa53 TO |
667 | 'activity_id' => $followupActivity->id, |
668 | 'case_id' => $vval['case_id'], | |
be2fb01f | 669 | ]; |
725fd9d9 | 670 | CRM_Case_BAO_Case::processCaseActivity($caseParams); |
7c77009f | 671 | $followupStatus = ts("A followup activity has been scheduled.") . '<br /><br />'; |
725fd9d9 | 672 | } |
6a488035 | 673 | } |
be2fb01f | 674 | $title = ts("%1 Saved", [1 => $this->_activityTypeName]); |
a62473e7 | 675 | CRM_Core_Session::setStatus($followupStatus . $mailStatus, $title, 'success'); |
725fd9d9 | 676 | } |
6a488035 | 677 | } |
96025800 | 678 | |
06f21064 TO |
679 | /** |
680 | * Returns the groups that contacts must belong to in order to be assigned | |
681 | * an activity for this case. It returns an empty array if no groups are found for | |
682 | * the case type linked to the caseId. | |
683 | * | |
684 | * @return array | |
685 | */ | |
686 | private function getActivityAssignmentGroups() { | |
687 | if (!$this->_caseTypeDefinition) { | |
688 | return []; | |
689 | } | |
690 | ||
691 | $assignmentGroups = []; | |
692 | foreach ($this->_caseTypeDefinition as $caseId => $definition) { | |
693 | if (!empty($definition['activityAsgmtGrps'])) { | |
694 | $assignmentGroups = array_merge($assignmentGroups, $definition['activityAsgmtGrps']); | |
695 | } | |
696 | } | |
697 | ||
698 | return $assignmentGroups; | |
699 | } | |
700 | ||
701 | /** | |
702 | * Returns whether contacts must have a user account in order to be | |
703 | * assigned an activity for this case. | |
704 | * | |
705 | * @return bool | |
706 | */ | |
707 | private function restrictAssignmentByUserAccount() { | |
708 | if (!$this->_caseTypeDefinition) { | |
709 | return FALSE; | |
710 | } | |
711 | ||
712 | foreach ($this->_caseTypeDefinition as $caseId => $definition) { | |
713 | if (!empty($definition['restrictActivityAsgmtToCmsUser'])) { | |
714 | return TRUE; | |
715 | } | |
716 | } | |
717 | ||
718 | return FALSE; | |
719 | } | |
720 | ||
721 | /** | |
722 | * Returns the case type definition column value for the case type linked to the caseId. | |
723 | * | |
724 | * @return array | |
725 | */ | |
726 | private function getCaseTypeDefinition() { | |
727 | if (!$this->_caseId) { | |
728 | return []; | |
729 | } | |
730 | ||
731 | $definitions = civicrm_api3('CaseType', 'get', [ | |
732 | 'return' => ['name', 'definition'], | |
733 | 'name' => ['IN' => array_unique($this->_caseType)], | |
734 | ]); | |
735 | ||
736 | return array_column($definitions['values'], 'definition', 'name'); | |
737 | } | |
738 | ||
0d83522a D |
739 | /** |
740 | * Get the edit link for a case activity | |
741 | * | |
742 | * This isn't here for reusability - it was a pull out | |
743 | * from preProcess to make it easier to test. | |
744 | * There is CRM_Case_Selector_Search::addCaseActivityLinks but it would | |
745 | * need some rejigging, and there's also a FIXME note there already. | |
746 | * | |
747 | * @param int $caseId | |
748 | * @param int $activityTypeId | |
749 | * @param int $currentUserId | |
750 | * @param int $currentlyViewedContactId | |
751 | * | |
752 | * @return string | |
753 | */ | |
754 | public static function getCaseActivityEditLink($caseId, $activityTypeId, $currentUserId, $currentlyViewedContactId) { | |
755 | $atArray = ['activity_type_id' => $activityTypeId]; | |
756 | $activities = CRM_Case_BAO_Case::getCaseActivity($caseId, | |
757 | $atArray, | |
758 | $currentUserId | |
759 | ); | |
760 | $firstActivity = CRM_Utils_Array::first($activities['data']); | |
761 | $activityId = empty($firstActivity['DT_RowId']) ? 0 : $firstActivity['DT_RowId']; | |
762 | return CRM_Utils_System::url('civicrm/case/activity', | |
763 | "reset=1&cid={$currentlyViewedContactId}&caseid={$caseId}&action=update&id={$activityId}" | |
764 | ); | |
765 | } | |
766 | ||
767 | /** | |
768 | * Check the current activity count against max instances for a given case id and activity type. | |
769 | * | |
770 | * This isn't here for reusability - it was a pull out | |
771 | * from preProcess to make it easier to test. | |
772 | * | |
773 | * @param int $caseId | |
774 | * @param int $activityTypeId | |
775 | * @param int $maxInstances | |
776 | * @param int $currentUserId | |
777 | * @param int $currentlyViewedContactId | |
778 | * @param int $activityCount | |
779 | * | |
780 | * @return string | |
781 | * If there is more than one existing activity of the given type then it's not clear which url to return so return null for the url. | |
782 | */ | |
783 | public static function checkMaxInstances($caseId, $activityTypeId, $maxInstances, $currentUserId, $currentlyViewedContactId, $activityCount) { | |
784 | $editUrl = NULL; | |
785 | if ($activityCount >= $maxInstances) { | |
786 | if ($maxInstances == 1) { | |
787 | $editUrl = self::getCaseActivityEditLink($caseId, $activityTypeId, $currentUserId, $currentlyViewedContactId); | |
788 | } | |
789 | } | |
790 | return $editUrl; | |
791 | } | |
792 | ||
793 | /** | |
794 | * Compute the message text for the bounce message when max_instances is reached, depending on whether it's one or more than one. | |
795 | * | |
796 | * @param string $editUrl | |
797 | * @param string $activityTypeName | |
798 | * This is actually label!! But we do want label though in this function. | |
799 | * @param int $maxInstances | |
800 | * @param int $activityCount | |
801 | * Count of existing activities of the given type on the case | |
802 | * | |
803 | * @return string | |
804 | */ | |
805 | public static function getMaxInstancesBounceMessage($editUrl, $activityTypeName, $maxInstances, $activityCount) { | |
806 | $bounceMessage = NULL; | |
807 | if ($activityCount >= $maxInstances) { | |
808 | if ($maxInstances == 1) { | |
809 | $bounceMessage = ts("You can not add another '%1' activity to this case. %2", | |
810 | [ | |
811 | 1 => $activityTypeName, | |
812 | 2 => ts("Do you want to <a %1>edit the existing activity</a>?", [1 => "href='$editUrl'"]), | |
813 | ] | |
814 | ); | |
815 | } | |
816 | else { | |
817 | // More than one instance, so don't provide a link. What would it be a link to anyway? | |
818 | $bounceMessage = ts("You can not add another '%1' activity to this case.", | |
819 | [ | |
820 | 1 => $activityTypeName, | |
821 | ] | |
822 | ); | |
823 | } | |
824 | } | |
825 | return $bounceMessage; | |
826 | } | |
827 | ||
6a488035 | 828 | } |