Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
6a488035 TO |
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 | +--------------------------------------------------------------------+ | |
e70a7fc0 | 26 | */ |
6a488035 TO |
27 | |
28 | /** | |
b081365f | 29 | * This api exposes CiviCRM Case objects. |
6a488035 TO |
30 | * Developed by woolman.org |
31 | * | |
32 | * @package CiviCRM_APIv3 | |
6a488035 TO |
33 | */ |
34 | ||
35 | ||
36 | /** | |
244bbdd8 | 37 | * Open a new case, add client and manager roles, and standard timeline. |
6a488035 | 38 | * |
6c552737 | 39 | * @param array $params |
37b8953e | 40 | * |
b081365f | 41 | * @code |
ea2aa8ff | 42 | * // REQUIRED for create: |
6a488035 TO |
43 | * 'case_type_id' => int OR |
44 | * 'case_type' => str (provide one or the other) | |
45 | * 'contact_id' => int // case client | |
46 | * 'subject' => str | |
ea2aa8ff | 47 | * // REQUIRED for update: |
791a8dc4 | 48 | * 'id' => case Id |
6a488035 TO |
49 | * |
50 | * //OPTIONAL | |
51 | * 'medium_id' => int // see civicrm option values for possibilities | |
52 | * 'creator_id' => int // case manager, default to the logged in user | |
53 | * 'status_id' => int // defaults to 1 "ongoing" | |
54 | * 'location' => str | |
55 | * 'start_date' => str datestamp // defaults to: date('YmdHis') | |
56 | * 'duration' => int // in minutes | |
57 | * 'details' => str // html format | |
b081365f | 58 | * @endcode |
6a488035 | 59 | * |
784e85a1 | 60 | * @throws API_Exception |
a6c01b45 | 61 | * @return array |
72b3a70c | 62 | * api result array |
6a488035 TO |
63 | */ |
64 | function civicrm_api3_case_create($params) { | |
6a488035 TO |
65 | _civicrm_api3_case_format_params($params); |
66 | ||
da4d8910 MW |
67 | if (empty($params['id'])) { |
68 | // Creating a new case, so make sure we have the necessary parameters | |
cf8f0fff | 69 | civicrm_api3_verify_mandatory($params, NULL, [ |
da4d8910 MW |
70 | 'contact_id', |
71 | 'subject', | |
cf8f0fff CW |
72 | ['case_type', 'case_type_id'], |
73 | ] | |
da4d8910 | 74 | ); |
6a488035 | 75 | } |
da4d8910 MW |
76 | else { |
77 | // Update an existing case | |
78 | // FIXME: Some of this logic should move to the BAO object? | |
79 | // FIXME: Should we check if case with ID actually exists? | |
6a488035 | 80 | |
da4d8910 | 81 | if (array_key_exists('creator_id', $params)) { |
ef76301b | 82 | throw new API_Exception('You cannot update creator id'); |
da4d8910 MW |
83 | } |
84 | ||
cf8f0fff | 85 | $mergedCaseIds = $origContactIds = []; |
da4d8910 | 86 | |
ea2aa8ff | 87 | // If a contact ID is specified we need to make sure this is the main contact ID for the case (and update if necessary) |
da4d8910 MW |
88 | if (!empty($params['contact_id'])) { |
89 | $origContactIds = CRM_Case_BAO_Case::retrieveContactIdsByCaseId($params['id']); | |
da4d8910 | 90 | |
ea2aa8ff MW |
91 | // Get the original contact ID for the case |
92 | // FIXME: Refactor as separate method to get contactId | |
93 | if (count($origContactIds) > 1) { | |
94 | // Multiple original contact IDs. Need to specify which one to use as a parameter | |
95 | if (empty($params['orig_contact_id'])) { | |
96 | throw new API_Exception('Case is linked with more than one contact id. Provide the required params orig_contact_id to be replaced'); | |
97 | } | |
98 | if (!empty($params['orig_contact_id']) && !in_array($params['orig_contact_id'], $origContactIds)) { | |
99 | throw new API_Exception('Invalid case contact id (orig_contact_id)'); | |
100 | } | |
101 | $origContactId = $params['orig_contact_id']; | |
2a3c0d28 | 102 | } |
ea2aa8ff MW |
103 | else { |
104 | // Only one original contact ID | |
105 | $origContactId = CRM_Utils_Array::first($origContactIds); | |
da4d8910 | 106 | } |
6a488035 | 107 | |
ea2aa8ff MW |
108 | // Get the specified main contact ID for the case |
109 | $mainContactId = CRM_Utils_Array::first($params['contact_id']); | |
da4d8910 | 110 | |
ea2aa8ff MW |
111 | // If the main contact ID is not in the list of original contact IDs for the case we need to change the main contact ID for the case |
112 | // This means we'll end up with a new case ID | |
113 | if (!in_array($mainContactId, $origContactIds)) { | |
114 | $mergedCaseIds = CRM_Case_BAO_Case::mergeCases($mainContactId, $params['id'], $origContactId, NULL, TRUE); | |
115 | // If we merged cases then the first element will contain the case ID of the merged case - update that one | |
116 | $params['id'] = CRM_Utils_Array::first($mergedCaseIds); | |
117 | } | |
da4d8910 MW |
118 | } |
119 | } | |
120 | ||
121 | // Create/update the case | |
122 | $caseBAO = CRM_Case_BAO_Case::create($params); | |
6a488035 TO |
123 | |
124 | if (!$caseBAO) { | |
784e85a1 | 125 | throw new API_Exception('Case not created. Please check input params.'); |
6a488035 TO |
126 | } |
127 | ||
6e36c320 | 128 | if (isset($params['contact_id']) && !isset($params['id'])) { |
791a8dc4 | 129 | foreach ((array) $params['contact_id'] as $cid) { |
cf8f0fff | 130 | $contactParams = ['case_id' => $caseBAO->id, 'contact_id' => $cid]; |
791a8dc4 MW |
131 | CRM_Case_BAO_CaseContact::create($contactParams); |
132 | } | |
6a488035 TO |
133 | } |
134 | ||
da4d8910 | 135 | if (!isset($params['id'])) { |
2a3c0d28 MW |
136 | // As the API was not passed an id we have created a new case. |
137 | // Only run the xmlProcessor for new cases to get all configuration for the new case. | |
da4d8910 MW |
138 | _civicrm_api3_case_create_xmlProcessor($params, $caseBAO); |
139 | } | |
140 | ||
141 | // return case | |
cf8f0fff | 142 | $values = []; |
da4d8910 MW |
143 | _civicrm_api3_object_to_array($caseBAO, $values[$caseBAO->id]); |
144 | ||
da4d8910 MW |
145 | return civicrm_api3_create_success($values, $params, 'Case', 'create', $caseBAO); |
146 | } | |
147 | ||
2a3c0d28 MW |
148 | /** |
149 | * When creating a new case, run the xmlProcessor to get all necessary params/configuration | |
150 | * for the new case, as cases use an xml file to store their configuration. | |
ea2aa8ff | 151 | * |
2a3c0d28 MW |
152 | * @param $params |
153 | * @param $caseBAO | |
ea2aa8ff MW |
154 | * |
155 | * @throws \Exception | |
2a3c0d28 | 156 | */ |
da4d8910 MW |
157 | function _civicrm_api3_case_create_xmlProcessor($params, $caseBAO) { |
158 | // Format params for xmlProcessor | |
ebf4aeaa MW |
159 | if (isset($caseBAO->id)) { |
160 | $params['id'] = $caseBAO->id; | |
161 | } | |
da4d8910 | 162 | |
6a488035 TO |
163 | // Initialize XML processor with $params |
164 | $xmlProcessor = new CRM_Case_XMLProcessor_Process(); | |
cf8f0fff | 165 | $xmlProcessorParams = [ |
2a3c0d28 MW |
166 | 'clientID' => CRM_Utils_Array::value('contact_id', $params), |
167 | 'creatorID' => CRM_Utils_Array::value('creator_id', $params), | |
6a488035 TO |
168 | 'standardTimeline' => 1, |
169 | 'activityTypeName' => 'Open Case', | |
2a3c0d28 MW |
170 | 'caseID' => CRM_Utils_Array::value('id', $params), |
171 | 'subject' => CRM_Utils_Array::value('subject', $params), | |
172 | 'location' => CRM_Utils_Array::value('location', $params), | |
173 | 'activity_date_time' => CRM_Utils_Array::value('start_date', $params), | |
174 | 'duration' => CRM_Utils_Array::value('duration', $params), | |
175 | 'medium_id' => CRM_Utils_Array::value('medium_id', $params), | |
176 | 'details' => CRM_Utils_Array::value('details', $params), | |
cf8f0fff | 177 | 'custom' => [], |
3717c347 | 178 | 'relationship_end_date' => CRM_Utils_Array::value('end_date', $params), |
cf8f0fff | 179 | ]; |
6a488035 TO |
180 | |
181 | // Do it! :-D | |
182 | $xmlProcessor->run($params['case_type'], $xmlProcessorParams); | |
6a488035 TO |
183 | } |
184 | ||
11e09c59 | 185 | /** |
2fb1dd66 | 186 | * Adjust Metadata for Get Action. |
6a488035 | 187 | * |
cf470720 | 188 | * @param array $params |
2fb1dd66 | 189 | * Parameters determined by getfields. |
6a488035 TO |
190 | */ |
191 | function _civicrm_api3_case_get_spec(&$params) { | |
cf8f0fff CW |
192 | $params['contact_id'] = [ |
193 | 'api.aliases' => ['client_id'], | |
d142432b | 194 | 'title' => 'Case Client', |
48bdb3cd | 195 | 'description' => 'Contact id of one or more clients to retrieve cases for', |
d142432b | 196 | 'type' => CRM_Utils_Type::T_INT, |
cf8f0fff CW |
197 | ]; |
198 | $params['activity_id'] = [ | |
48bdb3cd CW |
199 | 'title' => 'Case Activity', |
200 | 'description' => 'Id of an activity in the case', | |
201 | 'type' => CRM_Utils_Type::T_INT, | |
cf8f0fff CW |
202 | ]; |
203 | $params['tag_id'] = [ | |
9ef16723 | 204 | 'title' => 'Tags', |
cde84d6f | 205 | 'description' => 'Find cases with specified tags.', |
9ef16723 CW |
206 | 'type' => 1, |
207 | 'FKClassName' => 'CRM_Core_DAO_Tag', | |
208 | 'FKApiName' => 'Tag', | |
209 | 'supports_joins' => TRUE, | |
cf8f0fff | 210 | ]; |
6a488035 TO |
211 | } |
212 | ||
11e09c59 | 213 | /** |
2fb1dd66 | 214 | * Adjust Metadata for Create Action. |
6a488035 | 215 | * |
cf470720 | 216 | * @param array $params |
b081365f | 217 | * Array of parameters determined by getfields. |
6a488035 TO |
218 | */ |
219 | function _civicrm_api3_case_create_spec(&$params) { | |
cf8f0fff CW |
220 | $params['contact_id'] = [ |
221 | 'api.aliases' => ['client_id'], | |
d142432b | 222 | 'title' => 'Case Client', |
48bdb3cd | 223 | 'description' => 'Contact id of case client(s)', |
d142432b EM |
224 | 'api.required' => 1, |
225 | 'type' => CRM_Utils_Type::T_INT, | |
6e36c320 | 226 | 'FKApiName' => 'Contact', |
cf8f0fff | 227 | ]; |
6a488035 | 228 | $params['status_id']['api.default'] = 1; |
cf8f0fff | 229 | $params['status_id']['api.aliases'] = ['case_status']; |
941feb14 EM |
230 | $params['creator_id']['api.default'] = 'user_contact_id'; |
231 | $params['creator_id']['type'] = CRM_Utils_Type::T_INT; | |
b05e6d0d | 232 | $params['creator_id']['title'] = 'Case Created By'; |
ca11b9da | 233 | $params['start_date']['api.default'] = 'now'; |
cf8f0fff | 234 | $params['medium_id'] = [ |
16c0ec8d CW |
235 | 'name' => 'medium_id', |
236 | 'title' => 'Activity Medium', | |
d142432b | 237 | 'type' => CRM_Utils_Type::T_INT, |
cf8f0fff | 238 | ]; |
6a488035 TO |
239 | } |
240 | ||
11e09c59 | 241 | /** |
2fb1dd66 | 242 | * Adjust Metadata for Update action. |
6a488035 | 243 | * |
cf470720 | 244 | * @param array $params |
b081365f | 245 | * Array of parameters determined by getfields. |
6a488035 TO |
246 | */ |
247 | function _civicrm_api3_case_update_spec(&$params) { | |
248 | $params['id']['api.required'] = 1; | |
249 | } | |
250 | ||
11e09c59 | 251 | /** |
c1a920f1 | 252 | * Adjust Metadata for Delete action. |
6a488035 | 253 | * |
cf470720 | 254 | * @param array $params |
b081365f | 255 | * Array of parameters determined by getfields. |
6a488035 TO |
256 | */ |
257 | function _civicrm_api3_case_delete_spec(&$params) { | |
258 | $params['id']['api.required'] = 1; | |
259 | } | |
260 | ||
6a488035 | 261 | /** |
211e2fca | 262 | * Get details of a particular case, or search for cases, depending on params. |
6a488035 TO |
263 | * |
264 | * Please provide one (and only one) of the four get/search parameters: | |
265 | * | |
6c552737 TO |
266 | * @param array $params |
267 | * 'id' => if set, will get all available info about a case, including contacts and activities | |
6a488035 | 268 | * |
6c552737 TO |
269 | * // if no case_id provided, this function will use one of the following search parameters: |
270 | * 'client_id' => finds all cases with a specific client | |
271 | * 'activity_id' => returns the case containing a specific activity | |
272 | * 'contact_id' => finds all cases associated with a contact (in any role, not just client) | |
09f6c512 CW |
273 | * $params CRM_Utils_SQL_Select $sql |
274 | * Other apis wishing to wrap & extend this one can pass in a $sql object with extra clauses | |
6a488035 | 275 | * |
77b97be7 | 276 | * @throws API_Exception |
a6c01b45 | 277 | * @return array |
72b3a70c | 278 | * (get mode, case_id provided): Array with case details, case roles, case activity ids, (search mode, case_id not provided): Array of cases found |
6a488035 | 279 | */ |
09f6c512 | 280 | function civicrm_api3_case_get($params, $sql = NULL) { |
6a488035 | 281 | $options = _civicrm_api3_get_options_from_params($params); |
09f6c512 CW |
282 | if (!is_a($sql, 'CRM_Utils_SQL_Select')) { |
283 | $sql = CRM_Utils_SQL_Select::fragment(); | |
284 | } | |
48bdb3cd CW |
285 | |
286 | // Add clause to search by client | |
6a488035 | 287 | if (!empty($params['contact_id'])) { |
9808e205 CW |
288 | // Legacy support - this field historically supports a nonstandard format of array(1,2,3) as a synonym for array('IN' => array(1,2,3)) |
289 | if (is_array($params['contact_id'])) { | |
290 | $operator = CRM_Utils_Array::first(array_keys($params['contact_id'])); | |
291 | if (!in_array($operator, \CRM_Core_DAO::acceptedSQLOperators(), TRUE)) { | |
cf8f0fff | 292 | $params['contact_id'] = ['IN' => $params['contact_id']]; |
6a488035 TO |
293 | } |
294 | } | |
9808e205 | 295 | else { |
cf8f0fff | 296 | $params['contact_id'] = ['=' => $params['contact_id']]; |
9808e205 CW |
297 | } |
298 | $clause = CRM_Core_DAO::createSQLFilter('contact_id', $params['contact_id']); | |
299 | $sql->where("a.id IN (SELECT case_id FROM civicrm_case_contact WHERE $clause)"); | |
6a488035 TO |
300 | } |
301 | ||
242220e2 CW |
302 | // Order by case contact (primary client) |
303 | // Ex: "contact_id", "contact_id.display_name", "contact_id.sort_name DESC". | |
304 | if (!empty($options['sort']) && strpos($options['sort'], 'contact_id') !== FALSE) { | |
305 | $sort = explode(', ', $options['sort']); | |
306 | $contactSort = NULL; | |
4c6cc364 | 307 | foreach ($sort as $index => &$sortString) { |
242220e2 CW |
308 | if (strpos($sortString, 'contact_id') === 0) { |
309 | $contactSort = $sortString; | |
4c6cc364 | 310 | $sortString = '(1)'; |
242220e2 CW |
311 | // Get sort field and direction |
312 | list($sortField, $dir) = array_pad(explode(' ', $contactSort), 2, 'ASC'); | |
313 | list(, $sortField) = array_pad(explode('.', $sortField), 2, 'id'); | |
314 | // Validate inputs | |
315 | if (!array_key_exists($sortField, CRM_Contact_DAO_Contact::fieldKeys()) || ($dir != 'ASC' && $dir != 'DESC')) { | |
316 | throw new API_Exception("Unknown field specified for sort. Cannot order by '$contactSort'"); | |
317 | } | |
4c6cc364 | 318 | $sql->orderBy("case_contact.$sortField $dir", NULL, $index); |
242220e2 CW |
319 | } |
320 | } | |
321 | // Remove contact sort params so the basic_get function doesn't see them | |
322 | $params['options']['sort'] = implode(', ', $sort); | |
323 | unset($params['option_sort'], $params['option.sort'], $params['sort']); | |
324 | // Add necessary joins to the first case client | |
325 | if ($contactSort) { | |
326 | $sql->join('ccc', 'LEFT JOIN (SELECT * FROM civicrm_case_contact WHERE id IN (SELECT MIN(id) FROM civicrm_case_contact GROUP BY case_id)) AS ccc ON ccc.case_id = a.id'); | |
7a51786d | 327 | $sql->join('case_contact', 'LEFT JOIN civicrm_contact AS case_contact ON ccc.contact_id = case_contact.id AND case_contact.is_deleted <> 1'); |
242220e2 CW |
328 | } |
329 | } | |
330 | ||
48bdb3cd | 331 | // Add clause to search by activity |
6a488035 | 332 | if (!empty($params['activity_id'])) { |
48bdb3cd | 333 | if (!CRM_Utils_Rule::positiveInteger($params['activity_id'])) { |
784e85a1 | 334 | throw new API_Exception('Invalid parameter: activity_id. Must provide a numeric value.'); |
6a488035 | 335 | } |
48bdb3cd CW |
336 | $activityId = $params['activity_id']; |
337 | $originalId = CRM_Core_DAO::getFieldValue('CRM_Activity_BAO_Activity', $activityId, 'original_id'); | |
338 | if ($originalId) { | |
339 | $activityId .= ',' . $originalId; | |
6a488035 | 340 | } |
48bdb3cd CW |
341 | $sql |
342 | ->join('civicrm_case_activity', 'INNER JOIN civicrm_case_activity ON civicrm_case_activity.case_id = a.id') | |
343 | ->where("civicrm_case_activity.activity_id IN ($activityId)"); | |
6a488035 | 344 | } |
f21557af | 345 | |
9ef16723 CW |
346 | // Clause to search by tag |
347 | if (!empty($params['tag_id'])) { | |
cf8f0fff | 348 | $dummySpec = []; |
9ef16723 CW |
349 | _civicrm_api3_validate_integer($params, 'tag_id', $dummySpec, 'Case'); |
350 | if (!is_array($params['tag_id'])) { | |
cf8f0fff | 351 | $params['tag_id'] = ['=' => $params['tag_id']]; |
9ef16723 CW |
352 | } |
353 | $clause = \CRM_Core_DAO::createSQLFilter('tag_id', $params['tag_id']); | |
354 | if ($clause) { | |
cf8f0fff | 355 | $sql->where('a.id IN (SELECT entity_id FROM civicrm_entity_tag WHERE entity_table = "civicrm_case" AND !clause)', ['!clause' => $clause]); |
9ef16723 CW |
356 | } |
357 | } | |
358 | ||
cf8f0fff | 359 | $cases = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), ['sequential' => 0] + $params, TRUE, 'Case', $sql); |
a54ac083 | 360 | |
9ef16723 | 361 | if (empty($options['is_count']) && !empty($cases['values'])) { |
abd06efc | 362 | // For historic reasons we return these by default only when fetching a case by id |
10befc1f | 363 | if (!empty($params['id']) && is_numeric($params['id']) && empty($options['return'])) { |
cf8f0fff | 364 | $options['return'] = [ |
abd06efc CW |
365 | 'contacts' => 1, |
366 | 'activities' => 1, | |
367 | 'contact_id' => 1, | |
cf8f0fff | 368 | ]; |
abd06efc | 369 | } |
e01eccc0 | 370 | |
9ef16723 CW |
371 | _civicrm_api3_case_read($cases['values'], $options); |
372 | ||
373 | // We disabled sequential to keep the list indexed for case_read(). Now add it back. | |
374 | if (!empty($params['sequential'])) { | |
375 | $cases['values'] = array_values($cases['values']); | |
abd06efc | 376 | } |
35671d00 | 377 | } |
f21557af | 378 | |
9ef16723 | 379 | return $cases; |
6a488035 TO |
380 | } |
381 | ||
382 | /** | |
35823763 EM |
383 | * Deprecated API. |
384 | * | |
385 | * Use activity API instead. | |
9657ccf2 EM |
386 | * |
387 | * @param array $params | |
388 | * | |
389 | * @throws API_Exception | |
390 | * @return array | |
6a488035 TO |
391 | */ |
392 | function civicrm_api3_case_activity_create($params) { | |
a14e9d08 | 393 | require_once "api/v3/Activity.php"; |
cf8f0fff | 394 | return civicrm_api3_activity_create($params) + [ |
a14e9d08 | 395 | 'deprecated' => CRM_Utils_Array::value('activity_create', _civicrm_api3_case_deprecation()), |
cf8f0fff | 396 | ]; |
ae76ce5e CW |
397 | } |
398 | ||
399 | /** | |
400 | * Add a timeline to a case. | |
401 | * | |
402 | * @param array $params | |
403 | * | |
404 | * @throws API_Exception | |
405 | * @return array | |
406 | */ | |
407 | function civicrm_api3_case_addtimeline($params) { | |
408 | $caseType = CRM_Case_BAO_Case::getCaseType($params['case_id'], 'name'); | |
409 | $xmlProcessor = new CRM_Case_XMLProcessor_Process(); | |
cf8f0fff | 410 | $xmlProcessorParams = [ |
ae76ce5e CW |
411 | 'clientID' => CRM_Case_BAO_Case::getCaseClients($params['case_id']), |
412 | 'creatorID' => $params['creator_id'], | |
413 | 'standardTimeline' => 0, | |
414 | 'activity_date_time' => $params['activity_date_time'], | |
415 | 'caseID' => $params['case_id'], | |
416 | 'caseType' => $caseType, | |
417 | 'activitySetName' => $params['timeline'], | |
cf8f0fff | 418 | ]; |
ae76ce5e CW |
419 | $xmlProcessor->run($caseType, $xmlProcessorParams); |
420 | return civicrm_api3_create_success(); | |
421 | } | |
422 | ||
423 | /** | |
424 | * Adjust Metadata for addtimeline action. | |
425 | * | |
426 | * @param array $params | |
427 | * Array of parameters determined by getfields. | |
428 | */ | |
429 | function _civicrm_api3_case_addtimeline_spec(&$params) { | |
cf8f0fff | 430 | $params['case_id'] = [ |
ae76ce5e CW |
431 | 'title' => 'Case ID', |
432 | 'description' => 'Id of case to update', | |
433 | 'type' => CRM_Utils_Type::T_INT, | |
434 | 'api.required' => 1, | |
cf8f0fff CW |
435 | ]; |
436 | $params['timeline'] = [ | |
ae76ce5e CW |
437 | 'title' => 'Timeline', |
438 | 'description' => 'Name of activity set', | |
439 | 'type' => CRM_Utils_Type::T_STRING, | |
440 | 'api.required' => 1, | |
cf8f0fff CW |
441 | ]; |
442 | $params['activity_date_time'] = [ | |
ae76ce5e CW |
443 | 'api.default' => 'now', |
444 | 'title' => 'Activity date time', | |
445 | 'description' => 'Timeline start date', | |
446 | 'type' => CRM_Utils_Type::T_DATE, | |
cf8f0fff CW |
447 | ]; |
448 | $params['creator_id'] = [ | |
ae76ce5e CW |
449 | 'api.default' => 'user_contact_id', |
450 | 'title' => 'Activity creator', | |
451 | 'description' => 'Contact id of timeline creator', | |
452 | 'type' => CRM_Utils_Type::T_INT, | |
cf8f0fff | 453 | ]; |
a14e9d08 CW |
454 | } |
455 | ||
a6bc7218 CW |
456 | /** |
457 | * Merge 2 cases. | |
458 | * | |
459 | * @param array $params | |
460 | * | |
461 | * @throws API_Exception | |
462 | * @return array | |
463 | */ | |
464 | function civicrm_api3_case_merge($params) { | |
465 | $clients1 = CRM_Case_BAO_Case::getCaseClients($params['case_id_1']); | |
466 | $clients2 = CRM_Case_BAO_Case::getCaseClients($params['case_id_2']); | |
467 | CRM_Case_BAO_Case::mergeCases($clients1[0], $params['case_id_1'], $clients2[0], $params['case_id_2']); | |
468 | return civicrm_api3_create_success(); | |
469 | } | |
470 | ||
471 | /** | |
472 | * Adjust Metadata for merge action. | |
473 | * | |
474 | * @param array $params | |
475 | * Array of parameters determined by getfields. | |
476 | */ | |
477 | function _civicrm_api3_case_merge_spec(&$params) { | |
cf8f0fff | 478 | $params['case_id_1'] = [ |
a6bc7218 CW |
479 | 'title' => 'Case ID 1', |
480 | 'description' => 'Id of main case', | |
481 | 'type' => CRM_Utils_Type::T_INT, | |
482 | 'api.required' => 1, | |
cf8f0fff CW |
483 | ]; |
484 | $params['case_id_2'] = [ | |
a6bc7218 CW |
485 | 'title' => 'Case ID 2', |
486 | 'description' => 'Id of second case', | |
487 | 'type' => CRM_Utils_Type::T_INT, | |
488 | 'api.required' => 1, | |
cf8f0fff | 489 | ]; |
a6bc7218 CW |
490 | } |
491 | ||
a14e9d08 | 492 | /** |
35823763 EM |
493 | * Declare deprecated api functions. |
494 | * | |
a14e9d08 | 495 | * @deprecated api notice |
a6c01b45 | 496 | * @return array |
16b10e64 | 497 | * Array of deprecated actions |
a14e9d08 CW |
498 | */ |
499 | function _civicrm_api3_case_deprecation() { | |
cf8f0fff | 500 | return ['activity_create' => 'Case api "activity_create" action is deprecated. Use the activity api instead.']; |
6a488035 TO |
501 | } |
502 | ||
503 | /** | |
3755d879 | 504 | * @deprecated Update a specified case. Use civicrm_api3_case_create() instead. |
6a488035 | 505 | * |
6c552737 TO |
506 | * @param array $params |
507 | * //REQUIRED: | |
508 | * 'case_id' => int | |
6a488035 | 509 | * |
6c552737 TO |
510 | * //OPTIONAL |
511 | * 'status_id' => int | |
512 | * 'start_date' => str datestamp | |
513 | * 'contact_id' => int // case client | |
6a488035 | 514 | * |
784e85a1 | 515 | * @throws API_Exception |
a6c01b45 | 516 | * @return array |
72b3a70c | 517 | * api result array |
6a488035 TO |
518 | */ |
519 | function civicrm_api3_case_update($params) { | |
e720ce6e CB |
520 | if (!isset($params['case_id']) && isset($params['id'])) { |
521 | $params['case_id'] = $params['id']; | |
522 | } | |
523 | ||
6a488035 | 524 | //check parameters |
cf8f0fff | 525 | civicrm_api3_verify_mandatory($params, NULL, ['id']); |
6a488035 | 526 | |
784e85a1 | 527 | // return error if modifying creator id |
6a488035 | 528 | if (array_key_exists('creator_id', $params)) { |
784e85a1 | 529 | throw new API_Exception(ts('You cannot update creator id')); |
6a488035 TO |
530 | } |
531 | ||
cf8f0fff | 532 | $mCaseId = $origContactIds = []; |
6a488035 TO |
533 | |
534 | // get original contact id and creator id of case | |
535 | if (!empty($params['contact_id'])) { | |
c2e81506 | 536 | $origContactIds = CRM_Case_BAO_Case::retrieveContactIdsByCaseId($params['id']); |
f37c1b47 | 537 | $origContactId = CRM_Utils_Array::first($origContactIds); |
6a488035 TO |
538 | } |
539 | ||
540 | if (count($origContactIds) > 1) { | |
541 | // check valid orig contact id | |
542 | if (!empty($params['orig_contact_id']) && !in_array($params['orig_contact_id'], $origContactIds)) { | |
784e85a1 | 543 | throw new API_Exception('Invalid case contact id (orig_contact_id)'); |
6a488035 TO |
544 | } |
545 | elseif (empty($params['orig_contact_id'])) { | |
784e85a1 | 546 | throw new API_Exception('Case is linked with more than one contact id. Provide the required params orig_contact_id to be replaced'); |
6a488035 TO |
547 | } |
548 | $origContactId = $params['orig_contact_id']; | |
549 | } | |
550 | ||
551 | // check for same contact id for edit Client | |
552 | if (!empty($params['contact_id']) && !in_array($params['contact_id'], $origContactIds)) { | |
553 | $mCaseId = CRM_Case_BAO_Case::mergeCases($params['contact_id'], $params['case_id'], $origContactId, NULL, TRUE); | |
554 | } | |
555 | ||
556 | if (!empty($mCaseId[0])) { | |
c2e81506 | 557 | $params['id'] = $mCaseId[0]; |
6a488035 TO |
558 | } |
559 | ||
560 | $dao = new CRM_Case_BAO_Case(); | |
561 | $dao->id = $params['id']; | |
562 | ||
563 | $dao->copyValues($params); | |
564 | $dao->save(); | |
565 | ||
cf8f0fff | 566 | $case = []; |
6a488035 TO |
567 | _civicrm_api3_object_to_array($dao, $case); |
568 | ||
cf8f0fff | 569 | return civicrm_api3_create_success([$dao->id => $case], $params, 'Case', 'update', $dao); |
6a488035 TO |
570 | } |
571 | ||
572 | /** | |
573 | * Delete a specified case. | |
574 | * | |
6c552737 | 575 | * @param array $params |
37b8953e | 576 | * |
244bbdd8 | 577 | * @code |
6c552737 TO |
578 | * //REQUIRED: |
579 | * 'id' => int | |
6a488035 | 580 | * |
6c552737 TO |
581 | * //OPTIONAL |
582 | * 'move_to_trash' => bool (defaults to false) | |
244bbdd8 | 583 | * @endcode |
6a488035 | 584 | * |
77b97be7 | 585 | * @throws API_Exception |
8572e6de | 586 | * @return mixed |
6a488035 TO |
587 | */ |
588 | function civicrm_api3_case_delete($params) { | |
589 | //check parameters | |
cf8f0fff | 590 | civicrm_api3_verify_mandatory($params, NULL, ['id']); |
6a488035 TO |
591 | |
592 | if (CRM_Case_BAO_Case::deleteCase($params['id'], CRM_Utils_Array::value('move_to_trash', $params, FALSE))) { | |
244bbdd8 | 593 | return civicrm_api3_create_success($params, $params, 'Case', 'delete'); |
6a488035 TO |
594 | } |
595 | else { | |
784e85a1 | 596 | throw new API_Exception('Could not delete case.'); |
6a488035 TO |
597 | } |
598 | } | |
599 | ||
8572e6de CW |
600 | /** |
601 | * Case.restore API specification | |
602 | * | |
603 | * @param array $spec description of fields supported by this API call | |
604 | * @return void | |
605 | */ | |
606 | function _civicrm_api3_case_restore_spec(&$spec) { | |
cf8f0fff CW |
607 | $result = civicrm_api3('Case', 'getfields', ['api_action' => 'delete']); |
608 | $spec = ['id' => $result['values']['id']]; | |
8572e6de CW |
609 | } |
610 | ||
611 | /** | |
612 | * Restore a specified case from the trash. | |
613 | * | |
614 | * @param array $params | |
615 | * @throws API_Exception | |
616 | * @return mixed | |
617 | */ | |
618 | function civicrm_api3_case_restore($params) { | |
619 | if (CRM_Case_BAO_Case::restoreCase($params['id'])) { | |
620 | return civicrm_api3_create_success($params, $params, 'Case', 'restore'); | |
621 | } | |
622 | else { | |
623 | throw new API_Exception('Could not restore case.'); | |
624 | } | |
625 | } | |
626 | ||
6a488035 | 627 | /** |
9ef16723 | 628 | * Augment case results with extra data. |
6a488035 | 629 | * |
9ef16723 | 630 | * @param array $cases |
e9ff5391 | 631 | * @param array $options |
6a488035 | 632 | */ |
9ef16723 CW |
633 | function _civicrm_api3_case_read(&$cases, $options) { |
634 | foreach ($cases as &$case) { | |
635 | if (empty($options['return']) || !empty($options['return']['contact_id'])) { | |
636 | // Legacy support for client_id - TODO: in apiv4 remove 'client_id' | |
ea2aa8ff MW |
637 | // FIXME: Historically we return a 1-based array. Changing that risks breaking API clients that |
638 | // have been hardcoded to index "1", instead of the first array index (eg. using reset(), foreach etc) | |
639 | $case['client_id'] = $case['contact_id'] = CRM_Case_BAO_Case::retrieveContactIdsByCaseId($case['id'], NULL, 1); | |
9ef16723 CW |
640 | } |
641 | if (!empty($options['return']['contacts'])) { | |
642 | //get case contacts | |
643 | $contacts = CRM_Case_BAO_Case::getcontactNames($case['id']); | |
644 | $relations = CRM_Case_BAO_Case::getRelatedContacts($case['id']); | |
645 | $case['contacts'] = array_unique(array_merge($contacts, $relations), SORT_REGULAR); | |
646 | } | |
647 | if (!empty($options['return']['activities'])) { | |
648 | // add case activities array - we'll populate them in bulk below | |
cf8f0fff | 649 | $case['activities'] = []; |
9ef16723 CW |
650 | } |
651 | // Properly render this joined field | |
652 | if (!empty($options['return']['case_type_id.definition'])) { | |
653 | if (!empty($case['case_type_id.definition'])) { | |
654 | list($xml) = CRM_Utils_XML::parseString($case['case_type_id.definition']); | |
655 | } | |
656 | else { | |
657 | $caseTypeId = !empty($case['case_type_id']) ? $case['case_type_id'] : CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $case['id'], 'case_type_id'); | |
658 | $caseTypeName = !empty($case['case_type_id.name']) ? $case['case_type_id.name'] : CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'name'); | |
659 | $xml = CRM_Case_XMLRepository::singleton()->retrieve($caseTypeName); | |
660 | } | |
cf8f0fff | 661 | $case['case_type_id.definition'] = []; |
9ef16723 CW |
662 | if ($xml) { |
663 | $case['case_type_id.definition'] = CRM_Case_BAO_CaseType::convertXmlToDefinition($xml); | |
664 | } | |
665 | } | |
a54ac083 | 666 | } |
9ef16723 | 667 | // Bulk-load activities |
a54ac083 | 668 | if (!empty($options['return']['activities'])) { |
9ef16723 | 669 | $query = "SELECT case_id, activity_id FROM civicrm_case_activity WHERE case_id IN (%1)"; |
cf8f0fff | 670 | $params = [1 => [implode(',', array_keys($cases)), 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES]]; |
9ef16723 | 671 | $dao = CRM_Core_DAO::executeQuery($query, $params); |
a54ac083 | 672 | while ($dao->fetch()) { |
9ef16723 | 673 | $cases[$dao->case_id]['activities'][] = $dao->activity_id; |
6a488035 | 674 | } |
6a488035 | 675 | } |
9ef16723 | 676 | // Bulk-load tags. Supports joins onto the tag entity. |
cf8f0fff | 677 | $tagGet = ['tag_id', 'entity_id']; |
9ef16723 CW |
678 | foreach (array_keys($options['return']) as $key) { |
679 | if (strpos($key, 'tag_id.') === 0) { | |
680 | $tagGet[] = $key; | |
681 | $options['return']['tag_id'] = 1; | |
69f9c562 | 682 | } |
9ef16723 CW |
683 | } |
684 | if (!empty($options['return']['tag_id'])) { | |
cf8f0fff | 685 | $tags = civicrm_api3('EntityTag', 'get', [ |
9ef16723 | 686 | 'entity_table' => 'civicrm_case', |
cf8f0fff | 687 | 'entity_id' => ['IN' => array_keys($cases)], |
9ef16723 | 688 | 'return' => $tagGet, |
cf8f0fff CW |
689 | 'options' => ['limit' => 0], |
690 | ]); | |
9ef16723 CW |
691 | foreach ($tags['values'] as $tag) { |
692 | $key = (int) $tag['entity_id']; | |
693 | unset($tag['entity_id'], $tag['id']); | |
694 | $cases[$key]['tag_id'][$tag['tag_id']] = $tag; | |
69f9c562 CW |
695 | } |
696 | } | |
6a488035 TO |
697 | } |
698 | ||
699 | /** | |
61fe4988 | 700 | * Internal function to format create params for processing. |
9657ccf2 EM |
701 | * |
702 | * @param array $params | |
6a488035 TO |
703 | */ |
704 | function _civicrm_api3_case_format_params(&$params) { | |
2a3c0d28 | 705 | // Format/include custom params |
cf8f0fff | 706 | $values = []; |
2a3c0d28 MW |
707 | _civicrm_api3_custom_format_params($params, $values, 'Case'); |
708 | $params = array_merge($params, $values); | |
ebf4aeaa | 709 | |
ea2aa8ff MW |
710 | // A single or multiple contact_id (client_id) can be passed as a value or array. |
711 | // Convert single value to array here to simplify processing in later functions which expect an array. | |
712 | if (isset($params['contact_id'])) { | |
713 | if (!is_array($params['contact_id'])) { | |
cf8f0fff | 714 | $params['contact_id'] = [$params['contact_id']]; |
ea2aa8ff MW |
715 | } |
716 | } | |
717 | ||
718 | // DEPRECATED: case_id - use id parameter instead. | |
719 | if (!isset($params['id']) && isset($params['case_id'])) { | |
720 | $params['id'] = $params['case_id']; | |
721 | } | |
722 | ||
723 | // When creating a new case, either case_type_id or case_type must be specified. | |
2a3c0d28 | 724 | if (empty($params['case_type_id']) && empty($params['case_type'])) { |
ea2aa8ff | 725 | // If both case_type_id and case_type are empty we are updating a case so return here. |
2a3c0d28 MW |
726 | return; |
727 | } | |
728 | ||
ea2aa8ff | 729 | // We are creating a new case |
2a3c0d28 MW |
730 | // figure out case_type_id from case_type and vice-versa |
731 | $caseTypes = CRM_Case_PseudoConstant::caseType('name', FALSE); | |
732 | if (empty($params['case_type_id'])) { | |
733 | $params['case_type_id'] = array_search($params['case_type'], $caseTypes); | |
734 | ||
735 | // DEPRECATED: lookup by label for backward compatibility | |
736 | if (!$params['case_type_id']) { | |
737 | $caseTypeLabels = CRM_Case_PseudoConstant::caseType('title', FALSE); | |
738 | $params['case_type_id'] = array_search($params['case_type'], $caseTypeLabels); | |
61fe4988 | 739 | $params['case_type'] = $caseTypes[$params['case_type_id']]; |
3f25e694 | 740 | } |
6a488035 | 741 | } |
2a3c0d28 MW |
742 | elseif (empty($params['case_type'])) { |
743 | $params['case_type'] = $caseTypes[$params['case_type_id']]; | |
744 | } | |
6a488035 | 745 | } |
ff9340a4 | 746 | |
da4d8910 | 747 | |
ff9340a4 CW |
748 | /** |
749 | * It actually works a lot better to use the CaseContact api instead of the Case api | |
750 | * for entityRef fields so we can perform the necessary joins, | |
751 | * so we pass off getlist requests to the CaseContact api. | |
752 | * | |
753 | * @param array $params | |
754 | * @return mixed | |
755 | */ | |
756 | function civicrm_api3_case_getList($params) { | |
757 | require_once 'api/v3/Generic/Getlist.php'; | |
758 | require_once 'api/v3/CaseContact.php'; | |
09d55aa3 | 759 | //CRM:19956 - Assign case_id param if both id and case_id is passed to retrieve the case |
760 | if (!empty($params['id']) && !empty($params['params']) && !empty($params['params']['case_id'])) { | |
cf8f0fff | 761 | $params['params']['case_id'] = ['IN' => $params['id']]; |
09d55aa3 | 762 | unset($params['id']); |
763 | } | |
ff9340a4 CW |
764 | $params['id_field'] = 'case_id'; |
765 | $params['label_field'] = $params['search_field'] = 'contact_id.sort_name'; | |
cf8f0fff | 766 | $params['description_field'] = [ |
ff9340a4 CW |
767 | 'case_id', |
768 | 'case_id.case_type_id.title', | |
769 | 'case_id.subject', | |
770 | 'case_id.status_id', | |
771 | 'case_id.start_date', | |
cf8f0fff CW |
772 | ]; |
773 | $apiRequest = [ | |
09d55aa3 | 774 | 'version' => 3, |
ff9340a4 CW |
775 | 'entity' => 'CaseContact', |
776 | 'action' => 'getlist', | |
777 | 'params' => $params, | |
cf8f0fff | 778 | ]; |
ff9340a4 CW |
779 | return civicrm_api3_generic_getList($apiRequest); |
780 | } | |
781 | ||
782 | /** | |
783 | * Needed due to the above override | |
784 | * @param $params | |
785 | * @param $apiRequest | |
786 | */ | |
787 | function _civicrm_api3_case_getlist_spec(&$params, $apiRequest) { | |
788 | require_once 'api/v3/Generic/Getlist.php'; | |
789 | _civicrm_api3_generic_getlist_spec($params, $apiRequest); | |
790 | } |