Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
6a488035 TO |
2 | /* |
3 | +--------------------------------------------------------------------+ | |
81621fee | 4 | | CiviCRM version 4.7 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
1f4ea726 | 6 | | Copyright CiviCRM LLC (c) 2004-2017 | |
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 | +--------------------------------------------------------------------+ | |
26 | */ | |
27 | ||
28 | /** | |
244bbdd8 | 29 | * This api exposes CiviCRM Activity records. |
6a488035 TO |
30 | * |
31 | * @package CiviCRM_APIv3 | |
6a488035 TO |
32 | */ |
33 | ||
34 | ||
35 | /** | |
61fe4988 | 36 | * Creates or updates an Activity. |
6a488035 | 37 | * |
cf470720 | 38 | * @param array $params |
c28e1768 | 39 | * Array per getfields documentation. |
6a488035 | 40 | * |
77b97be7 | 41 | * @throws API_Exception |
a6c01b45 | 42 | * @return array |
00f8641b | 43 | * API result array |
6a488035 TO |
44 | */ |
45 | function civicrm_api3_activity_create($params) { | |
c16b4619 | 46 | $isNew = empty($params['id']); |
6a488035 | 47 | |
a7488080 | 48 | if (empty($params['id'])) { |
6a488035 TO |
49 | // an update does not require any mandatory parameters |
50 | civicrm_api3_verify_one_mandatory($params, | |
51 | NULL, | |
52 | array( | |
7cdbcb16 TO |
53 | 'activity_name', |
54 | 'activity_type_id', | |
55 | 'activity_label', | |
6a488035 TO |
56 | ) |
57 | ); | |
58 | } | |
59 | ||
6a488035 TO |
60 | // check for various error and required conditions |
61 | // note that almost all the processing in there should be managed by the wrapper layer | |
62 | // & should be removed - needs testing | |
63 | $errors = _civicrm_api3_activity_check_params($params); | |
64 | ||
65 | // this should not be required as should throw exception rather than return errors - | |
66 | //needs testing | |
67 | if (!empty($errors)) { | |
68 | return $errors; | |
69 | } | |
70 | ||
6a488035 | 71 | // processing for custom data |
10114f2d | 72 | $values = $activityArray = array(); |
6a488035 TO |
73 | _civicrm_api3_custom_format_params($params, $values, 'Activity'); |
74 | ||
75 | if (!empty($values['custom'])) { | |
76 | $params['custom'] = $values['custom']; | |
77 | } | |
78 | ||
79 | // this should be set as a default rather than hard coded | |
80 | // needs testing | |
81 | $params['skipRecentView'] = TRUE; | |
82 | ||
83 | // If this is a case activity, see if there is an existing activity | |
84 | // and set it as an old revision. Also retrieve details we'll need. | |
85 | // this handling should all be moved to the BAO layer | |
7cdbcb16 TO |
86 | $case_id = ''; |
87 | $createRevision = FALSE; | |
6a488035 | 88 | $oldActivityValues = array(); |
e96d5fa3 CW |
89 | // Lookup case id if not supplied |
90 | if (!isset($params['case_id']) && !empty($params['id'])) { | |
91 | $params['case_id'] = CRM_Core_DAO::singleValueQuery("SELECT case_id FROM civicrm_case_activity WHERE activity_id = " . (int) $params['id']); | |
92 | } | |
a7488080 | 93 | if (!empty($params['case_id'])) { |
6a488035 | 94 | $case_id = $params['case_id']; |
c16b4619 | 95 | if (!empty($params['id']) && Civi::settings()->get('civicaseActivityRevisions')) { |
6a488035 TO |
96 | $oldActivityParams = array('id' => $params['id']); |
97 | if (!$oldActivityValues) { | |
98 | CRM_Activity_BAO_Activity::retrieve($oldActivityParams, $oldActivityValues); | |
99 | } | |
100 | if (empty($oldActivityValues)) { | |
10114f2d | 101 | throw new API_Exception(ts("Unable to locate existing activity.")); |
6a488035 TO |
102 | } |
103 | else { | |
104 | $activityDAO = new CRM_Activity_DAO_Activity(); | |
105 | $activityDAO->id = $params['id']; | |
106 | $activityDAO->is_current_revision = 0; | |
107 | if (!$activityDAO->save()) { | |
08007144 TO |
108 | if (is_object($activityDAO)) { |
109 | $activityDAO->free(); | |
110 | } | |
10114f2d | 111 | throw new API_Exception(ts("Unable to revision existing case activity.")); |
6a488035 TO |
112 | } |
113 | $createRevision = TRUE; | |
114 | } | |
115 | } | |
116 | } | |
117 | ||
118 | $deleteActivityAssignment = FALSE; | |
119 | if (isset($params['assignee_contact_id'])) { | |
120 | $deleteActivityAssignment = TRUE; | |
121 | } | |
122 | ||
123 | $deleteActivityTarget = FALSE; | |
124 | if (isset($params['target_contact_id'])) { | |
125 | $deleteActivityTarget = TRUE; | |
126 | } | |
127 | ||
128 | // this should all be handled at the BAO layer | |
129 | $params['deleteActivityAssignment'] = CRM_Utils_Array::value('deleteActivityAssignment', $params, $deleteActivityAssignment); | |
130 | $params['deleteActivityTarget'] = CRM_Utils_Array::value('deleteActivityTarget', $params, $deleteActivityTarget); | |
131 | ||
132 | if ($case_id && $createRevision) { | |
133 | // This is very similar to the copy-to-case action. | |
134 | if (!CRM_Utils_Array::crmIsEmptyArray($oldActivityValues['target_contact'])) { | |
135 | $oldActivityValues['targetContactIds'] = implode(',', array_unique($oldActivityValues['target_contact'])); | |
136 | } | |
137 | if (!CRM_Utils_Array::crmIsEmptyArray($oldActivityValues['assignee_contact'])) { | |
138 | $oldActivityValues['assigneeContactIds'] = implode(',', array_unique($oldActivityValues['assignee_contact'])); | |
139 | } | |
140 | $oldActivityValues['mode'] = 'copy'; | |
141 | $oldActivityValues['caseID'] = $case_id; | |
142 | $oldActivityValues['activityID'] = $oldActivityValues['id']; | |
143 | $oldActivityValues['contactID'] = $oldActivityValues['source_contact_id']; | |
144 | ||
145 | $copyToCase = CRM_Activity_Page_AJAX::_convertToCaseActivity($oldActivityValues); | |
146 | if (empty($copyToCase['error_msg'])) { | |
147 | // now fix some things that are different from copy-to-case | |
148 | // then fall through to the create below to update with the passed in params | |
149 | $params['id'] = $copyToCase['newId']; | |
150 | $params['is_auto'] = 0; | |
151 | $params['original_id'] = empty($oldActivityValues['original_id']) ? $oldActivityValues['id'] : $oldActivityValues['original_id']; | |
152 | } | |
153 | else { | |
10114f2d | 154 | throw new API_Exception(ts("Unable to create new revision of case activity.")); |
6a488035 TO |
155 | } |
156 | } | |
157 | ||
158 | // create activity | |
159 | $activityBAO = CRM_Activity_BAO_Activity::create($params); | |
160 | ||
161 | if (isset($activityBAO->id)) { | |
c16b4619 | 162 | if ($case_id && $isNew && !$createRevision) { |
18e0f096 CW |
163 | // If this is a brand new case activity, add to case(s) |
164 | foreach ((array) $case_id as $singleCaseId) { | |
165 | $caseActivityParams = array('activity_id' => $activityBAO->id, 'case_id' => $singleCaseId); | |
166 | CRM_Case_BAO_Case::processCaseActivity($caseActivityParams); | |
167 | } | |
6a488035 TO |
168 | } |
169 | ||
170 | _civicrm_api3_object_to_array($activityBAO, $activityArray[$activityBAO->id]); | |
244bbdd8 | 171 | return civicrm_api3_create_success($activityArray, $params, 'Activity', 'get', $activityBAO); |
6a488035 TO |
172 | } |
173 | } | |
11e09c59 TO |
174 | |
175 | /** | |
61fe4988 EM |
176 | * Specify Meta data for create. |
177 | * | |
178 | * Note that this data is retrievable via the getfields function and is used for pre-filling defaults and | |
179 | * ensuring mandatory requirements are met. | |
180 | * | |
cf470720 | 181 | * @param array $params |
c28e1768 | 182 | * Array of parameters determined by getfields. |
6a488035 TO |
183 | */ |
184 | function _civicrm_api3_activity_create_spec(&$params) { | |
185 | ||
67744c4e CW |
186 | $params['status_id']['api.aliases'] = array('activity_status'); |
187 | ||
6a488035 TO |
188 | $params['assignee_contact_id'] = array( |
189 | 'name' => 'assignee_id', | |
0a24dc9a CW |
190 | 'title' => 'Activity Assignee', |
191 | 'description' => 'Contact(s) assigned to this activity.', | |
6a488035 | 192 | 'type' => 1, |
7e61908b | 193 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
0a24dc9a | 194 | 'FKApiName' => 'Contact', |
6a488035 TO |
195 | ); |
196 | $params['target_contact_id'] = array( | |
197 | 'name' => 'target_id', | |
198 | 'title' => 'Activity Target', | |
0a24dc9a | 199 | 'description' => 'Contact(s) participating in this activity.', |
6a488035 | 200 | 'type' => 1, |
7e61908b | 201 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
0a24dc9a | 202 | 'FKApiName' => 'Contact', |
6a488035 | 203 | ); |
2f3d72cf | 204 | |
205 | $params['source_contact_id'] = array( | |
7cdbcb16 TO |
206 | 'name' => 'source_contact_id', |
207 | 'title' => 'Activity Source Contact', | |
0a24dc9a | 208 | 'description' => 'Person who created this activity. Defaults to current user.', |
7cdbcb16 | 209 | 'type' => 1, |
7e61908b | 210 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
7cdbcb16 | 211 | 'api.default' => 'user_contact_id', |
0a24dc9a | 212 | 'FKApiName' => 'Contact', |
c442f1b6 | 213 | 'api.required' => TRUE, |
0a24dc9a CW |
214 | ); |
215 | ||
216 | $params['case_id'] = array( | |
217 | 'name' => 'case_id', | |
218 | 'title' => 'Case ID', | |
219 | 'description' => 'For creating an activity as part of a case.', | |
220 | 'type' => 1, | |
221 | 'FKClassName' => 'CRM_Case_DAO_Case', | |
222 | 'FKApiName' => 'Case', | |
2f3d72cf | 223 | ); |
224 | ||
6a488035 TO |
225 | } |
226 | ||
1196e086 CW |
227 | /** |
228 | * Specify Metadata for get. | |
229 | * | |
230 | * @param array $params | |
231 | */ | |
232 | function _civicrm_api3_activity_get_spec(&$params) { | |
233 | $params['tag_id'] = array( | |
1196e086 CW |
234 | 'title' => 'Tags', |
235 | 'description' => 'Find activities with specified tags.', | |
760ac501 | 236 | 'type' => CRM_Utils_Type::T_INT, |
1196e086 CW |
237 | 'FKClassName' => 'CRM_Core_DAO_Tag', |
238 | 'FKApiName' => 'Tag', | |
40875a91 CW |
239 | 'supports_joins' => TRUE, |
240 | ); | |
241 | $params['file_id'] = array( | |
242 | 'title' => 'Attached Files', | |
243 | 'description' => 'Find activities with attached files.', | |
760ac501 | 244 | 'type' => CRM_Utils_Type::T_INT, |
40875a91 CW |
245 | 'FKClassName' => 'CRM_Core_DAO_File', |
246 | 'FKApiName' => 'File', | |
1196e086 CW |
247 | ); |
248 | $params['case_id'] = array( | |
1196e086 CW |
249 | 'title' => 'Cases', |
250 | 'description' => 'Find activities within specified cases.', | |
760ac501 | 251 | 'type' => CRM_Utils_Type::T_INT, |
1196e086 CW |
252 | 'FKClassName' => 'CRM_Case_DAO_Case', |
253 | 'FKApiName' => 'Case', | |
2c9e4446 | 254 | 'supports_joins' => TRUE, |
1196e086 | 255 | ); |
526e0834 CW |
256 | $params['contact_id'] = array( |
257 | 'title' => 'Activity Contact ID', | |
258 | 'description' => 'Find activities involving this contact (as target, source, OR assignee).', | |
760ac501 | 259 | 'type' => CRM_Utils_Type::T_INT, |
526e0834 CW |
260 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
261 | 'FKApiName' => 'Contact', | |
262 | ); | |
1196e086 | 263 | $params['target_contact_id'] = array( |
1196e086 CW |
264 | 'title' => 'Target Contact ID', |
265 | 'description' => 'Find activities with specified target contact.', | |
760ac501 | 266 | 'type' => CRM_Utils_Type::T_INT, |
1196e086 CW |
267 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
268 | 'FKApiName' => 'Contact', | |
269 | ); | |
270 | $params['source_contact_id'] = array( | |
1196e086 CW |
271 | 'title' => 'Source Contact ID', |
272 | 'description' => 'Find activities with specified source contact.', | |
760ac501 | 273 | 'type' => CRM_Utils_Type::T_INT, |
1196e086 CW |
274 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
275 | 'FKApiName' => 'Contact', | |
276 | ); | |
277 | $params['assignee_contact_id'] = array( | |
1196e086 CW |
278 | 'title' => 'Assignee Contact ID', |
279 | 'description' => 'Find activities with specified assignee contact.', | |
760ac501 | 280 | 'type' => CRM_Utils_Type::T_INT, |
1196e086 CW |
281 | 'FKClassName' => 'CRM_Contact_DAO_Contact', |
282 | 'FKApiName' => 'Contact', | |
283 | ); | |
760ac501 CW |
284 | $params['is_overdue'] = array( |
285 | 'title' => 'Is Activity Overdue', | |
286 | 'description' => 'Incomplete activities with a past date.', | |
287 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
288 | ); | |
1196e086 CW |
289 | } |
290 | ||
6a488035 | 291 | /** |
61fe4988 | 292 | * Gets a CiviCRM activity according to parameters. |
6a488035 | 293 | * |
cf470720 | 294 | * @param array $params |
61fe4988 | 295 | * Array per getfields documentation. |
6a488035 | 296 | * |
bbd2743b | 297 | * @return array API result array |
00f8641b | 298 | * API result array |
bbd2743b | 299 | * |
300 | * @throws \API_Exception | |
301 | * @throws \CiviCRM_API3_Exception | |
302 | * @throws \Civi\API\Exception\UnauthorizedException | |
6a488035 TO |
303 | */ |
304 | function civicrm_api3_activity_get($params) { | |
760ac501 | 305 | $options = _civicrm_api3_get_options_from_params($params, FALSE, 'Activity', 'get'); |
526e0834 | 306 | $sql = CRM_Utils_SQL_Select::fragment(); |
d544ffcd | 307 | |
3c9d67b0 | 308 | if (empty($params['target_contact_id']) && empty($params['source_contact_id']) |
309 | && empty($params['assignee_contact_id']) && | |
310 | !empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities') | |
311 | && !CRM_Core_Permission::check('view all contacts') | |
312 | ) { | |
313 | // Force join on the activity contact table. | |
314 | // @todo get this & other acl filters to work, remove check further down. | |
315 | //$params['contact_id'] = array('IS NOT NULL' => TRUE); | |
316 | } | |
317 | ||
d544ffcd CW |
318 | _civicrm_api3_activity_get_extraFilters($params, $sql); |
319 | ||
320 | // Handle is_overdue sort | |
321 | if (!empty($options['sort'])) { | |
322 | $sort = explode(', ', $options['sort']); | |
323 | ||
324 | foreach ($sort as $index => &$sortString) { | |
325 | // Get sort field and direction | |
326 | list($sortField, $dir) = array_pad(explode(' ', $sortString), 2, 'ASC'); | |
327 | if ($sortField == 'is_overdue') { | |
328 | $incomplete = implode(',', array_keys(CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::INCOMPLETE))); | |
329 | $sql->orderBy("IF((a.activity_date_time >= NOW() OR a.status_id NOT IN ($incomplete)), 0, 1) $dir", NULL, $index); | |
330 | // Replace the sort with a placeholder which will be ignored by sql | |
331 | $sortString = '(1)'; | |
332 | } | |
333 | } | |
334 | $params['options']['sort'] = implode(', ', $sort); | |
335 | } | |
336 | ||
337 | // Ensure there's enough data for calculating is_overdue | |
338 | if (!empty($options['return']['is_overdue']) && (empty($options['return']['status_id']) || empty($options['return']['activity_date_time']))) { | |
339 | $options['return']['status_id'] = $options['return']['activity_date_time'] = 1; | |
340 | $params['return'] = array_keys($options['return']); | |
341 | } | |
342 | ||
343 | $activities = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, 'Activity', $sql); | |
344 | if (!empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities')) { | |
345 | // @todo get this to work at the query level - see contact_id join above. | |
346 | foreach ($activities as $activity) { | |
347 | if (!CRM_Activity_BAO_Activity::checkPermission($activity['id'], CRM_Core_Action::VIEW)) { | |
348 | unset($activities[$activity['id']]); | |
349 | } | |
350 | } | |
351 | } | |
352 | if ($options['is_count']) { | |
353 | return civicrm_api3_create_success($activities, $params, 'Activity', 'get'); | |
354 | } | |
355 | ||
356 | $activities = _civicrm_api3_activity_get_formatResult($params, $activities, $options); | |
357 | //legacy custom data get - so previous formatted response is still returned too | |
358 | return civicrm_api3_create_success($activities, $params, 'Activity', 'get'); | |
359 | } | |
360 | ||
361 | /** | |
362 | * Support filters beyond what basic_get can do. | |
363 | * | |
364 | * @param array $params | |
365 | * @param CRM_Utils_SQL_Select $sql | |
366 | * @throws \CiviCRM_API3_Exception | |
367 | * @throws \Exception | |
368 | */ | |
369 | function _civicrm_api3_activity_get_extraFilters(&$params, &$sql) { | |
370 | // Filter by activity contacts | |
371 | $recordTypes = civicrm_api3('ActivityContact', 'getoptions', array('field' => 'record_type_id')); | |
372 | $recordTypes = $recordTypes['values']; | |
373 | $activityContactOptions = array( | |
374 | 'contact_id' => NULL, | |
375 | 'target_contact_id' => array_search('Activity Targets', $recordTypes), | |
376 | 'source_contact_id' => array_search('Activity Source', $recordTypes), | |
377 | 'assignee_contact_id' => array_search('Activity Assignees', $recordTypes), | |
378 | ); | |
526e0834 CW |
379 | foreach ($activityContactOptions as $activityContactName => $activityContactValue) { |
380 | if (!empty($params[$activityContactName])) { | |
526e0834 CW |
381 | if (!is_array($params[$activityContactName])) { |
382 | $params[$activityContactName] = array('=' => $params[$activityContactName]); | |
383 | } | |
384 | $clause = \CRM_Core_DAO::createSQLFilter('contact_id', $params[$activityContactName]); | |
385 | $typeClause = $activityContactValue ? 'record_type_id = #typeId AND ' : ''; | |
386 | $sql->where("a.id IN (SELECT activity_id FROM civicrm_activity_contact WHERE $typeClause !clause)", | |
387 | array('#typeId' => $activityContactValue, '!clause' => $clause) | |
388 | ); | |
6a488035 TO |
389 | } |
390 | } | |
749522a2 | 391 | |
760ac501 | 392 | // Handle is_overdue filter |
d544ffcd | 393 | // Boolean calculated field - does not support operators |
760ac501 | 394 | if (isset($params['is_overdue'])) { |
ce9d78e1 | 395 | $incomplete = implode(',', array_keys(CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::INCOMPLETE))); |
760ac501 CW |
396 | if ($params['is_overdue']) { |
397 | $sql->where('a.activity_date_time < NOW()'); | |
ce9d78e1 | 398 | $sql->where("a.status_id IN ($incomplete)"); |
760ac501 CW |
399 | } |
400 | else { | |
ce9d78e1 | 401 | $sql->where("(a.activity_date_time >= NOW() OR a.status_id NOT IN ($incomplete))"); |
760ac501 CW |
402 | } |
403 | } | |
404 | ||
749522a2 TO |
405 | // Define how to handle filters on some related entities. |
406 | // Subqueries are nice in (a) avoiding duplicates and (b) when the result | |
407 | // list is expected to be bite-sized. Joins are nice (a) with larger | |
408 | // datasets and (b) checking for non-existent relations. | |
409 | $rels = array( | |
410 | 'tag_id' => array( | |
411 | 'subquery' => 'a.id IN (SELECT entity_id FROM civicrm_entity_tag WHERE entity_table = "civicrm_activity" AND !clause)', | |
412 | 'join' => '!joinType civicrm_entity_tag !alias ON (!alias.entity_table = "civicrm_activity" AND !alias.entity_id = a.id)', | |
413 | 'column' => 'tag_id', | |
414 | ), | |
415 | 'file_id' => array( | |
416 | 'subquery' => 'a.id IN (SELECT entity_id FROM civicrm_entity_file WHERE entity_table = "civicrm_activity" AND !clause)', | |
417 | 'join' => '!joinType civicrm_entity_file !alias ON (!alias.entity_table = "civicrm_activity" AND !alias.entity_id = a.id)', | |
418 | 'column' => 'file_id', | |
419 | ), | |
420 | 'case_id' => array( | |
421 | 'subquery' => 'a.id IN (SELECT activity_id FROM civicrm_case_activity WHERE !clause)', | |
422 | 'join' => '!joinType civicrm_case_activity !alias ON (!alias.activity_id = a.id)', | |
423 | 'column' => 'case_id', | |
424 | ), | |
425 | ); | |
426 | foreach ($rels as $filter => $relSpec) { | |
427 | if (!empty($params[$filter])) { | |
428 | if (!is_array($params[$filter])) { | |
429 | $params[$filter] = array('=' => $params[$filter]); | |
430 | } | |
431 | // $mode is one of ('LEFT JOIN', 'INNER JOIN', 'SUBQUERY') | |
432 | $mode = isset($params[$filter]['IS NULL']) ? 'LEFT JOIN' : 'SUBQUERY'; | |
433 | if ($mode === 'SUBQUERY') { | |
434 | $clause = \CRM_Core_DAO::createSQLFilter($relSpec['column'], $params[$filter]); | |
435 | if ($clause) { | |
436 | $sql->where($relSpec['subquery'], array('!clause' => $clause)); | |
437 | } | |
438 | } | |
439 | else { | |
440 | $alias = 'actjoin_' . $filter; | |
441 | $clause = \CRM_Core_DAO::createSQLFilter($alias . "." . $relSpec['column'], $params[$filter]); | |
442 | if ($clause) { | |
443 | $sql->join($alias, $relSpec['join'], array('!alias' => $alias, 'joinType' => $mode)); | |
444 | $sql->where($clause); | |
445 | } | |
446 | } | |
0298287b | 447 | } |
6a488035 | 448 | } |
ab5fa8f2 TO |
449 | } |
450 | ||
451 | /** | |
61fe4988 | 452 | * Given a list of activities, append any extra data requested about the activities. |
ab5fa8f2 | 453 | * |
b081365f | 454 | * @note Called by civicrm-core and CiviHR |
ab5fa8f2 | 455 | * |
cf470720 TO |
456 | * @param array $params |
457 | * API request parameters. | |
ab5fa8f2 | 458 | * @param array $activities |
61fe4988 | 459 | * |
a6c01b45 | 460 | * @return array |
72b3a70c | 461 | * new activities list |
ab5fa8f2 | 462 | */ |
bc4b6f0f | 463 | function _civicrm_api3_activity_get_formatResult($params, $activities, $options) { |
30db5cbf CW |
464 | if (!$activities) { |
465 | return $activities; | |
466 | } | |
467 | ||
bc4b6f0f | 468 | $returns = $options['return']; |
6a488035 TO |
469 | foreach ($params as $n => $v) { |
470 | if (substr($n, 0, 7) == 'return.') { | |
471 | $returnkey = substr($n, 7); | |
472 | $returns[$returnkey] = $v; | |
473 | } | |
474 | } | |
0298287b | 475 | |
2f3d72cf | 476 | $returns['source_contact_id'] = 1; |
db6e8cb4 CW |
477 | if (!empty($returns['target_contact_name'])) { |
478 | $returns['target_contact_id'] = 1; | |
479 | } | |
480 | if (!empty($returns['assignee_contact_name'])) { | |
481 | $returns['assignee_contact_id'] = 1; | |
482 | } | |
483 | ||
40875a91 | 484 | $tagGet = array('tag_id', 'entity_id'); |
2c9e4446 | 485 | $caseGet = $caseIds = array(); |
40875a91 CW |
486 | foreach (array_keys($returns) as $key) { |
487 | if (strpos($key, 'tag_id.') === 0) { | |
488 | $tagGet[] = $key; | |
489 | $returns['tag_id'] = 1; | |
490 | } | |
2c9e4446 CW |
491 | if (strpos($key, 'case_id.') === 0) { |
492 | $caseGet[] = str_replace('case_id.', '', $key); | |
493 | $returns['case_id'] = 1; | |
494 | } | |
40875a91 CW |
495 | } |
496 | ||
6a488035 TO |
497 | foreach ($returns as $n => $v) { |
498 | switch ($n) { | |
499 | case 'assignee_contact_id': | |
500 | foreach ($activities as $key => $activityArray) { | |
db6e8cb4 CW |
501 | $cids = $activities[$key]['assignee_contact_id'] = CRM_Activity_BAO_ActivityAssignment::retrieveAssigneeIdsByActivityId($activityArray['id']); |
502 | if ($cids && !empty($returns['assignee_contact_name'])) { | |
503 | foreach ($cids as $cid) { | |
504 | $activities[$key]['assignee_contact_name'][$cid] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'); | |
505 | } | |
506 | } | |
6a488035 TO |
507 | } |
508 | break; | |
35671d00 | 509 | |
6a488035 TO |
510 | case 'target_contact_id': |
511 | foreach ($activities as $key => $activityArray) { | |
db6e8cb4 CW |
512 | $cids = $activities[$key]['target_contact_id'] = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activityArray['id']); |
513 | if ($cids && !empty($returns['target_contact_name'])) { | |
514 | foreach ($cids as $cid) { | |
515 | $activities[$key]['target_contact_name'][$cid] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'); | |
516 | } | |
517 | } | |
6a488035 TO |
518 | } |
519 | break; | |
35671d00 | 520 | |
42d30b83 DL |
521 | case 'source_contact_id': |
522 | foreach ($activities as $key => $activityArray) { | |
db6e8cb4 CW |
523 | $cid = $activities[$key]['source_contact_id'] = CRM_Activity_BAO_Activity::getSourceContactID($activityArray['id']); |
524 | if ($cid && !empty($returns['source_contact_name'])) { | |
525 | $activities[$key]['source_contact_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'); | |
526 | } | |
42d30b83 DL |
527 | } |
528 | break; | |
35671d00 | 529 | |
30db5cbf CW |
530 | case 'tag_id': |
531 | $tags = civicrm_api3('EntityTag', 'get', array( | |
532 | 'entity_table' => 'civicrm_activity', | |
533 | 'entity_id' => array('IN' => array_keys($activities)), | |
40875a91 | 534 | 'return' => $tagGet, |
30db5cbf CW |
535 | 'options' => array('limit' => 0), |
536 | )); | |
537 | foreach ($tags['values'] as $tag) { | |
40875a91 CW |
538 | $key = (int) $tag['entity_id']; |
539 | unset($tag['entity_id'], $tag['id']); | |
540 | $activities[$key]['tag_id'][$tag['tag_id']] = $tag; | |
541 | } | |
542 | break; | |
543 | ||
544 | case 'file_id': | |
545 | $dao = CRM_Core_DAO::executeQuery("SELECT entity_id, file_id FROM civicrm_entity_file WHERE entity_table = 'civicrm_activity' AND entity_id IN (%1)", | |
546 | array(1 => array(implode(',', array_keys($activities)), 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES))); | |
547 | while ($dao->fetch()) { | |
548 | $activities[$dao->entity_id]['file_id'][] = $dao->file_id; | |
30db5cbf CW |
549 | } |
550 | break; | |
551 | ||
bc4b6f0f CW |
552 | case 'case_id': |
553 | $dao = CRM_Core_DAO::executeQuery("SELECT activity_id, case_id FROM civicrm_case_activity WHERE activity_id IN (%1)", | |
554 | array(1 => array(implode(',', array_keys($activities)), 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES))); | |
555 | while ($dao->fetch()) { | |
18e0f096 | 556 | $activities[$dao->activity_id]['case_id'][] = $dao->case_id; |
2c9e4446 | 557 | $caseIds[$dao->case_id] = $dao->case_id; |
bc4b6f0f CW |
558 | } |
559 | break; | |
560 | ||
760ac501 CW |
561 | case 'is_overdue': |
562 | foreach ($activities as $key => $activityArray) { | |
563 | $activities[$key]['is_overdue'] = (int) CRM_Activity_BAO_Activity::isOverdue($activityArray); | |
564 | } | |
565 | break; | |
566 | ||
6a488035 TO |
567 | default: |
568 | if (substr($n, 0, 6) == 'custom') { | |
569 | $returnProperties[$n] = $v; | |
570 | } | |
2c9e4446 CW |
571 | } |
572 | } | |
573 | ||
574 | // Fetch case fields via the join syntax | |
575 | // Note this is limited to the first case if the activity belongs to more than one | |
576 | if ($caseGet && $caseIds) { | |
577 | $cases = civicrm_api3('Case', 'get', array( | |
578 | 'id' => array('IN' => $caseIds), | |
579 | 'options' => array('limit' => 0), | |
580 | 'check_permissions' => !empty($params['check_permissions']), | |
581 | 'return' => $caseGet, | |
582 | )); | |
583 | foreach ($activities as &$activity) { | |
584 | if (!empty($activity['case_id'])) { | |
585 | $case = CRM_Utils_Array::value($activity['case_id'][0], $cases['values']); | |
586 | if ($case) { | |
587 | foreach ($case as $key => $value) { | |
588 | if ($key != 'id') { | |
589 | $activity['case_id.' . $key] = $value; | |
590 | } | |
591 | } | |
592 | } | |
593 | } | |
6a488035 TO |
594 | } |
595 | } | |
526e0834 | 596 | |
40875a91 | 597 | // Legacy extras |
526e0834 CW |
598 | if (!empty($params['contact_id'])) { |
599 | $statusOptions = CRM_Activity_BAO_Activity::buildOptions('status_id', 'get'); | |
600 | $typeOptions = CRM_Activity_BAO_Activity::buildOptions('activity_type_id', 'validate'); | |
601 | foreach ($activities as $key => &$activityArray) { | |
602 | if (!empty($activityArray['status_id'])) { | |
603 | $activityArray['status'] = $statusOptions[$activityArray['status_id']]; | |
604 | } | |
605 | if (!empty($activityArray['activity_type_id'])) { | |
606 | $activityArray['activity_name'] = $typeOptions[$activityArray['activity_type_id']]; | |
607 | } | |
608 | } | |
609 | } | |
610 | ||
30db5cbf | 611 | if (!empty($returnProperties) || !empty($params['contact_id'])) { |
6a488035 | 612 | foreach ($activities as $activityId => $values) { |
10114f2d | 613 | //@todo - should possibly load activity type id if not loaded (update with id) |
e9ff5391 | 614 | _civicrm_api3_custom_data_get($activities[$activityId], CRM_Utils_Array::value('check_permissions', $params), 'Activity', $activityId, NULL, CRM_Utils_Array::value('activity_type_id', $values)); |
6a488035 TO |
615 | } |
616 | } | |
ab5fa8f2 | 617 | return $activities; |
6a488035 TO |
618 | } |
619 | ||
2f3d72cf | 620 | |
6a488035 TO |
621 | /** |
622 | * Delete a specified Activity. | |
623 | * | |
cf470720 TO |
624 | * @param array $params |
625 | * Array holding 'id' of activity to be deleted. | |
6a488035 | 626 | * |
10114f2d | 627 | * @throws API_Exception |
6a488035 | 628 | * |
61fe4988 | 629 | * @return array |
00f8641b | 630 | * API result array |
6a488035 TO |
631 | */ |
632 | function civicrm_api3_activity_delete($params) { | |
633 | ||
634 | if (CRM_Activity_BAO_Activity::deleteActivity($params)) { | |
244bbdd8 | 635 | return civicrm_api3_create_success(1, $params, 'Activity', 'delete'); |
6a488035 TO |
636 | } |
637 | else { | |
244bbdd8 | 638 | throw new API_Exception('Could not delete Activity'); |
6a488035 TO |
639 | } |
640 | } | |
641 | ||
642 | /** | |
61fe4988 | 643 | * Check for required params. |
6a488035 | 644 | * |
cf470720 TO |
645 | * @param array $params |
646 | * Associated array of fields. | |
10114f2d EM |
647 | * |
648 | * @throws API_Exception | |
649 | * @throws Exception | |
a6c01b45 | 650 | * @return array |
72b3a70c | 651 | * array with errors |
6a488035 TO |
652 | */ |
653 | function _civicrm_api3_activity_check_params(&$params) { | |
35671d00 | 654 | $activityIds = array( |
7cdbcb16 TO |
655 | 'activity' => CRM_Utils_Array::value('id', $params), |
656 | 'parent' => CRM_Utils_Array::value('parent_id', $params), | |
657 | 'original' => CRM_Utils_Array::value('original_id', $params), | |
6a488035 TO |
658 | ); |
659 | ||
660 | foreach ($activityIds as $id => $value) { | |
661 | if ($value && | |
662 | !CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $value, 'id') | |
663 | ) { | |
10114f2d | 664 | throw new API_Exception('Invalid ' . ucfirst($id) . ' Id'); |
6a488035 TO |
665 | } |
666 | } | |
667 | // this should be handled by wrapper layer & probably the api would already manage it | |
668 | //correctly by doing pseudoconstant validation | |
669 | // needs testing | |
a60ed840 | 670 | $activityTypes = CRM_Activity_BAO_Activity::buildOptions('activity_type_id', 'validate'); |
7cdbcb16 TO |
671 | $activityName = CRM_Utils_Array::value('activity_name', $params); |
672 | $activityName = ucfirst($activityName); | |
6a488035 TO |
673 | $activityLabel = CRM_Utils_Array::value('activity_label', $params); |
674 | if ($activityLabel) { | |
a60ed840 | 675 | $activityTypes = CRM_Activity_BAO_Activity::buildOptions('activity_type_id', 'create'); |
6a488035 TO |
676 | } |
677 | ||
678 | $activityTypeId = CRM_Utils_Array::value('activity_type_id', $params); | |
679 | ||
680 | if ($activityName || $activityLabel) { | |
681 | $activityTypeIdInList = array_search(($activityName ? $activityName : $activityLabel), $activityTypes); | |
682 | ||
683 | if (!$activityTypeIdInList) { | |
35671d00 | 684 | $errorString = $activityName ? "Invalid Activity Name : $activityName" : "Invalid Activity Type Label"; |
6a488035 TO |
685 | throw new Exception($errorString); |
686 | } | |
687 | elseif ($activityTypeId && ($activityTypeId != $activityTypeIdInList)) { | |
10114f2d | 688 | throw new API_Exception('Mismatch in Activity'); |
6a488035 TO |
689 | } |
690 | $params['activity_type_id'] = $activityTypeIdInList; | |
691 | } | |
692 | elseif ($activityTypeId && | |
693 | !array_key_exists($activityTypeId, $activityTypes) | |
694 | ) { | |
10114f2d | 695 | throw new API_Exception('Invalid Activity Type ID'); |
6a488035 TO |
696 | } |
697 | ||
6a488035 TO |
698 | // check for activity duration minutes |
699 | // this should be validated @ the wrapper layer not here | |
700 | // needs testing | |
701 | if (isset($params['duration_minutes']) && !is_numeric($params['duration_minutes'])) { | |
10114f2d | 702 | throw new API_Exception('Invalid Activity Duration (in minutes)'); |
6a488035 TO |
703 | } |
704 | ||
6a488035 TO |
705 | //if adding a new activity & date_time not set make it now |
706 | // this should be managed by the wrapper layer & setting ['api.default'] in speces | |
707 | // needs testing | |
8cc574cf | 708 | if (empty($params['id']) && empty($params['activity_date_time'])) { |
6a488035 TO |
709 | $params['activity_date_time'] = CRM_Utils_Date::processDate(date('Y-m-d H:i:s')); |
710 | } | |
711 | ||
712 | return NULL; | |
713 | } | |
714 | ||
dabf9814 | 715 | /** |
61fe4988 EM |
716 | * Get parameters for activity list. |
717 | * | |
7cdbcb16 | 718 | * @see _civicrm_api3_generic_getlist_params |
dabf9814 | 719 | * |
7cdbcb16 TO |
720 | * @param array $request |
721 | * API request. | |
dabf9814 CW |
722 | */ |
723 | function _civicrm_api3_activity_getlist_params(&$request) { | |
7cdbcb16 TO |
724 | $fieldsToReturn = array( |
725 | 'activity_date_time', | |
726 | 'activity_type_id', | |
727 | 'subject', | |
728 | 'source_contact_id', | |
729 | ); | |
dabf9814 CW |
730 | $request['params']['return'] = array_unique(array_merge($fieldsToReturn, $request['extra'])); |
731 | $request['params']['options']['sort'] = 'activity_date_time DESC'; | |
732 | $request['params'] += array( | |
733 | 'is_current_revision' => 1, | |
734 | 'is_deleted' => 0, | |
735 | ); | |
736 | } | |
737 | ||
738 | /** | |
61fe4988 EM |
739 | * Get output for activity list. |
740 | * | |
dabf9814 CW |
741 | * @see _civicrm_api3_generic_getlist_output |
742 | * | |
8c6b335b CW |
743 | * @param array $result |
744 | * @param array $request | |
dabf9814 CW |
745 | * |
746 | * @return array | |
747 | */ | |
748 | function _civicrm_api3_activity_getlist_output($result, $request) { | |
749 | $output = array(); | |
750 | if (!empty($result['values'])) { | |
751 | foreach ($result['values'] as $row) { | |
752 | $data = array( | |
753 | 'id' => $row[$request['id_field']], | |
754 | 'label' => $row[$request['label_field']] ? $row[$request['label_field']] : ts('(no subject)'), | |
7cdbcb16 TO |
755 | 'description' => array( |
756 | CRM_Core_Pseudoconstant::getLabel('CRM_Activity_BAO_Activity', 'activity_type_id', $row['activity_type_id']), | |
757 | ), | |
dabf9814 CW |
758 | ); |
759 | if (!empty($row['activity_date_time'])) { | |
760 | $data['description'][0] .= ': ' . CRM_Utils_Date::customFormat($row['activity_date_time']); | |
761 | } | |
762 | if (!empty($row['source_contact_id'])) { | |
7cdbcb16 TO |
763 | $data['description'][] = ts('By %1', array( |
764 | 1 => CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $row['source_contact_id'], 'display_name'), | |
765 | )); | |
dabf9814 | 766 | } |
8a938c69 CW |
767 | // Add repeating info |
768 | $repeat = CRM_Core_BAO_RecurringEntity::getPositionAndCount($row['id'], 'civicrm_activity'); | |
769 | $data['extra']['is_recur'] = FALSE; | |
770 | if ($repeat) { | |
771 | $data['suffix'] = ts('(%1 of %2)', array(1 => $repeat[0], 2 => $repeat[1])); | |
772 | $data['extra']['is_recur'] = TRUE; | |
773 | } | |
dabf9814 CW |
774 | $output[] = $data; |
775 | } | |
776 | } | |
777 | return $output; | |
778 | } |