Merge pull request #12949 from eileenmcnaughton/activity_extract
[civicrm-core.git] / tests / phpunit / api / v3 / CaseTest.php
1 <?php
2 /**
3 * @file
4 * File for the TestCase class
5 *
6 * (PHP 5)
7 *
8 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
9 * @copyright Copyright CiviCRM LLC (C) 2009
10 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html
11 * GNU Affero General Public License version 3
12 * @version $Id: ActivityTest.php 31254 2010-12-15 10:09:29Z eileen $
13 * @package CiviCRM
14 *
15 * This file is part of CiviCRM
16 *
17 * CiviCRM is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Affero General Public License
19 * as published by the Free Software Foundation; either version 3 of
20 * the License, or (at your option) any later version.
21 *
22 * CiviCRM is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Affero General Public License for more details.
26 *
27 * You should have received a copy of the GNU Affero General Public
28 * License along with this program. If not, see
29 * <http://www.gnu.org/licenses/>.
30 */
31
32 /**
33 * Test APIv3 civicrm_case_* functions
34 *
35 * @package CiviCRM_APIv3
36 * @group headless
37 */
38 class api_v3_CaseTest extends CiviCaseTestCase {
39 protected $_params;
40 protected $_entity;
41 protected $_apiversion = 3;
42 protected $followup_activity_type_value;
43 /**
44 * Activity ID of created case.
45 *
46 * @var int
47 */
48 protected $_caseActivityId;
49
50 /**
51 * @var \Civi\Core\SettingsStack
52 */
53 protected $settingsStack;
54
55 /**
56 * Test setup for every test.
57 *
58 * Connect to the database, truncate the tables that will be used
59 * and redirect stdin to a temporary file.
60 */
61 public function setUp() {
62 $this->_entity = 'case';
63
64 parent::setUp();
65
66 $activityTypes = $this->callAPISuccess('option_value', 'get', array(
67 'option_group_id' => 2,
68 'name' => 'Follow Up',
69 'label' => 'Follow Up',
70 'sequential' => 1,
71 ));
72 $this->followup_activity_type_value = $activityTypes['values'][0]['value'];
73
74 $this->_params = array(
75 'case_type_id' => $this->caseTypeId,
76 'subject' => 'Test case',
77 'contact_id' => 17,
78 );
79
80 $this->settingsStack = new \Civi\Core\SettingsStack();
81 }
82
83 public function tearDown() {
84 $this->settingsStack->popAll();
85 parent::tearDown();
86 }
87
88 /**
89 * Check with empty array.
90 */
91 public function testCaseCreateEmpty() {
92 $this->callAPIFailure('case', 'create', array());
93 }
94
95 /**
96 * Check if required fields are not passed.
97 */
98 public function testCaseCreateWithoutRequired() {
99 $params = array(
100 'subject' => 'this case should fail',
101 'case_type_id' => 1,
102 );
103
104 $this->callAPIFailure('case', 'create', $params);
105 }
106
107 /**
108 * Test Getlist with id and case_id
109 */
110 public function testCaseGetListById() {
111 $params = $this->_params;
112 $params['contact_id'] = $this->individualCreate();
113
114 //Create 3 sample Cases.
115 $case1 = $this->callAPISuccess('case', 'create', $params);
116 $params['subject'] = 'Test Case 2';
117 $case2 = $this->callAPISuccess('case', 'create', $params);
118 $params['subject'] = 'Test Case 3';
119 $this->callAPISuccess('case', 'create', $params);
120
121 $getParams = array(
122 'id' => array($case1['id']),
123 'extra' => array('contact_id'),
124 'params' => array(
125 'version' => 3,
126 'case_id' => array('!=' => $case2['id']),
127 'case_id.is_deleted' => 0,
128 'case_id.status_id' => array('!=' => "Closed"),
129 'case_id.end_date' => array('IS NULL' => 1),
130 ),
131 );
132 $result = $this->callAPISuccess('case', 'getlist', $getParams);
133
134 //Only 1 case should be returned.
135 $this->assertEquals(count($result['values']), 1);
136 $this->assertEquals($result['values'][0]['id'], $case1['id']);
137 }
138
139 /**
140 * Test create function with valid parameters.
141 */
142 public function testCaseCreate() {
143 $params = $this->_params;
144 // Test using label instead of value.
145 unset($params['case_type_id']);
146 $params['case_type'] = $this->caseType;
147 $result = $this->callAPIAndDocument('case', 'create', $params, __FUNCTION__, __FILE__);
148 $id = $result['id'];
149
150 // Check result
151 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
152 $this->assertEquals($result['values'][$id]['id'], $id);
153 $this->assertEquals($result['values'][$id]['case_type_id'], $this->caseTypeId);
154 $this->assertEquals($result['values'][$id]['subject'], $params['subject']);
155 }
156
157 /**
158 * Test create function with resolved status.
159 */
160 public function testCaseCreateWithResolvedStatus() {
161 $params = $this->_params;
162 // Test using label instead of value.
163 unset($params['case_type_id']);
164 $params['case_type'] = $this->caseType;
165 $params['status_id'] = 'Closed';
166 $result = $this->callAPISuccess('case', 'create', $params);
167 $id = $result['id'];
168
169 // Check result
170 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
171 $this->assertEquals($result['values'][$id]['id'], $id);
172 $this->assertEquals($result['values'][$id]['case_type_id'], $this->caseTypeId);
173 $this->assertEquals($result['values'][$id]['subject'], $params['subject']);
174 $this->assertEquals($result['values'][$id]['end_date'], date('Y-m-d'));
175
176 //Check all relationship end dates are set to case end date.
177 $relationships = $this->callAPISuccess('Relationship', 'get', array(
178 'sequential' => 1,
179 'case_id' => $id,
180 ));
181 foreach ($relationships['values'] as $key => $values) {
182 $this->assertEquals($values['end_date'], date('Y-m-d'));
183 }
184
185 //Verify there are no active relationships.
186 $activeCaseRelationships = CRM_Case_BAO_Case::getCaseRoles($result['values'][$id]['client_id'][1], $id);
187 $this->assertEquals(count($activeCaseRelationships), 0, "Checking for empty array");
188
189 //Check if getCaseRoles() is able to return inactive relationships.
190 $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($result['values'][$id]['client_id'][1], $id, NULL, FALSE);
191 $this->assertEquals(count($caseRelationships), 1);
192 }
193
194 /**
195 * Test case create with valid parameters and custom data.
196 */
197 public function testCaseCreateCustom() {
198 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
199 $params = $this->_params;
200 $params['custom_' . $ids['custom_field_id']] = "custom string";
201 $result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__);
202 $result = $this->callAPISuccess($this->_entity, 'get', array(
203 'return.custom_' . $ids['custom_field_id'] => 1,
204 'id' => $result['id'],
205 ));
206 $this->assertEquals("custom string", $result['values'][$result['id']]['custom_' . $ids['custom_field_id']]);
207
208 $this->customFieldDelete($ids['custom_field_id']);
209 $this->customGroupDelete($ids['custom_group_id']);
210 }
211
212 /**
213 * Test update (create with id) function with valid parameters.
214 */
215 public function testCaseUpdate() {
216 $params = $this->_params;
217 // Test using name instead of value
218 unset($params['case_type_id']);
219 $params['case_type'] = $this->caseType;
220 $result = $this->callAPISuccess('case', 'create', $params);
221 $id = $result['id'];
222 $case = $this->callAPISuccess('case', 'getsingle', array('id' => $id));
223
224 // Update Case.
225 $params = array('id' => $id);
226 $params['subject'] = $case['subject'] = 'Something Else';
227 $this->callAPISuccess('case', 'create', $params);
228
229 // Verify that updated case is equal to the original with new subject.
230 $result = $this->callAPISuccessGetSingle('Case', array('case_id' => $id));
231 // Modification dates are likely to differ by 0-2 sec. Check manually.
232 $this->assertGreaterThanOrEqual($case['modified_date'], $result['modified_date']);
233 unset($result['modified_date'], $case['modified_date']);
234 // Everything else should be identical.
235 $this->assertAPIArrayComparison($result, $case);
236 }
237
238 /**
239 * Test update (create with id) function with valid parameters.
240 */
241 public function testCaseUpdateWithExistingCaseContact() {
242 $params = $this->_params;
243 // Test using name instead of value
244 unset($params['case_type_id']);
245 $params['case_type'] = $this->caseType;
246 $result = $this->callAPISuccess('case', 'create', $params);
247 $id = $result['id'];
248 $case = $this->callAPISuccess('case', 'getsingle', array('id' => $id));
249
250 // Update Case, we specify existing case ID and existing contact ID to verify that CaseContact.create is not called
251 $params = $this->_params;
252 $params['id'] = $id;
253 $this->callAPISuccess('case', 'create', $params);
254
255 // Verify that updated case is equal to the original with new subject.
256 $result = $this->callAPISuccessGetSingle('Case', array('case_id' => $id));
257 // Modification dates are likely to differ by 0-2 sec. Check manually.
258 $this->assertGreaterThanOrEqual($case['modified_date'], $result['modified_date']);
259 unset($result['modified_date'], $case['modified_date']);
260 // Everything else should be identical.
261 $this->assertAPIArrayComparison($result, $case);
262 }
263
264 /**
265 * Test case update with custom data
266 */
267 public function testCaseUpdateCustom() {
268 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
269 $params = $this->_params;
270
271 // Create a case with custom data
272 $params['custom_' . $ids['custom_field_id']] = 'custom string';
273 $result = $this->callAPISuccess($this->_entity, 'create', $params);
274
275 $caseId = $result['id'];
276 $result = $this->callAPISuccess($this->_entity, 'get', array(
277 'return.custom_' . $ids['custom_field_id'] => 1,
278 'version' => 3,
279 'id' => $result['id'],
280 ));
281 $this->assertEquals("custom string", $result['values'][$result['id']]['custom_' . $ids['custom_field_id']]);
282 $fields = $this->callAPISuccess($this->_entity, 'getfields', array('version' => $this->_apiversion));
283 $this->assertTrue(is_array($fields['values']['custom_' . $ids['custom_field_id']]));
284
285 // Update the activity with custom data.
286 $params = array(
287 'id' => $caseId,
288 'custom_' . $ids['custom_field_id'] => 'Updated my test data',
289 'version' => $this->_apiversion,
290 );
291 $result = $this->callAPISuccess($this->_entity, 'create', $params);
292
293 $result = $this->callAPISuccess($this->_entity, 'get', array(
294 'return.custom_' . $ids['custom_field_id'] => 1,
295 'version' => 3,
296 'id' => $result['id'],
297 ));
298 $this->assertEquals("Updated my test data", $result['values'][$result['id']]['custom_' . $ids['custom_field_id']]);
299 }
300
301 /**
302 * Test delete function with valid parameters.
303 */
304 public function testCaseDelete() {
305 // Create Case
306 $result = $this->callAPISuccess('case', 'create', $this->_params);
307
308 // Move Case to Trash
309 $id = $result['id'];
310 $this->callAPISuccess('case', 'delete', array('id' => $id, 'move_to_trash' => 1));
311
312 // Check result - also check that 'case_id' works as well as 'id'
313 $result = $this->callAPISuccess('case', 'get', array('case_id' => $id));
314 $this->assertEquals(1, $result['values'][$id]['is_deleted']);
315
316 // Restore Case from Trash
317 $this->callAPISuccess('case', 'restore', array('id' => $id));
318
319 // Check result
320 $result = $this->callAPISuccess('case', 'get', array('case_id' => $id));
321 $this->assertEquals(0, $result['values'][$id]['is_deleted']);
322
323 // Delete Case Permanently
324 $this->callAPISuccess('case', 'delete', array('case_id' => $id));
325
326 // Check result - case should no longer exist
327 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
328 $this->assertEquals(0, $result['count']);
329 }
330
331 /**
332 * Test Case role relationship is correctly created
333 * for contacts.
334 */
335 public function testCaseRoleRelationships() {
336 // Create Case
337 $case = $this->callAPISuccess('case', 'create', $this->_params);
338 $relType = $this->relationshipTypeCreate(array('name_a_b' => 'Test AB', 'name_b_a' => 'Test BA', 'contact_type_b' => 'Individual'));
339 $relContact = $this->individualCreate(array('first_name' => 'First', 'last_name' => 'Last'));
340
341 $_REQUEST = array(
342 'rel_type' => "{$relType}_b_a",
343 'rel_contact' => $relContact,
344 'case_id' => $case['id'],
345 'is_unit_test' => TRUE,
346 );
347 $ret = CRM_Contact_Page_AJAX::relationship();
348 $this->assertEquals(0, $ret['is_error']);
349 //Check if relationship exist for the case.
350 $relationship = $this->callAPISuccess('Relationship', 'get', array(
351 'sequential' => 1,
352 'relationship_type_id' => $relType,
353 'case_id' => $case['id'],
354 ));
355 $this->assertEquals($relContact, $relationship['values'][0]['contact_id_a']);
356 $this->assertEquals($this->_params['contact_id'], $relationship['values'][0]['contact_id_b']);
357
358 //Check if activity is assigned to correct contact.
359 $activity = $this->callAPISuccess('Activity', 'get', array(
360 'subject' => 'Test BA : Mr. First Last II',
361 ));
362 $this->callAPISuccess('ActivityContact', 'get', array(
363 'contact_id' => $relContact,
364 'activity_id' => $activity['id'],
365 ));
366 }
367
368 /**
369 * Test get function based on activity.
370 */
371 public function testCaseGetByActivity() {
372 // Create Case
373 $result = $this->callAPISuccess('case', 'create', $this->_params);
374 $id = $result['id'];
375
376 // Check result - we should get a list of activity ids
377 $result = $this->callAPISuccess('case', 'get', array('id' => $id, 'return' => 'activities'));
378 $case = $result['values'][$id];
379 $activity = $case['activities'][0];
380
381 // Fetch case based on an activity id
382 $result = $this->callAPISuccess('case', 'get', array(
383 'activity_id' => $activity,
384 'return' => 'activities',
385 ));
386 $this->assertEquals(FALSE, empty($result['values'][$id]));
387 $this->assertEquals($result['values'][$id], $case);
388 }
389
390 /**
391 * Test get function based on contact id.
392 */
393 public function testCaseGetByContact() {
394 // Create Case
395 $result = $this->callAPISuccess('case', 'create', $this->_params);
396 $id = $result['id'];
397
398 // Store result for later
399 $case = $this->callAPISuccessGetSingle('case', array('id' => $id, 'return' => array('activities', 'contacts')));
400
401 // Fetch case based on client contact id
402 $result = $this->callAPISuccess('case', 'get', array(
403 'client_id' => $this->_params['contact_id'],
404 'return' => array('activities', 'contacts'),
405 ));
406 $this->assertAPIArrayComparison($result['values'][$id], $case);
407 }
408
409 /**
410 * Test get function based on subject.
411 */
412 public function testCaseGetBySubject() {
413 // Create Case
414 $result = $this->callAPISuccess('case', 'create', $this->_params);
415 $id = $result['id'];
416
417 // Store result for later
418 $case = $this->callAPISuccessGetSingle('Case', array('id' => $id, 'return' => 'subject'));
419
420 // Fetch case based on client contact id
421 $result = $this->callAPISuccess('case', 'get', array(
422 'subject' => $this->_params['subject'],
423 'return' => array('subject'),
424 ));
425 $this->assertAPIArrayComparison($result['values'][$id], $case);
426 }
427
428 /**
429 * Test get function based on wrong subject.
430 */
431 public function testCaseGetByWrongSubject() {
432 $this->callAPISuccess('case', 'create', $this->_params);
433
434 // Append 'wrong' to subject so that it is no longer the same.
435 $result = $this->callAPISuccess('case', 'get', array(
436 'subject' => $this->_params['subject'] . 'wrong',
437 'return' => array('activities', 'contacts'),
438 ));
439 $this->assertEquals(0, $result['count']);
440 }
441
442 /**
443 * Test get function with no criteria.
444 */
445 public function testCaseGetNoCriteria() {
446 $result = $this->callAPISuccess('case', 'create', $this->_params);
447 $id = $result['id'];
448
449 // Store result for later
450 $case = $this->callAPISuccessGetSingle('Case', array('id' => $id, 'return' => 'contact_id'));
451
452 $result = $this->callAPISuccess('case', 'get', array('limit' => 0, 'return' => array('contact_id')));
453 $this->assertAPIArrayComparison($result['values'][$id], $case);
454 }
455
456 /**
457 * Test activity api create for case activities.
458 */
459 public function testCaseActivityCreate() {
460 $params = $this->_params;
461 $case = $this->callAPISuccess('case', 'create', $params);
462 $params = array(
463 'case_id' => $case['id'],
464 // follow up
465 'activity_type_id' => $this->followup_activity_type_value,
466 'subject' => 'Test followup 123',
467 'source_contact_id' => $this->_loggedInUser,
468 'target_contact_id' => $this->_params['contact_id'],
469 );
470 $result = $this->callAPISuccess('activity', 'create', $params);
471 $this->assertEquals($result['values'][$result['id']]['activity_type_id'], $params['activity_type_id']);
472
473 // might need this for other tests that piggyback on this one
474 $this->_caseActivityId = $result['values'][$result['id']]['id'];
475
476 // Check other DB tables populated properly - is there a better way to do this? assertDBState() requires that we know the id already.
477 $dao = new CRM_Case_DAO_CaseActivity();
478 $dao->case_id = $case['id'];
479 $dao->activity_id = $this->_caseActivityId;
480 $this->assertEquals($dao->find(), 1, 'case_activity table not populated correctly');
481
482 $dao = new CRM_Activity_DAO_ActivityContact();
483 $dao->activity_id = $this->_caseActivityId;
484 $dao->contact_id = $this->_params['contact_id'];
485 $dao->record_type_id = 3;
486 $this->assertEquals($dao->find(), 1, 'activity_contact table not populated correctly');
487
488 // Check that fetching an activity by case id works, as well as returning case_id
489 $result = $this->callAPISuccessGetSingle('Activity', array(
490 'case_id' => $case['id'],
491 'activity_type_id' => $this->followup_activity_type_value,
492 'subject' => 'Test followup 123',
493 'return' => array('case_id'),
494 ));
495 $this->assertContains($case['id'], $result['case_id']);
496 }
497
498 /**
499 * Test activity api update for case activities.
500 */
501 public function testCaseActivityUpdate_Tracked() {
502 $this->settingsStack->push('civicaseActivityRevisions', TRUE);
503
504 // Need to create the case and activity before we can update it
505 $this->testCaseActivityCreate();
506
507 $params = array(
508 'activity_id' => $this->_caseActivityId,
509 'case_id' => 1,
510 'activity_type_id' => 14,
511 'source_contact_id' => $this->_loggedInUser,
512 'subject' => 'New subject',
513 );
514 $result = $this->callAPISuccess('activity', 'create', $params);
515
516 $this->assertEquals($result['values'][$result['id']]['subject'], $params['subject']);
517
518 // id should be one greater, since this is a new revision
519 $this->assertEquals($result['values'][$result['id']]['id'], $this->_caseActivityId + 1);
520 $this->assertEquals($result['values'][$result['id']]['original_id'], $this->_caseActivityId);
521
522 // Check revision is as expected
523 $revParams = array(
524 'activity_id' => $this->_caseActivityId,
525 );
526 $revActivity = $this->callAPISuccess('activity', 'get', $revParams);
527 $this->assertEquals($revActivity['values'][$this->_caseActivityId]['is_current_revision'],
528 0);
529 $this->assertEquals($revActivity['values'][$this->_caseActivityId]['is_deleted'],
530 0
531 );
532 }
533
534 /**
535 * If you disable `civicaseActivityRevisions`, then editing an activity
536 * will *not* create or change IDs.
537 */
538 public function testCaseActivityUpdate_Untracked() {
539 $this->settingsStack->push('civicaseActivityRevisions', FALSE);
540
541 // Need to create the case and activity before we can update it
542 $this->testCaseActivityCreate();
543
544 $oldIDs = CRM_Utils_SQL_Select::from('civicrm_activity')
545 ->select('id, original_id, is_current_revision')
546 ->orderBy('id')
547 ->execute()->fetchAll();
548
549 $params = array(
550 'activity_id' => $this->_caseActivityId,
551 'case_id' => 1,
552 'activity_type_id' => 14,
553 'source_contact_id' => $this->_loggedInUser,
554 'subject' => 'New subject',
555 );
556 $result = $this->callAPISuccess('activity', 'create', $params);
557 $this->assertEquals($result['values'][$result['id']]['subject'], $params['subject']);
558
559 // id should not change because we've opted out.
560 $this->assertEquals($this->_caseActivityId, $result['values'][$result['id']]['id']);
561 $this->assertEmpty($result['values'][$result['id']]['original_id']);
562
563 $newIDs = CRM_Utils_SQL_Select::from('civicrm_activity')
564 ->select('id, original_id, is_current_revision')
565 ->orderBy('id')
566 ->execute()->fetchAll();
567 $this->assertEquals($oldIDs, $newIDs);
568 }
569
570 public function testCaseActivityUpdateCustom() {
571 $this->settingsStack->push('civicaseActivityRevisions', TRUE);
572
573 // Create a case first
574 $result = $this->callAPISuccess('case', 'create', $this->_params);
575
576 // Create custom field group
577 // Note the second parameter is Activity on purpose, not Case.
578 $custom_ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ActivityTest.php');
579
580 // create activity
581 $params = array(
582 'case_id' => $result['id'],
583 // follow up
584 'activity_type_id' => 14,
585 'subject' => 'Test followup',
586 'source_contact_id' => $this->_loggedInUser,
587 'target_contact_id' => $this->_params['contact_id'],
588 'custom_' . $custom_ids['custom_field_id'] => "custom string",
589 );
590 $result = $this->callAPISuccess('activity', 'create', $params);
591
592 $aid = $result['values'][$result['id']]['id'];
593
594 // Update activity
595 $params = array(
596 'activity_id' => $aid,
597 'case_id' => 1,
598 'activity_type_id' => 14,
599 'source_contact_id' => $this->_loggedInUser,
600 'subject' => 'New subject',
601 );
602 $this->callAPISuccess('activity', 'create', $params);
603
604 // Retrieve revision and check custom fields got copied.
605 $revParams = array(
606 'activity_id' => $aid + 1,
607 'return.custom_' . $custom_ids['custom_field_id'] => 1,
608 );
609 $revAct = $this->callAPISuccess('activity', 'get', $revParams);
610
611 $this->assertEquals($revAct['values'][$aid + 1]['custom_' . $custom_ids['custom_field_id']], "custom string",
612 "Error message: " . CRM_Utils_Array::value('error_message', $revAct));
613
614 $this->customFieldDelete($custom_ids['custom_field_id']);
615 $this->customGroupDelete($custom_ids['custom_group_id']);
616 }
617
618 public function testCaseGetByStatus() {
619 // Create 2 cases with different status ids.
620 $case1 = $this->callAPISuccess('Case', 'create', array(
621 'contact_id' => 17,
622 'subject' => "Test case 1",
623 'case_type_id' => $this->caseTypeId,
624 'status_id' => "Open",
625 'sequential' => 1,
626 ));
627 $this->callAPISuccess('Case', 'create', array(
628 'contact_id' => 17,
629 'subject' => "Test case 2",
630 'case_type_id' => $this->caseTypeId,
631 'status_id' => "Urgent",
632 'sequential' => 1,
633 ));
634 $result = $this->callAPISuccessGetSingle('Case', array(
635 'sequential' => 1,
636 'contact_id' => 17,
637 'status_id' => "Open",
638 ));
639 $this->assertEquals($case1['id'], $result['id']);
640 }
641
642 public function testCaseGetWithRoles() {
643 $case1 = $this->callAPISuccess('Case', 'create', array(
644 'contact_id' => 17,
645 'subject' => "Test case with roles",
646 'case_type_id' => $this->caseTypeId,
647 'status_id' => "Open",
648 ));
649 $result = $this->callAPISuccessGetSingle('Case', array(
650 'id' => $case1['id'],
651 'status_id' => "Open",
652 'return' => array('contacts'),
653 ));
654 foreach ($result['contacts'] as $contact) {
655 if ($contact['role'] == 'Client') {
656 $this->assertEquals(17, $contact['contact_id']);
657 }
658 elseif ($contact['role'] == 'Homeless Services Coordinator') {
659 $this->assertEquals(1, $contact['creator']);
660 $this->assertEquals(1, $contact['manager']);
661 }
662 }
663 }
664
665 public function testCaseGetWithDefinition() {
666 $case1 = $this->callAPISuccess('Case', 'create', array(
667 'contact_id' => 17,
668 'subject' => "Test case with definition",
669 'case_type_id' => $this->caseTypeId,
670 'status_id' => "Open",
671 ));
672 $result1 = $this->callAPISuccessGetSingle('Case', array(
673 'id' => $case1['id'],
674 'status_id' => "Open",
675 'return' => array('case_type_id.definition'),
676 ));
677 $result2 = $this->callAPISuccessGetSingle('Case', array(
678 'id' => $case1['id'],
679 'status_id' => "Open",
680 'return' => array('case_type_id', 'case_type_id.definition'),
681 ));
682 $this->assertEquals($result1['case_type_id.definition'], $result2['case_type_id.definition']);
683 $def = $result1['case_type_id.definition'];
684 $this->assertEquals(array('name' => 'Open Case', 'max_instances' => 1), $def['activityTypes'][0]);
685 $this->assertNotEmpty($def['activitySets'][0]['activityTypes']);
686 $this->assertNotEmpty($def['caseRoles'][0]['manager']);
687 $this->assertNotEmpty($def['caseRoles'][0]['creator']);
688 }
689
690 public function testCaseGetTags() {
691 $case1 = $this->callAPISuccess('Case', 'create', array(
692 'contact_id' => 17,
693 'subject' => "Test case with tags",
694 'case_type_id' => $this->caseTypeId,
695 'status_id' => "Open",
696 ));
697 $tag1 = $this->tagCreate(array(
698 'name' => 'CaseTag1',
699 'used_for' => 'civicrm_case',
700 ));
701 $tag2 = $this->tagCreate(array(
702 'name' => 'CaseTag2',
703 'used_for' => 'civicrm_case',
704 ));
705 $this->callAPISuccess('EntityTag', 'create', array(
706 'entity_table' => 'civicrm_case',
707 'entity_id' => $case1['id'],
708 'tag_id' => $tag1['id'],
709 ));
710 $this->callAPIFailure('Case', 'getsingle', array(
711 'tag_id' => $tag2['id'],
712 ));
713 $result = $this->callAPISuccessGetSingle('Case', array(
714 'tag_id' => $tag1['id'],
715 'return' => 'tag_id.name',
716 ));
717 $this->assertEquals('CaseTag1', $result['tag_id'][$tag1['id']]['tag_id.name']);
718 }
719
720 /**
721 * Test that a chained api call can use the operator syntax.
722 *
723 * E.g. array('IN' => $value.contact_id)
724 *
725 * @throws \Exception
726 */
727 public function testCaseGetChainedOp() {
728 $contact1 = $this->individualCreate(array(), 1);
729 $contact2 = $this->individualCreate(array(), 2);
730 $case1 = $this->callAPISuccess('Case', 'create', array(
731 'contact_id' => $contact1,
732 'subject' => "Test case 1",
733 'case_type_id' => $this->caseTypeId,
734 ));
735 $case2 = $this->callAPISuccess('Case', 'create', array(
736 'contact_id' => $contact2,
737 'subject' => "Test case 2",
738 'case_type_id' => $this->caseTypeId,
739 ));
740 $case3 = $this->callAPISuccess('Case', 'create', array(
741 'contact_id' => array($contact1, $contact2),
742 'subject' => "Test case 3",
743 'case_type_id' => $this->caseTypeId,
744 ));
745
746 // Fetch case 1 and all cases with the same client. Chained get should return case 3.
747 $result = $this->callAPISuccessGetSingle('Case', array(
748 'id' => $case1['id'],
749 'return' => 'contact_id',
750 'api.Case.get' => array(
751 'contact_id' => array('IN' => "\$value.contact_id"),
752 'id' => array('!=' => "\$value.id"),
753 ),
754 ));
755 $this->assertEquals($case3['id'], $result['api.Case.get']['id']);
756
757 // Fetch case 3 and all cases with the same clients. Chained get should return case 1&2.
758 $result = $this->callAPISuccessGetSingle('Case', array(
759 'id' => $case3['id'],
760 'return' => array('contact_id'),
761 'api.Case.get' => array(
762 'return' => 'id',
763 'contact_id' => array('IN' => "\$value.contact_id"),
764 'id' => array('!=' => "\$value.id"),
765 ),
766 ));
767 $this->assertEquals(array($case1['id'], $case2['id']), array_keys(CRM_Utils_Array::rekey($result['api.Case.get']['values'], 'id')));
768 }
769
770 /**
771 * Test the ability to order by client using the join syntax.
772 *
773 * For multi-client cases, should order by the first client.
774 */
775 public function testCaseGetOrderByClient() {
776 $contact1 = $this->individualCreate(array('first_name' => 'Aa', 'last_name' => 'Zz'));
777 $contact2 = $this->individualCreate(array('first_name' => 'Bb', 'last_name' => 'Zz'));
778 $contact3 = $this->individualCreate(array('first_name' => 'Cc', 'last_name' => 'Xx'));
779
780 $case1 = $this->callAPISuccess('Case', 'create', array(
781 'contact_id' => $contact1,
782 'subject' => "Test case 1",
783 'case_type_id' => $this->caseTypeId,
784 ));
785 $case2 = $this->callAPISuccess('Case', 'create', array(
786 'contact_id' => $contact2,
787 'subject' => "Test case 2",
788 'case_type_id' => $this->caseTypeId,
789 ));
790 $case3 = $this->callAPISuccess('Case', 'create', array(
791 'contact_id' => array($contact3, $contact1),
792 'subject' => "Test case 3",
793 'case_type_id' => $this->caseTypeId,
794 ));
795
796 $result = $this->callAPISuccess('Case', 'get', array(
797 'contact_id' => array('IN' => array($contact1, $contact2, $contact3)),
798 'sequential' => 1,
799 'return' => 'id',
800 'options' => array('sort' => 'contact_id.first_name'),
801 ));
802 $this->assertEquals($case3['id'], $result['values'][2]['id']);
803 $this->assertEquals($case2['id'], $result['values'][1]['id']);
804 $this->assertEquals($case1['id'], $result['values'][0]['id']);
805
806 $result = $this->callAPISuccess('Case', 'get', array(
807 'contact_id' => array('IN' => array($contact1, $contact2, $contact3)),
808 'sequential' => 1,
809 'return' => 'id',
810 'options' => array('sort' => 'contact_id.last_name ASC, contact_id.first_name DESC'),
811 ));
812 $this->assertEquals($case1['id'], $result['values'][2]['id']);
813 $this->assertEquals($case2['id'], $result['values'][1]['id']);
814 $this->assertEquals($case3['id'], $result['values'][0]['id']);
815
816 $result = $this->callAPISuccess('Case', 'get', array(
817 'contact_id' => array('IN' => array($contact1, $contact2, $contact3)),
818 'sequential' => 1,
819 'return' => 'id',
820 'options' => array('sort' => 'contact_id.first_name DESC'),
821 ));
822 $this->assertEquals($case1['id'], $result['values'][2]['id']);
823 $this->assertEquals($case2['id'], $result['values'][1]['id']);
824 $this->assertEquals($case3['id'], $result['values'][0]['id']);
825
826 $result = $this->callAPISuccess('Case', 'get', array(
827 'contact_id' => array('IN' => array($contact1, $contact2, $contact3)),
828 'sequential' => 1,
829 'return' => 'id',
830 'options' => array('sort' => 'case_type_id, contact_id DESC, status_id'),
831 ));
832 $this->assertEquals($case1['id'], $result['values'][2]['id']);
833 $this->assertEquals($case2['id'], $result['values'][1]['id']);
834 $this->assertEquals($case3['id'], $result['values'][0]['id']);
835 $this->assertCount(3, $result['values']);
836 }
837
838 /**
839 * Test the ability to add a timeline to an existing case.
840 *
841 * See the case.addtimeline api.
842 *
843 * @param bool $enableRevisions
844 *
845 * @dataProvider caseActivityRevisionExamples
846 *
847 * @throws \Exception
848 */
849 public function testCaseAddtimeline($enableRevisions) {
850 $this->settingsStack->push('civicaseActivityRevisions', $enableRevisions);
851
852 $caseSpec = array(
853 'title' => 'Application with Definition',
854 'name' => 'Application_with_Definition',
855 'is_active' => 1,
856 'weight' => 4,
857 'definition' => array(
858 'activityTypes' => array(
859 array('name' => 'Follow up'),
860 ),
861 'activitySets' => array(
862 array(
863 'name' => 'set1',
864 'label' => 'Label 1',
865 'timeline' => 1,
866 'activityTypes' => array(
867 array('name' => 'Open Case', 'status' => 'Completed'),
868 ),
869 ),
870 array(
871 'name' => 'set2',
872 'label' => 'Label 2',
873 'timeline' => 1,
874 'activityTypes' => array(
875 array('name' => 'Follow up'),
876 ),
877 ),
878 ),
879 'caseRoles' => array(
880 array('name' => 'Homeless Services Coordinator', 'creator' => 1, 'manager' => 1),
881 ),
882 ),
883 );
884 $cid = $this->individualCreate();
885 $caseType = $this->callAPISuccess('CaseType', 'create', $caseSpec);
886 $case = $this->callAPISuccess('Case', 'create', array(
887 'case_type_id' => $caseType['id'],
888 'contact_id' => $cid,
889 'subject' => 'Test case with timeline',
890 ));
891 // Created case should only have 1 activity per the spec
892 $result = $this->callAPISuccessGetSingle('Activity', array('case_id' => $case['id'], 'return' => 'activity_type_id.name'));
893 $this->assertEquals('Open Case', $result['activity_type_id.name']);
894 // Add timeline.
895 $this->callAPISuccess('Case', 'addtimeline', array(
896 'case_id' => $case['id'],
897 'timeline' => 'set2',
898 ));
899 $result = $this->callAPISuccess('Activity', 'get', array(
900 'case_id' => $case['id'],
901 'return' => 'activity_type_id.name',
902 'sequential' => 1,
903 'options' => array('sort' => 'id'),
904 ));
905 $this->assertEquals(2, $result['count']);
906 $this->assertEquals('Follow up', $result['values'][1]['activity_type_id.name']);
907 }
908
909 /**
910 * Test the case merge function.
911 *
912 * 2 cases should be mergeable into 1
913 *
914 * @throws \Exception
915 */
916 public function testCaseMerge() {
917 $contact1 = $this->individualCreate(array(), 1);
918 $case1 = $this->callAPISuccess('Case', 'create', array(
919 'contact_id' => $contact1,
920 'subject' => "Test case 1",
921 'case_type_id' => $this->caseTypeId,
922 ));
923 $case2 = $this->callAPISuccess('Case', 'create', array(
924 'contact_id' => $contact1,
925 'subject' => "Test case 2",
926 'case_type_id' => $this->caseTypeId,
927 ));
928 $result = $this->callAPISuccess('Case', 'getcount', array('contact_id' => $contact1));
929 $this->assertEquals(2, $result);
930
931 $this->callAPISuccess('Case', 'merge', array('case_id_1' => $case1['id'], 'case_id_2' => $case2['id']));
932
933 $result = $this->callAPISuccess('Case', 'getsingle', array('id' => $case2['id']));
934 $this->assertEquals(1, $result['is_deleted']);
935 }
936
937 /**
938 * Get case activity revision sample data.
939 *
940 * @return array
941 */
942 public function caseActivityRevisionExamples() {
943 $examples = array();
944 $examples[] = array(FALSE);
945 $examples[] = array(TRUE);
946 return $examples;
947 }
948
949 public function testTimestamps() {
950 $params = $this->_params;
951 $case_created = $this->callAPISuccess('case', 'create', $params);
952
953 $case_1 = $this->callAPISuccess('Case', 'getsingle', array(
954 'id' => $case_created['id'],
955 ));
956 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $case_1['created_date']);
957 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $case_1['modified_date']);
958 $this->assertApproxEquals(strtotime($case_1['created_date']), strtotime($case_1['modified_date']), 2);
959
960 $activity_1 = $this->callAPISuccess('activity', 'getsingle', array(
961 'case_id' => $case_created['id'],
962 'options' => array(
963 'limit' => 1,
964 ),
965 ));
966 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $activity_1['created_date']);
967 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $activity_1['modified_date']);
968 $this->assertApproxEquals(strtotime($activity_1['created_date']), strtotime($activity_1['modified_date']), 2);
969
970 usleep(1.5 * 1000000);
971 $this->callAPISuccess('activity', 'create', array(
972 'id' => $activity_1['id'],
973 'subject' => 'Make cheese',
974 ));
975
976 $activity_2 = $this->callAPISuccess('activity', 'getsingle', array(
977 'id' => $activity_1['id'],
978 ));
979 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $activity_2['created_date']);
980 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $activity_2['modified_date']);
981 $this->assertNotEquals($activity_2['created_date'], $activity_2['modified_date']);
982
983 $this->assertEquals($activity_1['created_date'], $activity_2['created_date']);
984 $this->assertNotEquals($activity_1['modified_date'], $activity_2['modified_date']);
985 $this->assertLessThan($activity_2['modified_date'], $activity_1['modified_date'],
986 sprintf("Original modification time (%s) should predate later modification time (%s)", $activity_1['modified_date'], $activity_2['modified_date']));
987
988 $case_2 = $this->callAPISuccess('Case', 'getsingle', array(
989 'id' => $case_created['id'],
990 ));
991 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $case_2['created_date']);
992 $this->assertRegExp(';^\d\d\d\d-\d\d-\d\d \d\d:\d\d;', $case_2['modified_date']);
993 $this->assertEquals($case_1['created_date'], $case_2['created_date']);
994 $this->assertNotEquals($case_2['created_date'], $case_2['modified_date']);
995 }
996
997 }