Merge branch '4.4' into master
[civicrm-core.git] / tests / phpunit / api / v3 / CaseTest.php
1 <?php
2 /**
3 * File for the TestCase class
4 *
5 * (PHP 5)
6 *
7 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
8 * @copyright Copyright CiviCRM LLC (C) 2009
9 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html
10 * GNU Affero General Public License version 3
11 * @version $Id: ActivityTest.php 31254 2010-12-15 10:09:29Z eileen $
12 * @package CiviCRM
13 *
14 * This file is part of CiviCRM
15 *
16 * CiviCRM is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Affero General Public License
18 * as published by the Free Software Foundation; either version 3 of
19 * the License, or (at your option) any later version.
20 *
21 * CiviCRM is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Affero General Public License for more details.
25 *
26 * You should have received a copy of the GNU Affero General Public
27 * License along with this program. If not, see
28 * <http://www.gnu.org/licenses/>.
29 */
30
31 /**
32 * Include class definitions
33 */
34 require_once 'CiviTest/CiviUnitTestCase.php';
35
36 /**
37 * Test APIv3 civicrm_case_* functions
38 *
39 * @package CiviCRM_APIv3
40 */
41 class api_v3_CaseTest extends CiviUnitTestCase {
42 protected $_params;
43 protected $_entity;
44 protected $_apiversion =3;
45 protected $followup_activity_type_value;
46 protected $caseTypeId;
47 protected $caseStatusGroup;
48 protected $caseTypeGroup;
49 protected $optionValues;
50
51 /**
52 * Test setup for every test
53 *
54 * Connect to the database, truncate the tables that will be used
55 * and redirect stdin to a temporary file
56 */
57 public function setUp() {
58 $this->_entity = 'case';
59
60 parent::setUp();
61 // CRM-9404 - set-up is a bit cumbersome but had to put something in place to set up activity types & case types
62 //. Using XML was causing breakage as id numbers were changing over time
63 // & was really hard to troubleshoot as involved truncating option_value table to mitigate this & not leaving DB in a
64 // state where tests could run afterwards without re-loading.
65 $this->caseStatusGroup = $this->callAPISuccess('option_group', 'get', array(
66 'name' => 'case_status',
67 'format.only_id' => 1)
68 );
69 $this->caseTypeGroup = $this->callAPISuccess('option_group', 'get', array(
70 'name' => 'case_type',
71 'format.only_id' => 1)
72 );
73 $caseTypes = $this->callAPISuccess('option_value', 'Create', array(
74 'option_group_id' => $this->caseTypeGroup,
75 'name' => 'housing_support',
76 'label' => "Housing Support",
77 'sequential' => 1,
78 'description' => 'Help homeless individuals obtain temporary and long-term housing',
79 ));
80
81 $this->caseTypeId = $caseTypes['values'][0]['value'];
82 $this->optionValues[] = $caseTypes['id'];
83 $optionValues = array(
84 'Medical evaluation' => 'Medical evaluation',
85 'Mental health evaluation' => "Mental health evaluation",
86 'Secure temporary housing' => 'Secure temporary housing',
87 'Long-term housing plan' => 'Long-term housing plan',
88 'ADC referral' => 'ADC referral',
89 'Income and benefits stabilization' => 'Income and benefits stabilization',
90 );
91 foreach ($optionValues as $name => $label) {
92 $activityTypes = $this->callAPISuccess('option_value', 'Create', array(
93 'option_group_id' => 2,
94 'name' => $name,
95 'label' => $label,
96 'component_id' => 7,
97 ));
98 // store for cleanup
99 $this->optionValues[] = $activityTypes['id'];
100 }
101 $tablesToTruncate = array(
102 'civicrm_activity',
103 'civicrm_contact',
104 'civicrm_custom_group',
105 'civicrm_custom_field',
106 'civicrm_case',
107 'civicrm_case_contact',
108 'civicrm_case_activity',
109 'civicrm_activity_contact',
110 'civicrm_relationship',
111 'civicrm_relationship_type',
112 );
113
114 $this->quickCleanup($tablesToTruncate);
115
116 $activityTypes = $this->callAPISuccess('option_value', 'get', array(
117 'option_group_id' => 2,
118 'name' => 'Follow Up',
119 'label' => 'Follow Up',
120 'sequential' => 1,
121 ));
122 $this->followup_activity_type_value = $activityTypes['values'][0]['value'];
123 // Insert a row in civicrm_contact creating contact 17
124 $op = new PHPUnit_Extensions_Database_Operation_Insert();
125 $op->execute($this->_dbconn,
126 new PHPUnit_Extensions_Database_DataSet_XMLDataSet(
127 dirname(__FILE__) . '/dataset/contact_17.xml'
128 )
129 );
130
131 //Create relationship types
132 $relTypeParams = array(
133 'name_a_b' => 'Case Coordinator is',
134 'label_a_b' => 'Case Coordinator is',
135 'name_b_a' => 'Case Coordinator',
136 'label_b_a' => 'Case Coordinator',
137 'description' => 'Case Coordinator',
138 'contact_type_a' => 'Individual',
139 'contact_type_b' => 'Individual',
140 'is_reserved' => 0,
141 'is_active' => 1,
142 );
143 $this->relationshipTypeCreate($relTypeParams);
144
145 $relTypeParams = array(
146 'name_a_b' => 'Homeless Services Coordinator is',
147 'label_a_b' => 'Homeless Services Coordinator is',
148 'name_b_a' => 'Homeless Services Coordinator',
149 'label_b_a' => 'Homeless Services Coordinator',
150 'description' => 'Homeless Services Coordinator',
151 'contact_type_a' => 'Individual',
152 'contact_type_b' => 'Individual',
153 'is_reserved' => 0,
154 'is_active' => 1,
155 );
156 $this->relationshipTypeCreate($relTypeParams);
157
158 $relTypeParams = array(
159 'name_a_b' => 'Health Services Coordinator is',
160 'label_a_b' => 'Health Services Coordinator is',
161 'name_b_a' => 'Health Services Coordinator',
162 'label_b_a' => 'Health Services Coordinator',
163 'description' => 'Health Services Coordinator',
164 'contact_type_a' => 'Individual',
165 'contact_type_b' => 'Individual',
166 'is_reserved' => 0,
167 'is_active' => 1,
168 );
169 $this->relationshipTypeCreate($relTypeParams);
170
171 $relTypeParams = array(
172 'name_a_b' => 'Senior Services Coordinator is',
173 'label_a_b' => 'Senior Services Coordinator is',
174 'name_b_a' => 'Senior Services Coordinator',
175 'label_b_a' => 'Senior Services Coordinator',
176 'description' => 'Senior Services Coordinator',
177 'contact_type_a' => 'Individual',
178 'contact_type_b' => 'Individual',
179 'is_reserved' => 0,
180 'is_active' => 1,
181 );
182 $this->relationshipTypeCreate($relTypeParams);
183
184 $relTypeParams = array(
185 'name_a_b' => 'Benefits Specialist is',
186 'label_a_b' => 'Benefits Specialist is',
187 'name_b_a' => 'Benefits Specialist',
188 'label_b_a' => 'Benefits Specialist',
189 'description' => 'Benefits Specialist',
190 'contact_type_a' => 'Individual',
191 'contact_type_b' => 'Individual',
192 'is_reserved' => 0,
193 'is_active' => 1,
194 );
195 $this->relationshipTypeCreate($relTypeParams);
196
197 // enable the default custom templates for the case type xml files
198 $this->customDirectories(array('template_path' => TRUE));
199
200 // case is not enabled by default
201 $enableResult = CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
202 $this->assertTrue($enableResult, 'Cannot enable CiviCase in line ' . __LINE__);
203
204 $this->_params = array(
205 'case_type_id' => $this->caseTypeId,
206 'subject' => 'Test case',
207 'contact_id' => 17,
208 );
209
210 // create a logged in USER since the code references it for source_contact_id
211 $this->createLoggedInUser();
212 $session = CRM_Core_Session::singleton();
213 $this->_loggedInUser = $session->get('userID');
214 /// note that activityType options are cached by the FULL set of options you pass in
215 // ie. because Activity api includes campaign in it's call cache is not flushed unless
216 // included in this call. Also note flush function doesn't work on this property as it sets to null not empty array
217 CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name', TRUE);
218 }
219
220 /**
221 * Tears down the fixture, for example, closes a network connection.
222 * This method is called after a test is executed.
223 *
224 * @access protected
225 */
226 function tearDown() {
227 foreach ($this->optionValues as $id) {
228 $this->callAPISuccess('option_value', 'delete', array('id' => $id));
229 }
230 $tablesToTruncate = array(
231 'civicrm_contact',
232 'civicrm_activity',
233 'civicrm_case',
234 'civicrm_case_contact',
235 'civicrm_case_activity',
236 'civicrm_activity_contact',
237 'civicrm_relationship',
238 'civicrm_relationship_type',
239 );
240 $this->quickCleanup($tablesToTruncate, TRUE);
241
242 $this->customDirectories(array('template_path' => FALSE));
243 }
244
245 /**
246 * check with empty array
247 */
248 function testCaseCreateEmpty() {
249 $result = $this->callAPIFailure('case', 'create', array());
250 }
251
252 /**
253 * check if required fields are not passed
254 */
255 function testCaseCreateWithoutRequired() {
256 $params = array(
257 'subject' => 'this case should fail',
258 'case_type_id' => 1,
259 );
260
261 $result = $this->callAPIFailure('case', 'create', $params);
262 }
263
264 /**
265 * Test create function with valid parameters
266 */
267 function testCaseCreate() {
268 // Create Case
269 $params = $this->_params;
270 // Test using label instead of value
271 unset($params['case_type_id']);
272 $params['case_type'] = 'Housing Support';
273 $result = $this->callAPISuccess('case', 'create', $params);
274 $id = $result['id'];
275
276 // Check result
277 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
278 $this->assertEquals($result['values'][$id]['id'], 1, 'in line ' . __LINE__);
279 $this->assertEquals($result['values'][$id]['case_type_id'], $this->caseTypeId, 'in line ' . __LINE__);
280 $this->assertEquals($result['values'][$id]['subject'], $params['subject'], 'in line ' . __LINE__);
281 }
282
283 /**
284 * Test update (create with id) function with valid parameters
285 */
286 function testCaseUpdate() {
287 // Create Case
288 $params = $this->_params;
289 // Test using name instead of value
290 $params['case_type_id'] = 'housing_support';
291 $result = $this->callAPISuccess('case', 'create', $params);
292 $id = $result['id'];
293 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
294 $case = $result['values'][$id];
295
296 // Update Case
297 $params = array('id' => $id);
298 $params['subject'] = $case['subject'] = 'Something Else';
299 $result = $this->callAPISuccess('case', 'create', $params);
300
301 // Verify that updated case is exactly equal to the original with new subject
302 $result = $this->callAPISuccess('case', 'get', array('case_id' => $id));
303 $this->assertEquals($result['values'][$id], $case, 'in line ' . __LINE__);
304 }
305
306 /**
307 * Test delete function with valid parameters
308 */
309 function testCaseDelete() {
310 // Create Case
311 $result = $this->callAPISuccess('case', 'create', $this->_params);
312
313 // Move Case to Trash
314 $id = $result['id'];
315 $result = $this->callAPISuccess('case', 'delete', array('id' => $id, 'move_to_trash' => 1));
316
317 // Check result - also check that 'case_id' works as well as 'id'
318 $result = $this->callAPISuccess('case', 'get', array('case_id' => $id));
319 $this->assertEquals(1, $result['values'][$id]['is_deleted'], 'in line ' . __LINE__);
320
321 // Delete Case Permanently - also check that 'case_id' works as well as 'id'
322 $result = $this->callAPISuccess('case', 'delete', array('case_id' => $id));
323
324 // Check result - case should no longer exist
325 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
326 $this->assertEquals(0, $result['count']);
327 }
328
329 /**
330 * Test get function based on activity
331 */
332 function testCaseGetByActivity() {
333 // Create Case
334 $result = $this->callAPISuccess('case', 'create', $this->_params);
335 $id = $result['id'];
336
337 // Check result - we should get a list of activity ids
338 $result = $this->callAPISuccess('case', 'get', array('id' => $id));
339 $case = $result['values'][$id];
340 $activity = $case['activities'][0];
341
342 // Fetch case based on an activity id
343 $result = $this->callAPISuccess('case', 'get', array('activity_id' => $activity, 'return' => 'activities,contacts'));
344 $this->assertEquals(FALSE, empty($result['values'][$id]), 'in line ' . __LINE__);
345 $this->assertEquals($result['values'][$id], $case, 'in line ' . __LINE__);
346 }
347
348 /**
349 * Test get function based on contact id
350 */
351 function testCaseGetByContact() {
352 // Create Case
353 $result = $this->callAPISuccess('case', 'create', $this->_params);
354 $id = $result['id'];
355
356 // Store result for later
357 $case = $this->callAPISuccess('case', 'getsingle', array('id' => $id));
358
359 // Fetch case based on client contact id
360 $result = $this->callAPISuccess('case', 'get', array('client_id' => $this->_params['contact_id'], 'return' => array('activities', 'contacts')));
361 $this->assertAPIArrayComparison($result['values'][$id], $case);
362 }
363
364 /**
365 * Test get function based on subject
366 */
367 function testCaseGetBySubject() {
368 // Create Case
369 $result = $this->callAPISuccess('case', 'create', $this->_params);
370 $id = $result['id'];
371
372 // Store result for later
373 $case = $this->callAPISuccess('case', 'getsingle', array('id' => $id));
374
375 // Fetch case based on client contact id
376 $result = $this->callAPISuccess('case', 'get', array('subject' => $this->_params['subject'], 'return' => array('activities', 'contacts')));
377 $this->assertAPIArrayComparison($result['values'][$id], $case);
378 }
379
380 /**
381 * Test get function based on wrong subject
382 */
383 function testCaseGetByWrongSubject() {
384 // Create Case
385 $result = $this->callAPISuccess('case', 'create', $this->_params);
386 $id = $result['id'];
387
388 // Append 'wrong' to subject so that it is no longer the same
389 $result = $this->callAPISuccess('case', 'get', array('subject' => $this->_params['subject'] . 'wrong', 'return' => array('activities', 'contacts')));
390 $this->assertEquals(0, $result['count'], 'in line ' . __LINE__);
391 }
392
393 /**
394 * Test get function with no criteria
395 */
396 function testCaseGetNoCriteria() {
397 // Create Case
398 $result = $this->callAPISuccess('case', 'create', $this->_params);
399 $id = $result['id'];
400
401 // Store result for later
402 $case = $this->callAPISuccess('case', 'getsingle', array('id' => $id));
403
404 $result = $this->callAPISuccess('case', 'get', array('return' => array('activities', 'contacts')));
405 $this->assertAPIArrayComparison($result['values'][$id], $case);
406 }
407
408 /**
409 * Test activity api create for case activities
410 */
411 function testCaseActivityCreate() {
412 // Create a case first
413 $params = $this->_params;
414 $result = $this->callAPISuccess('case', 'create', $params);
415 $params = array(
416 'case_id' => 1,
417 // follow up
418 'activity_type_id' => $this->followup_activity_type_value,
419 'subject' => 'Test followup',
420 'source_contact_id' => $this->_loggedInUser,
421 'target_contact_id' => $this->_params['contact_id'],
422 );
423 $result = $this->callAPISuccess('activity', 'create', $params);
424 $this->assertEquals($result['values'][$result['id']]['activity_type_id'], $params['activity_type_id'], 'in line ' . __LINE__);
425
426 // might need this for other tests that piggyback on this one
427 $this->_caseActivityId = $result['values'][$result['id']]['id'];
428
429 // Check other DB tables populated properly - is there a better way to do this? assertDBState() requires that we know the id already.
430 $dao = new CRM_Case_DAO_CaseActivity();
431 $dao->case_id = 1;
432 $dao->activity_id = $this->_caseActivityId;
433 $this->assertEquals($dao->find(), 1, 'case_activity table not populated correctly in line ' . __LINE__);
434 $dao->free();
435
436 $dao = new CRM_Activity_DAO_ActivityContact();
437 $dao->activity_id = $this->_caseActivityId;
438 $dao->contact_id = $this->_params['contact_id'];
439 $dao->record_type_id = 3;
440 $this->assertEquals($dao->find(), 1, 'activity_contact table not populated correctly in line ' . __LINE__);
441 $dao->free();
442
443 // TODO: There's more things we could check
444 }
445
446 /**
447 * Test activity api update for case activities
448 */
449 function testCaseActivityUpdate() {
450 // Need to create the case and activity before we can update it
451 $this->testCaseActivityCreate();
452
453 $params = array(
454 'activity_id' => $this->_caseActivityId,
455 'case_id' => 1,
456 'activity_type_id' => 14,
457 'source_contact_id' => $this->_loggedInUser,
458 'subject' => 'New subject',
459 );
460 $result = $this->callAPISuccess('activity', 'create', $params);
461
462 $this->assertEquals($result['values'][$result['id']]['subject'], $params['subject'], 'in line ' . __LINE__);
463
464 // id should be one greater, since this is a new revision
465 $this->assertEquals($result['values'][$result['id']]['id'],
466 $this->_caseActivityId + 1,
467 'in line ' . __LINE__
468 );
469 $this->assertEquals($result['values'][$result['id']]['original_id'],
470 $this->_caseActivityId,
471 'in line ' . __LINE__
472 );
473
474 // Check revision is as expected
475 $revParams = array(
476 'activity_id' => $this->_caseActivityId,
477 );
478 $revActivity = $this->callAPISuccess('activity', 'get', $revParams);
479 $this->assertEquals($revActivity['values'][$this->_caseActivityId]['is_current_revision'],
480 0);
481 $this->assertEquals($revActivity['values'][$this->_caseActivityId]['is_deleted'],
482 0
483 );
484
485 //TODO: check some more things
486 }
487
488 function testCaseActivityUpdateCustom() {
489 // Create a case first
490 $result = $this->callAPISuccess('case', 'create', $this->_params);
491
492 // Create custom field group
493 // Note the second parameter is Activity on purpose, not Case.
494 $custom_ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ActivityTest.php');
495
496 // create activity
497 $params = array(
498 'case_id' => $result['id'],
499 // follow up
500 'activity_type_id' => 14,
501 'subject' => 'Test followup',
502 'source_contact_id' => $this->_loggedInUser,
503 'target_contact_id' => $this->_params['contact_id'],
504 'custom_' . $custom_ids['custom_field_id'] => "custom string",
505 );
506 $result = $this->callAPISuccess('activity', 'create', $params);
507
508 $aid = $result['values'][$result['id']]['id'];
509
510 // Update activity
511 $params = array(
512 'activity_id' => $aid,
513 'case_id' => 1,
514 'activity_type_id' => 14,
515 'source_contact_id' => $this->_loggedInUser,
516 'subject' => 'New subject',
517 );
518 $revAct = $this->callAPISuccess('activity', 'create', $params);
519
520 // Retrieve revision and check custom fields got copied
521 $revParams = array(
522 'activity_id' => $aid + 1,
523 'return.custom_' . $custom_ids['custom_field_id'] => 1,
524 );
525 $revAct = $this->callAPISuccess('activity', 'get', $revParams);
526
527 $this->assertEquals($revAct['values'][$aid + 1]['custom_' . $custom_ids['custom_field_id']], "custom string",
528 "Error message: " . CRM_Utils_Array::value('error_message', $revAct) . ' in line ' . __LINE__
529 );
530
531 $this->customFieldDelete($custom_ids['custom_field_id']);
532 $this->customGroupDelete($custom_ids['custom_group_id']);
533 }
534 }