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