Merge pull request #417 from colemanw/CRM-12339
[civicrm-core.git] / api / v2 / Case.php
1 <?php
2 // $Id$
3
4 /*
5 +--------------------------------------------------------------------+
6 | CiviCRM version 4.3 |
7 +--------------------------------------------------------------------+
8 | Copyright CiviCRM LLC (c) 2004-2013 |
9 +--------------------------------------------------------------------+
10 | This file is a part of CiviCRM. |
11 | |
12 | CiviCRM is free software; you can copy, modify, and distribute it |
13 | under the terms of the GNU Affero General Public License |
14 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
15 | |
16 | CiviCRM is distributed in the hope that it will be useful, but |
17 | WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
19 | See the GNU Affero General Public License for more details. |
20 | |
21 | You should have received a copy of the GNU Affero General Public |
22 | License and the CiviCRM Licensing Exception along |
23 | with this program; if not, contact CiviCRM LLC |
24 | at info[AT]civicrm[DOT]org. If you have questions about the |
25 | GNU Affero General Public License or the licensing of CiviCRM, |
26 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
27 +--------------------------------------------------------------------+
28 */
29
30 /**
31 * File for the CiviCRM APIv2 Case functions
32 * Developed by woolman.org
33 *
34 * @package CiviCRM_APIv2
35 * @subpackage API_Case
36 * @copyright CiviCRM LLC (c) 2004-2013
37 *
38 */
39
40 require_once 'api/v2/utils.php';
41 require_once 'CRM/Case/BAO/Case.php';
42 require_once 'CRM/Case/PseudoConstant.php';
43
44 /**
45 * Open a new case, add client and manager roles, and add standard timeline
46 *
47 * @param array(
48 //REQUIRED:
49 * 'case_type_id' => int OR 'case_type' => str (provide one or the other)
50 * 'contact_id' => int // case client
51 * 'creator_id' => int // case manager
52 * 'subject' => str
53 * 'medium_id' => int // see civicrm option values for possibilities
54 *
55 * //OPTIONAL
56 * 'status_id' => int // defaults to 1 "ongoing"
57 * 'location' => str
58 * 'start_date' => str datestamp // defaults to: date('YmdHis')
59 * 'duration' => int // in minutes
60 * 'details' => str // html format
61 *
62 * @return sucessfully opened case
63 *
64 * @access public
65 */
66 function civicrm_case_create(&$params) {
67 _civicrm_initialize();
68
69 //check parameters
70 $errors = _civicrm_case_check_params($params, 'create');
71
72 if ($errors) {
73
74 return $errors;
75 }
76
77 _civicrm_case_format_params($params, 'create');
78 // If format_params didn't find what it was looking for, return error
79 if (!$params['case_type_id']) {
80 return civicrm_create_error(ts('Invalid case_type. No such case type exists.'));
81 }
82 if (!$params['case_type']) {
83 return civicrm_create_error(ts('Invalid case_type_id. No such case type exists.'));
84 }
85
86 // format input with value separators
87 $sep = CRM_Core_DAO::VALUE_SEPARATOR;
88 $newParams = array(
89 'case_type_id' => $sep . $params['case_type_id'] . $sep,
90 'creator_id' => $params['creator_id'],
91 'status_id' => $params['status_id'],
92 'start_date' => $params['start_date'],
93 'subject' => $params['subject'],
94 );
95
96 $case = CRM_Case_BAO_Case::create($newParams);
97
98 if (!$case) {
99 return civicrm_create_error(ts('Case not created. Please check your input params.'));
100 }
101
102 // Add client role
103 $contactParams = array(
104 'case_id' => $case->id,
105 'contact_id' => $params['contact_id'],
106 );
107
108 CRM_Case_BAO_Case::addCaseToContact($contactParams);
109
110 // Initialize XML processor with $params
111 require_once 'CRM/Case/XMLProcessor/Process.php';
112 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
113 $xmlProcessorParams = array(
114 'clientID' => $params['contact_id'],
115 'creatorID' => $params['creator_id'],
116 'standardTimeline' => 1,
117 'activityTypeName' => 'Open Case',
118 'caseID' => $case->id,
119 'subject' => $params['subject'],
120 'location' => $params['location'],
121 'activity_date_time' => $params['start_date'],
122 'duration' => $params['duration'],
123 'medium_id' => $params['medium_id'],
124 'details' => $params['details'],
125 'custom' => array(),
126 );
127
128 // Do it! :-D
129 $xmlProcessor->run($params['case_type'], $xmlProcessorParams);
130
131 // status msg
132 $params['statusMsg'] = ts('Case opened successfully.');
133
134 // return case
135 $details = _civicrm_case_read($case->id);
136 return civicrm_create_success($details);
137 }
138
139 /**
140 * Get details of a particular case, or search for cases, depending on params
141 *
142 * Please provide one (and only one) of the four get/search parameters:
143 *
144 * @param array(
145 'case_id' => if set, will get all available info about a case, including contacts and activities
146 *
147 * // if no case_id provided, this function will use one of the following search parameters:
148 * 'client_id' => finds all cases with a specific client
149 * 'activity_id' => returns the case containing a specific activity
150 * 'contact_id' => finds all cases associated with a contact (in any role, not just client)
151 *
152 *
153 * @return (get mode, case_id provided): Array with case details, case roles, case activity ids, (search mode, case_id not provided): Array of cases found
154 * @access public
155 */
156 function civicrm_case_get(&$params) {
157 _civicrm_initialize();
158
159 //get mode
160 if ($caseId = $params['case_id']) {
161 //validate param
162 if (!is_numeric($caseId)) {
163 return civicrm_create_error(ts('Invalid parameter: case_id. Must provide a numeric value.'));
164 }
165
166 $case = _civicrm_case_read($caseId);
167
168 if ($case) {
169 //get case contacts
170 $contacts = CRM_Case_BAO_Case::getcontactNames($caseId);
171 $relations = CRM_Case_BAO_Case::getRelatedContacts($caseId);
172 $case['contacts'] = array_merge($contacts, $relations);
173
174 //get case activities
175
176 $query = "SELECT activity_id FROM civicrm_case_activity WHERE case_id = $caseId";
177 $dao = CRM_Core_DAO::executeQuery($query);
178
179 $case['activities'] = array();
180
181 while ($dao->fetch()) {
182 $case['activities'][] = $dao->activity_id;
183 }
184
185 return civicrm_create_success($case);
186 }
187 else {
188 return civicrm_create_success(array());
189 }
190 }
191
192 //search by client
193 if ($client = $params['client_id']) {
194
195 if (!is_numeric($client)) {
196 return civicrm_create_error(ts('Invalid parameter: client_id. Must provide a numeric value.'));
197 }
198
199 $ids = CRM_Case_BAO_Case::retrieveCaseIdsByContactId($client, TRUE);
200
201 if (empty($ids)) {
202
203 return civicrm_create_success(array());
204 }
205
206 $cases = array();
207
208 foreach ($ids as $id) {
209 $cases[$id] = _civicrm_case_read($id);
210 }
211 return civicrm_create_success($cases);
212 }
213
214 //search by activity
215 if ($act = $params['activity_id']) {
216
217 if (!is_numeric($act)) {
218 return civicrm_create_error(ts('Invalid parameter: activity_id. Must provide a numeric value.'));
219 }
220
221 $sql = "SELECT case_id FROM civicrm_case_activity WHERE activity_id = $act";
222
223 $caseId = CRM_Core_DAO::singleValueQuery($sql);
224
225 if (!$caseId) {
226 return civicrm_create_success(array());
227 }
228
229 $case = array($caseId => _civicrm_case_read($caseId));
230
231 return civicrm_create_success($case);
232 }
233
234 //search by contacts
235 if ($contact = $params['contact_id']) {
236 if (!is_numeric($contact)) {
237 return civicrm_create_error(ts('Invalid parameter: contact_id. Must provide a numeric value.'));
238 }
239
240 $sql = "
241 SELECT DISTINCT case_id
242 FROM civicrm_relationship
243 WHERE (contact_id_a = $contact
244 OR contact_id_b = $contact)
245 AND case_id IS NOT NULL";
246 $dao = CRM_Core_DAO::executeQuery($sql);
247
248 $cases = array();
249
250 while ($dao->fetch()) {
251 $cases[$dao->case_id] = _civicrm_case_read($dao->case_id);
252 }
253
254 return civicrm_create_success($cases);
255 }
256
257 return civicrm_create_error(ts('Missing required parameter. Must provide case_id, client_id, activity_id, or contact_id.'));
258 }
259
260 /**
261 * Create new activity for a case
262 *
263 * @param array(
264 //REQUIRED:
265 * 'case_id' => int
266 * 'activity_type_id' => int
267 * 'source_contact_id' => int
268 * 'status_id' => int
269 * 'medium_id' => int // see civicrm option values for possibilities
270 *
271 * //OPTIONAL
272 * 'subject' => str
273 * 'activity_date_time' => date string // defaults to: date('YmdHis')
274 * 'details => str
275 *
276 * @return activity id
277 *
278 * NOTE: For other case activity functions (update, delete, etc) use the Activity API
279 *
280 */
281 function civicrm_case_activity_create(&$params) {
282 _civicrm_initialize();
283
284 //check parameters
285 $errors = _civicrm_case_check_params($params, 'activity');
286
287 _civicrm_case_format_params($params, 'activity');
288
289 if ($errors) {
290 return $errors;
291 }
292 require_once 'CRM/Activity/BAO/Activity.php';
293
294 $activity = CRM_Activity_BAO_Activity::create($params);
295
296 $caseParams = array(
297 'activity_id' => $activity->id,
298 'case_id' => $params['case_id'],
299 );
300
301 CRM_Case_BAO_Case::processCaseActivity($caseParams);
302
303 return civicrm_create_success($activity->id);
304 }
305
306 /**
307 * Update a specified case.
308 *
309 * @param array(
310 //REQUIRED:
311 * 'case_id' => int
312 *
313 * //OPTIONAL
314 * 'status_id' => int
315 * 'start_date' => str datestamp
316 * 'contact_id' => int // case client
317 * 'creator_id' => int // case manager
318 *
319 * @return Updated case
320 *
321 * @access public
322 *
323 */
324 function civicrm_case_update(&$params) {
325 _civicrm_initialize();
326
327 $errors = array();
328 //check for various error and required conditions
329 $errors = _civicrm_case_check_params($params, 'update');
330
331 if (!empty($errors)) {
332 return $errors;
333 }
334
335 // return error if modifing creator id
336 if (array_key_exists('creator_id', $params)) {
337 return civicrm_create_error(ts('You have no provision to update creator id'));
338 }
339
340 $mCaseId = array();
341 $origContactIds = array();
342
343 // get original contact id and creator id of case
344 if ($params['contact_id']) {
345 $origContactIds = CRM_Case_BAO_Case::retrieveContactIdsByCaseId($params['case_id']);
346 $origContactId = $origContactIds[1];
347 }
348
349 if (count($origContactIds) > 1) {
350 // check valid orig contact id
351 if ($params['orig_contact_id'] && !in_array($params['orig_contact_id'], $origContactIds)) {
352 return civicrm_create_error(ts('Invalid case contact id (orig_contact_id)'));
353 }
354 elseif (!$params['orig_contact_id']) {
355 return civicrm_create_error(ts('Case is linked with more than one contact id. Provide the required params orig_contact_id to be replaced'));
356 }
357 $origContactId = $params['orig_contact_id'];
358 }
359
360 // check for same contact id for edit Client
361 if ($params['contact_id'] && !in_array($params['contact_id'], $origContactIds)) {
362 $mCaseId = CRM_Case_BAO_Case::mergeCases($params['contact_id'], $params['case_id'],
363 $origContactId, NULL, TRUE
364 );
365 }
366
367 if (CRM_Utils_Array::value('0', $mCaseId)) {
368 $params['case_id'] = $mCaseId[0];
369 }
370
371 $dao = new CRM_Case_BAO_Case();
372 $dao->id = $params['case_id'];
373
374 $dao->copyValues($params);
375 $dao->save();
376
377 $case = array();
378
379 _civicrm_object_to_array($dao, $case);
380
381 return civicrm_create_success($case);
382 }
383
384 /**
385 * Delete a specified case.
386 *
387 * @param array(
388 //REQUIRED:
389 * 'case_id' => int
390 *
391 * //OPTIONAL
392 * 'move_to_trash' => bool (defaults to false)
393 *
394 * @return boolean: true if success, else false
395 *
396 * @access public
397 */
398 function civicrm_case_delete(&$params) {
399 _civicrm_initialize();
400
401 //check parameters
402 $errors = _civicrm_case_check_params($params, 'delete');
403
404 if ($errors) {
405
406 return $errors;
407 }
408
409 if (CRM_Case_BAO_Case::deleteCase($params['case_id'], $params['move_to_trash'])) {
410 return civicrm_create_success(ts('Case Deleted'));
411 }
412 else {
413 return civicrm_create_error(ts('Could not delete case.'));
414 }
415 }
416
417 /***********************************/
418 /* */
419
420
421 /* INTERNAL FUNCTIONS */
422
423
424 /* */
425
426 /***********************************/
427
428 /**
429 * Internal function to retrieve a case.
430 *
431 * @param int $caseId
432 *
433 * @return array (reference) case object
434 *
435 */
436 function _civicrm_case_read($caseId) {
437
438 $dao = new CRM_Case_BAO_Case();
439 $dao->id = $caseId;
440 if ($dao->find(TRUE)) {
441 $case = array();
442 _civicrm_object_to_array($dao, $case);
443
444 //handle multi-value case type
445 $sep = CRM_Core_DAO::VALUE_SEPARATOR;
446 $case['case_type_id'] = trim(str_replace($sep, ',', $case['case_type_id']), ',');
447
448 return $case;
449 }
450 else {
451 return FALSE;
452 }
453 }
454
455 /**
456 * Internal function to format params for processing
457 */
458 function _civicrm_case_format_params(&$params, $mode) {
459 switch ($mode) {
460 case 'create':
461 // set defaults
462 if (!$params['status_id']) {
463 $params['status_id'] = 1;
464 }
465 if (!$params['start_date']) {
466 $params['start_date'] = date('YmdHis');
467 }
468
469 // figure out case type id, if not supplied
470 if (!$params['case_type_id']) {
471 $sql = "
472 SELECT ov.value
473 FROM civicrm_option_value ov
474 JOIN civicrm_option_group og ON og.id = ov.option_group_id
475 WHERE ov.label = %1 AND og.name = 'case_type'";
476
477 $values = array(1 => array($params['case_type'], 'String'));
478 $params['case_type_id'] = CRM_Core_DAO::singleValueQuery($sql, $values);
479 }
480 elseif (!$params['case_type']) {
481 // figure out case type, if not supplied
482 $sql = "
483 SELECT ov.name
484 FROM civicrm_option_value ov
485 JOIN civicrm_option_group og ON og.id = ov.option_group_id
486 WHERE ov.value = %1 AND og.name = 'case_type'";
487
488 $values = array(1 => array($params['case_type_id'], 'Integer'));
489 $params['case_type'] = CRM_Core_DAO::singleValueQuery($sql, $values);
490 }
491 break;
492
493 case 'activity':
494 //set defaults
495 if (!$params['activity_date_time']) {
496 $params['activity_date_time'] = date('YmdHis');
497 }
498 break;
499 }
500 }
501
502 /**
503 * Internal function to check for valid parameters
504 */
505 function _civicrm_case_check_params(&$params, $mode = NULL) {
506
507 // return error if we do not get any params
508 if (is_null($params) || !is_array($params) || empty($params)) {
509 return civicrm_create_error(ts('Invalid or missing input parameters. Must provide an associative array.'));
510 }
511
512 switch ($mode) {
513 case 'create':
514
515 if (!$params['case_type_id'] && !$params['case_type']) {
516
517 return civicrm_create_error(ts('Missing input parameters. Must provide case_type or case_type_id.'));
518 }
519
520 $required = array(
521 'contact_id' => 'num',
522 'status_id' => 'num',
523 'medium_id' => 'num',
524 'creator_id' => 'num',
525 'subject' => 'str',
526 );
527
528 if (!$params['case_type']) {
529
530 $required['case_type_id'] = 'num';
531 }
532 if (!$params['case_type_id']) {
533 $required['case_type'] = 'str';
534 }
535 break;
536
537 case 'activity':
538
539 $required = array(
540 'case_id' => 'num',
541 'activity_type_id' => 'num',
542 'source_contact_id' => 'num',
543 'status_id' => 'num',
544 'medium_id' => 'num',
545 );
546 break;
547
548 case 'update':
549 case 'delete':
550 $required = array('case_id' => 'num');
551 break;
552
553 default:
554 return NULL;
555 }
556
557 foreach ($required as $req => $type) {
558
559 if (!$params[$req]) {
560
561 return civicrm_create_error(ts('Missing required parameter: %1.', array(1 => $req)));
562 }
563
564 if ($type == 'num' && !is_numeric($params[$req])) {
565
566 return civicrm_create_error(ts('Invalid parameter: %1. Must provide a numeric value.', array(1 => $req)));
567 }
568
569 if ($type == 'str' && !is_string($params[$req])) {
570
571 return civicrm_create_error(ts('Invalid parameter: %1. Must provide a string.', array(1 => $req)));
572 }
573 }
574
575 $caseTypes = CRM_Case_PseudoConstant::caseType();
576
577 if (CRM_Utils_Array::value('case_type', $params) && !in_array($params['case_type'], $caseTypes)) {
578 return civicrm_create_error(ts('Invalid Case Type'));
579 }
580
581 if (CRM_Utils_Array::value('case_type_id', $params)) {
582 if (!array_key_exists($params['case_type_id'], $caseTypes)) {
583 return civicrm_create_error(ts('Invalid Case Type Id'));
584 }
585
586 // check case type miss match error
587 if (CRM_Utils_Array::value('case_type', $params) &&
588 $params['case_type_id'] != array_search($params['case_type'], $caseTypes)
589 ) {
590 return civicrm_create_error(ts('Case type and case type id mismatch'));
591 }
592
593 $sep = CRM_Case_BAO_Case::VALUE_SEPARATOR;
594 $params['case_type'] = $caseTypes[$params['case_type_id']];
595 $params['case_type_id'] = $sep . $params['case_type_id'] . $sep;
596 }
597
598 // check for valid status id
599 $caseStatusIds = CRM_Case_PseudoConstant::caseStatus();
600 if (CRM_Utils_Array::value('status_id', $params) &&
601 !array_key_exists($params['status_id'], $caseStatusIds) &&
602 $mode != 'activity'
603 ) {
604 return civicrm_create_error(ts('Invalid Case Status Id'));
605 }
606
607 // check for valid medium id
608 $encounterMedium = CRM_Core_OptionGroup::values('encounter_medium');
609 if (CRM_Utils_Array::value('medium_id', $params) &&
610 !array_key_exists($params['medium_id'], $encounterMedium)
611 ) {
612 return civicrm_create_error(ts('Invalid Case Medium Id'));
613 }
614
615 $contactIds = array('creator' => CRM_Utils_Array::value('creator_id', $params),
616 'contact' => CRM_Utils_Array::value('contact_id', $params),
617 );
618 foreach ($contactIds as $key => $value) {
619 if ($value &&
620 !CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'id')
621 ) {
622 return civicrm_create_error(ts('Invalid %1 Id', array(1 => ucfirst($key))));
623 }
624 }
625 }
626